LibDisassembly: Split existing generic interfaces from x86-specific code

InstructionStream, SymbolProvider and Disassembler are already generic
interfaces, so we can separate those from the x86-specific code. The
x86-specific code is moved to a new x86 subdirectory, which will be
accompanied by other architecture-specific directories soon.
This commit is contained in:
kleines Filmröllchen authored and Tim Schumacher committed 2025-03-15 23:34:54 +01:00
1 parent 881681580a
commit e222d2cb8e
15 files changed
+121 -91

No files matched your search

+3 -3
View File
@@ -16,7 +16,7 @@
#include <LibDebug/DebugInfo.h>
#include <LibDebug/DebugSession.h>
#include <LibDisassembly/Disassembler.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibLine/Editor.h>
#include <LibMain/Main.h>
#include <signal.h>
@@ -82,8 +82,8 @@ static bool handle_disassemble_command(ByteString const& command, FlatPtr first_
break;
}
Disassembly::X86::SimpleInstructionStream stream(code.data(), code.size());
Disassembly::X86::Disassembler disassembler(stream);
Disassembly::SimpleInstructionStream stream(code.data(), code.size());
Disassembly::Disassembler disassembler(stream);
for (size_t i = 0; i < number_of_instructions_to_disassemble; ++i) {
auto offset = stream.offset();
@@ -50,9 +50,9 @@ DisassemblyModel::DisassemblyModel(Debug::DebugSession const& debug_session, Ptr
auto view = symbol.value().raw_data();
Disassembly::X86::ELFSymbolProvider symbol_provider(*elf);
Disassembly::X86::SimpleInstructionStream stream((u8 const*)view.characters_without_null_termination(), view.length());
Disassembly::X86::Disassembler disassembler(stream);
Disassembly::ELFSymbolProvider symbol_provider(*elf);
Disassembly::SimpleInstructionStream stream((u8 const*)view.characters_without_null_termination(), view.length());
Disassembly::Disassembler disassembler(stream);
size_t offset_into_symbol = 0;
for (;;) {
@@ -8,7 +8,7 @@
#pragma once
#include <AK/Vector.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibGUI/Model.h>
#include <sys/arch/regs.h>
@@ -93,9 +93,9 @@ DisassemblyModel::DisassemblyModel(Profile& profile, ProfileNode& node)
auto symbol_offset_from_function_start = node.address() - base_address - symbol->value();
auto view = symbol.value().raw_data().substring_view(symbol_offset_from_function_start);
Disassembly::X86::ELFSymbolProvider symbol_provider(*elf, base_address);
Disassembly::X86::SimpleInstructionStream stream((u8 const*)view.characters_without_null_termination(), view.length());
Disassembly::X86::Disassembler disassembler(stream);
Disassembly::ELFSymbolProvider symbol_provider(*elf, base_address);
Disassembly::SimpleInstructionStream stream((u8 const*)view.characters_without_null_termination(), view.length());
Disassembly::Disassembler disassembler(stream);
size_t offset_into_symbol = 0;
FlatPtr last_instruction_offset = 0;
@@ -8,7 +8,7 @@
#pragma once
#include <LibDebug/DebugInfo.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibGUI/Model.h>
namespace Profiler {
@@ -1,5 +1,5 @@
set(SOURCES
Instruction.cpp
x86/Instruction.cpp
)
serenity_lib(LibDisassembly disassembly)
@@ -7,9 +7,10 @@
#pragma once
#include <AK/Optional.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/InstructionStream.h>
#include <LibDisassembly/x86/Instruction.h>
namespace Disassembly::X86 {
namespace Disassembly {
class Disassembler {
public:
@@ -18,12 +19,12 @@ public:
{
}
Optional<Instruction> next()
Optional<X86::Instruction> next()
{
if (!m_stream.can_read())
return {};
#if ARCH(X86_64)
return Instruction::from_stream(m_stream, ProcessorMode::Long);
return X86::Instruction::from_stream(m_stream, X86::ProcessorMode::Long);
#else
dbgln("Unsupported platform");
return {};
@@ -6,10 +6,11 @@
#pragma once
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/SymbolProvider.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibELF/Image.h>
namespace Disassembly::X86 {
namespace Disassembly {
class ELFSymbolProvider final : public SymbolProvider {
public:
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2023, kleines Filmröllchen <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
namespace Disassembly {
class InstructionStream {
public:
virtual bool can_read() = 0;
virtual u8 read8() = 0;
virtual u16 read16() = 0;
virtual u32 read32() = 0;
virtual u64 read64() = 0;
protected:
virtual ~InstructionStream() = default;
};
class SimpleInstructionStream final : public InstructionStream {
public:
SimpleInstructionStream(u8 const* data, size_t size)
: m_data(data)
, m_size(size)
{
}
virtual bool can_read() override { return m_offset < m_size; }
virtual u8 read8() override
{
if (!can_read())
return 0;
return m_data[m_offset++];
}
virtual u16 read16() override
{
u8 lsb = read8();
u8 msb = read8();
return ((u16)msb << 8) | (u16)lsb;
}
virtual u32 read32() override
{
u16 lsw = read16();
u16 msw = read16();
return ((u32)msw << 16) | (u32)lsw;
}
virtual u64 read64() override
{
u32 lsw = read32();
u32 msw = read32();
return ((u64)msw << 32) | (u64)lsw;
}
size_t offset() const { return m_offset; }
private:
u8 const* m_data { nullptr };
size_t m_offset { 0 };
size_t m_size { 0 };
};
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2023, kleines Filmröllchen <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/ByteString.h>
#include <AK/Types.h>
namespace Disassembly {
class SymbolProvider {
public:
virtual ByteString symbolicate(FlatPtr, u32* offset = nullptr) const = 0;
protected:
virtual ~SymbolProvider() = default;
};
}
@@ -6,8 +6,8 @@
*/
#include <AK/StringBuilder.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/Interpreter.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibDisassembly/x86/Interpreter.h>
#if defined(AK_COMPILER_GCC)
# pragma GCC optimize("O3")
@@ -11,6 +11,7 @@
#include <AK/Optional.h>
#include <AK/StdLibExtras.h>
#include <AK/Types.h>
#include <LibDisassembly/SymbolProvider.h>
#include <stdio.h>
namespace Disassembly::X86 {
@@ -19,14 +20,6 @@ class Instruction;
class Interpreter;
typedef void (Interpreter::*InstructionHandler)(Instruction const&);
class SymbolProvider {
public:
virtual ByteString symbolicate(FlatPtr, u32* offset = nullptr) const = 0;
protected:
virtual ~SymbolProvider() = default;
};
template<typename T>
struct TypeTrivia {
static constexpr size_t bits = sizeof(T) * 8;
@@ -459,62 +452,6 @@ private:
FlatPtr m_offset { 0 };
};
class InstructionStream {
public:
virtual bool can_read() = 0;
virtual u8 read8() = 0;
virtual u16 read16() = 0;
virtual u32 read32() = 0;
virtual u64 read64() = 0;
protected:
virtual ~InstructionStream() = default;
};
class SimpleInstructionStream final : public InstructionStream {
public:
SimpleInstructionStream(u8 const* data, size_t size)
: m_data(data)
, m_size(size)
{
}
virtual bool can_read() override { return m_offset < m_size; }
virtual u8 read8() override
{
if (!can_read())
return 0;
return m_data[m_offset++];
}
virtual u16 read16() override
{
u8 lsb = read8();
u8 msb = read8();
return ((u16)msb << 8) | (u16)lsb;
}
virtual u32 read32() override
{
u16 lsw = read16();
u16 msw = read16();
return ((u32)msw << 16) | (u32)lsw;
}
virtual u64 read64() override
{
u32 lsw = read32();
u32 msw = read32();
return ((u64)msw << 32) | (u64)lsw;
}
size_t offset() const { return m_offset; }
private:
u8 const* m_data { nullptr };
size_t m_offset { 0 };
size_t m_size { 0 };
};
class MemoryOrRegisterReference {
friend class Instruction;
+4 -4
View File
@@ -67,12 +67,12 @@ ErrorOr<int> serenity_main(Main::Arguments args)
Vector<Symbol> zero_size_symbols;
size_t file_offset = 0;
OwnPtr<Disassembly::X86::ELFSymbolProvider> symbol_provider; // nullptr for non-ELF disassembly.
OwnPtr<Disassembly::ELFSymbolProvider> symbol_provider; // nullptr for non-ELF disassembly.
OwnPtr<ELF::Image> elf;
if (asm_size >= 4 && strncmp(reinterpret_cast<char const*>(asm_data), "\u007fELF", 4) == 0) {
elf = make<ELF::Image>(asm_data, asm_size);
if (elf->is_valid()) {
symbol_provider = make<Disassembly::X86::ELFSymbolProvider>(*elf);
symbol_provider = make<Disassembly::ELFSymbolProvider>(*elf);
elf->for_each_section_of_type(SHT_PROGBITS, [&](ELF::Image::Section const& section) {
// FIXME: Disassemble all SHT_PROGBITS sections, not just .text.
if (section.name() != ".text")
@@ -116,8 +116,8 @@ ErrorOr<int> serenity_main(Main::Arguments args)
}
}
Disassembly::X86::SimpleInstructionStream stream(asm_data, asm_size);
Disassembly::X86::Disassembler disassembler(stream);
Disassembly::SimpleInstructionStream stream(asm_data, asm_size);
Disassembly::Disassembler disassembler(stream);
Vector<Symbol>::Iterator current_ranged_symbol = ranged_symbols.begin();
Vector<Symbol>::Iterator current_zero_size_symbol = zero_size_symbols.begin();
+3 -3
View File
@@ -13,7 +13,7 @@
#include <LibCore/System.h>
#include <LibDebug/DebugSession.h>
#include <LibDisassembly/Disassembler.h>
#include <LibDisassembly/Instruction.h>
#include <LibDisassembly/x86/Instruction.h>
#include <LibELF/Image.h>
#include <LibMain/Main.h>
#include <signal.h>
@@ -83,8 +83,8 @@ static NonnullOwnPtr<HashMap<FlatPtr, Disassembly::X86::Instruction>> instrument
if (section.name() != ".text")
return IterationDecision::Continue;
Disassembly::X86::SimpleInstructionStream stream((u8 const*)((uintptr_t)lib.file->data() + section.offset()), section.size());
Disassembly::X86::Disassembler disassembler(stream);
Disassembly::SimpleInstructionStream stream((u8 const*)((uintptr_t)lib.file->data() + section.offset()), section.size());
Disassembly::Disassembler disassembler(stream);
for (;;) {
auto offset = stream.offset();
auto instruction_address = section.address() + offset + lib.base_address;