mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 18:02:05 -05:00
Debugger: Add source-level operations
- Print current source location, if available - Add a breakpoint at a source location - "sl" command - step to the next line in source
This commit is contained in:
parent
8a886e0e96
commit
e35219b5ce
4 changed files with 72 additions and 14 deletions
|
@ -32,6 +32,7 @@
|
|||
#include <AK/kmalloc.h>
|
||||
#include <LibC/sys/arch/i386/regs.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibDebug/DebugInfo.h>
|
||||
#include <LibDebug/DebugSession.h>
|
||||
#include <LibLine/Editor.h>
|
||||
#include <LibX86/Disassembler.h>
|
||||
|
@ -126,7 +127,24 @@ bool handle_breakpoint_command(const String& command)
|
|||
|
||||
u32 breakpoint_address = 0;
|
||||
|
||||
if ((argument[0] >= '0' && argument[0] <= '9')) {
|
||||
if (argument.contains(":")) {
|
||||
auto source_arguments = argument.split(':');
|
||||
if (source_arguments.size() != 2)
|
||||
return false;
|
||||
bool ok = false;
|
||||
size_t line = source_arguments[1].to_uint(ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
auto file = source_arguments[0];
|
||||
if (!file.contains("/"))
|
||||
file = String::format("./%s", file.characters());
|
||||
auto result = g_debug_session->debug_info().get_instruction_from_source(file, line);
|
||||
if (!result.has_value()) {
|
||||
printf("No matching instruction found\n");
|
||||
return false;
|
||||
}
|
||||
breakpoint_address = result.value();
|
||||
} else if ((argument[0] >= '0' && argument[0] <= '9')) {
|
||||
breakpoint_address = strtoul(argument.characters(), nullptr, 16);
|
||||
} else {
|
||||
auto symbol = g_debug_session->elf().find_demangled_function(argument);
|
||||
|
@ -136,6 +154,7 @@ bool handle_breakpoint_command(const String& command)
|
|||
}
|
||||
breakpoint_address = reinterpret_cast<u32>(symbol.value().value());
|
||||
}
|
||||
|
||||
bool success = g_debug_session->insert_breakpoint(reinterpret_cast<void*>(breakpoint_address));
|
||||
if (!success) {
|
||||
fprintf(stderr, "coult not insert breakpoint at: %08x\n", breakpoint_address);
|
||||
|
@ -149,10 +168,12 @@ void print_help()
|
|||
{
|
||||
printf("Options:\n"
|
||||
"cont - Continue execution\n"
|
||||
"s - step over the current instruction\n"
|
||||
"si - step to the next instruction\n"
|
||||
"sl - step to the next source line\n"
|
||||
"line - show the position of the current instruction in the source code"
|
||||
"regs - Print registers\n"
|
||||
"dis [number of instructions] - Print disassembly\n"
|
||||
"bp <address/symbol> - Insert a breakpoint\n");
|
||||
"bp <address/symbol/file:line> - Insert a breakpoint\n");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
|
@ -188,6 +209,9 @@ int main(int argc, char** argv)
|
|||
bool rc = g_debug_session->insert_breakpoint(g_debug_session->elf().entry().as_ptr());
|
||||
ASSERT(rc);
|
||||
|
||||
DebugInfo::SourcePosition previous_source_position;
|
||||
bool in_step_line = false;
|
||||
|
||||
g_debug_session->run([&](DebugSession::DebugBreakReason reason, Optional<PtraceRegisters> optional_regs) {
|
||||
if (reason == DebugSession::DebugBreakReason::Exited) {
|
||||
printf("Program exited.\n");
|
||||
|
@ -198,7 +222,28 @@ int main(int argc, char** argv)
|
|||
const PtraceRegisters& regs = optional_regs.value();
|
||||
|
||||
auto symbol_at_ip = g_debug_session->elf().symbolicate(regs.eip);
|
||||
auto source_position = g_debug_session->debug_info().get_source_position(regs.eip);
|
||||
|
||||
if (in_step_line) {
|
||||
bool no_source_info = !source_position.has_value();
|
||||
if (no_source_info || source_position.value() != previous_source_position) {
|
||||
if (no_source_info)
|
||||
printf("No source information for current instruction! stoppoing.\n");
|
||||
in_step_line = false;
|
||||
} else {
|
||||
return DebugSession::DebugDecision::SingleStep;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Program is stopped at: 0x%x (%s)\n", regs.eip, symbol_at_ip.characters());
|
||||
|
||||
if (source_position.has_value()) {
|
||||
previous_source_position = source_position.value();
|
||||
printf("Source location: %s:%lu\n", source_position.value().file_path.characters(), source_position.value().line_number);
|
||||
} else {
|
||||
printf("(No source location information for the current instruction)\n");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
auto command = editor.get_line("(sdb) ");
|
||||
bool success = false;
|
||||
|
@ -210,13 +255,18 @@ int main(int argc, char** argv)
|
|||
if (command == "cont") {
|
||||
decision = DebugSession::DebugDecision::Continue;
|
||||
success = true;
|
||||
}
|
||||
if (command == "s") {
|
||||
} else if (command == "si") {
|
||||
decision = DebugSession::DebugDecision::SingleStep;
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (command == "regs") {
|
||||
} else if (command == "sl") {
|
||||
if (source_position.has_value()) {
|
||||
decision = DebugSession::DebugDecision::SingleStep;
|
||||
in_step_line = true;
|
||||
success = true;
|
||||
} else {
|
||||
printf("No source location information for the current instruction\n");
|
||||
}
|
||||
} else if (command == "regs") {
|
||||
handle_print_registers(regs);
|
||||
success = true;
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
DebugSession::DebugSession(int pid)
|
||||
: m_debugee_pid(pid)
|
||||
, m_executable(String::format("/proc/%d/exe", pid))
|
||||
, m_elf(reinterpret_cast<u8*>(m_executable.data()), m_executable.size())
|
||||
, m_elf(ELF::Loader::create(reinterpret_cast<u8*>(m_executable.data()), m_executable.size()))
|
||||
, m_debug_info(m_elf)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,12 @@
|
|||
#include <AK/Demangle.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/MappedFile.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibC/sys/arch/i386/regs.h>
|
||||
#include <LibDebug/DebugInfo.h>
|
||||
#include <LibELF/Loader.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
@ -85,8 +87,10 @@ public:
|
|||
template<typename Callback>
|
||||
void run(Callback callback);
|
||||
|
||||
const ELF::Loader& elf() const { return m_elf; }
|
||||
const ELF::Loader& elf() const { return *m_elf; }
|
||||
NonnullRefPtr<const ELF::Loader> elf_ref() const { return m_elf; }
|
||||
const MappedFile& executable() const { return m_executable; }
|
||||
const DebugInfo& debug_info() const { return m_debug_info; }
|
||||
|
||||
enum DebugDecision {
|
||||
Continue,
|
||||
|
@ -104,14 +108,14 @@ public:
|
|||
|
||||
private:
|
||||
// x86 breakpoint instruction "int3"
|
||||
static constexpr u8 BREAKPOINT_INSTRUCTION
|
||||
= 0xcc;
|
||||
static constexpr u8 BREAKPOINT_INSTRUCTION = 0xcc;
|
||||
|
||||
int m_debugee_pid { -1 };
|
||||
bool m_is_debugee_dead { false };
|
||||
|
||||
MappedFile m_executable;
|
||||
ELF::Loader m_elf;
|
||||
NonnullRefPtr<const ELF::Loader> m_elf;
|
||||
DebugInfo m_debug_info;
|
||||
|
||||
HashMap<void*, BreakPoint> m_breakpoints;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
OBJS = \
|
||||
DebugSession.o
|
||||
DebugSession.o \
|
||||
DebugInfo.o \
|
||||
Dwarf/LineProgram.o \
|
||||
|
||||
|
||||
LIBRARY = libdebug.a
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue