1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 01:17:35 +00:00

LibDebug: Support shared libraries

DebugSession now makes the loader stop after loading the libraries,
and parses the loaded libraries of the program before continuing its
execution.

DebugSession now also supports inserting a breakpoint at a given symbol
or source position.
Additionally, DebugInfo now takes the base address of its object into
consideration.
This commit is contained in:
Itamar 2021-01-06 21:49:25 +02:00 committed by Andreas Kling
parent ca9d6d21b5
commit 4b91e7c821
6 changed files with 328 additions and 53 deletions

View file

@ -84,25 +84,27 @@ static void print_syscall(PtraceRegisters& regs, size_t depth)
static NonnullOwnPtr<HashMap<void*, X86::Instruction>> instrument_code()
{
[[maybe_unused]] auto r = demangle("foo"); // Required for linked with __cxa_demangle
auto instrumented = make<HashMap<void*, X86::Instruction>>();
g_debug_session->elf().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) {
if (section.name() != ".text")
return IterationDecision::Continue;
g_debug_session->for_each_loaded_library([&](const Debug::DebugSession::LoadedLibrary& lib) {
lib.debug_info->elf().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) {
if (section.name() != ".text")
return IterationDecision::Continue;
X86::SimpleInstructionStream stream((const u8*)((u32)g_debug_session->executable().data() + section.offset()), section.size());
X86::Disassembler disassembler(stream);
for (;;) {
auto offset = stream.offset();
void* instruction_address = (void*)(section.address() + offset);
auto insn = disassembler.next();
if (!insn.has_value())
break;
if (insn.value().mnemonic() == "RET" || insn.value().mnemonic() == "CALL") {
g_debug_session->insert_breakpoint(instruction_address);
instrumented->set(instruction_address, insn.value());
X86::SimpleInstructionStream stream((const u8*)((u32)lib.file.data() + section.offset()), section.size());
X86::Disassembler disassembler(stream);
for (;;) {
auto offset = stream.offset();
void* instruction_address = (void*)(section.address() + offset + lib.base_address);
auto insn = disassembler.next();
if (!insn.has_value())
break;
if (insn.value().mnemonic() == "RET" || insn.value().mnemonic() == "CALL") {
g_debug_session->insert_breakpoint(instruction_address);
instrumented->set(instruction_address, insn.value());
}
}
}
return IterationDecision::Continue;
});
return IterationDecision::Continue;
});
return instrumented;
@ -142,7 +144,7 @@ int main(int argc, char** argv)
size_t depth = 0;
bool new_function = true;
g_debug_session->run([&](Debug::DebugSession::DebugBreakReason reason, Optional<PtraceRegisters> regs) {
g_debug_session->run(Debug::DebugSession::DesiredInitialDebugeeState::Running, [&](Debug::DebugSession::DebugBreakReason reason, Optional<PtraceRegisters> regs) {
if (reason == Debug::DebugSession::DebugBreakReason::Exited) {
outln("Program exited.");
return Debug::DebugSession::DebugDecision::Detach;
@ -154,8 +156,8 @@ int main(int argc, char** argv)
}
if (new_function) {
auto function_name = g_debug_session->elf().symbolicate(regs.value().eip);
print_function_call(function_name, depth);
auto function_name = g_debug_session->symbolicate(regs.value().eip);
print_function_call(function_name.value().symbol, depth);
new_function = false;
return Debug::DebugSession::ContinueBreakAtSyscall;
}