diff --git a/DevTools/HackStudio/Debugger/BacktraceModel.cpp b/DevTools/HackStudio/Debugger/BacktraceModel.cpp index f85539778bc..fe0f6a31f59 100644 --- a/DevTools/HackStudio/Debugger/BacktraceModel.cpp +++ b/DevTools/HackStudio/Debugger/BacktraceModel.cpp @@ -57,7 +57,10 @@ Vector BacktraceModel::create_backtrace(const Debug:: u32 current_instruction = regs.eip; Vector frames; do { - String name = debug_session.debug_info().name_of_containing_function(current_instruction); + auto lib = debug_session.library_at(regs.eip); + if (!lib) + continue; + String name = lib->debug_info->name_of_containing_function(current_instruction - lib->base_address); if (name.is_null()) { dbgln("BacktraceModel: couldn't find containing function for address: {:p}", current_instruction); name = ""; diff --git a/DevTools/HackStudio/Debugger/Debugger.cpp b/DevTools/HackStudio/Debugger/Debugger.cpp index 0c531e65e77..20527e379de 100644 --- a/DevTools/HackStudio/Debugger/Debugger.cpp +++ b/DevTools/HackStudio/Debugger/Debugger.cpp @@ -38,11 +38,12 @@ Debugger& Debugger::the() } void Debugger::initialize( + String source_root, Function on_stop_callback, Function on_continue_callback, Function on_exit_callback) { - s_the = new Debugger(move(on_stop_callback), move(on_continue_callback), move(on_exit_callback)); + s_the = new Debugger(source_root, move(on_stop_callback), move(on_continue_callback), move(on_exit_callback)); } bool Debugger::is_initialized() @@ -51,10 +52,12 @@ bool Debugger::is_initialized() } Debugger::Debugger( + String source_root, Function on_stop_callback, Function on_continue_callback, Function on_exit_callback) - : m_on_stopped_callback(move(on_stop_callback)) + : m_source_root(source_root) + , m_on_stopped_callback(move(on_stop_callback)) , m_on_continue_callback(move(on_continue_callback)) , m_on_exit_callback(move(on_exit_callback)) { @@ -76,7 +79,7 @@ void Debugger::on_breakpoint_change(const String& file, size_t line, BreakpointC if (!session) return; - auto address = session->debug_info().get_instruction_from_source(position.file_path, position.line_number); + auto address = session->get_address_from_source_position(position.file_path, position.line_number); if (!address.has_value()) { dbgln("Warning: couldn't get instruction address from source"); // TODO: Currently, the GUI will indicate that a breakpoint was inserted/removed at this line, @@ -86,10 +89,10 @@ void Debugger::on_breakpoint_change(const String& file, size_t line, BreakpointC } if (change_type == BreakpointChange::Added) { - bool success = session->insert_breakpoint(reinterpret_cast(address.value())); + bool success = session->insert_breakpoint(reinterpret_cast(address.value().address)); ASSERT(success); } else { - bool success = session->remove_breakpoint(reinterpret_cast(address.value())); + bool success = session->remove_breakpoint(reinterpret_cast(address.value().address)); ASSERT(success); } } @@ -109,14 +112,14 @@ int Debugger::start_static() void Debugger::start() { - m_debug_session = Debug::DebugSession::exec_and_attach(m_executable_path); + m_debug_session = Debug::DebugSession::exec_and_attach(m_executable_path, m_source_root); ASSERT(!!m_debug_session); for (const auto& breakpoint : m_breakpoints) { - dbgln("insertig breakpoint at: {}:{}", breakpoint.file_path, breakpoint.line_number); - auto address = m_debug_session->debug_info().get_instruction_from_source(breakpoint.file_path, breakpoint.line_number); + dbgln("inserting breakpoint at: {}:{}", breakpoint.file_path, breakpoint.line_number); + auto address = m_debug_session->get_address_from_source_position(breakpoint.file_path, breakpoint.line_number); if (address.has_value()) { - bool success = m_debug_session->insert_breakpoint(reinterpret_cast(address.value())); + bool success = m_debug_session->insert_breakpoint(reinterpret_cast(address.value().address)); ASSERT(success); } else { dbgln("couldn't insert breakpoint"); @@ -130,7 +133,7 @@ int Debugger::debugger_loop() { ASSERT(m_debug_session); - m_debug_session->run([this](Debug::DebugSession::DebugBreakReason reason, Optional optional_regs) { + m_debug_session->run(Debug::DebugSession::DesiredInitialDebugeeState::Running, [this](Debug::DebugSession::DebugBreakReason reason, Optional optional_regs) { if (reason == Debug::DebugSession::DebugBreakReason::Exited) { dbgln("Program exited"); m_on_exit_callback(); @@ -140,9 +143,16 @@ int Debugger::debugger_loop() ASSERT(optional_regs.has_value()); const PtraceRegisters& regs = optional_regs.value(); - auto source_position = m_debug_session->debug_info().get_source_position(regs.eip); + auto source_position = m_debug_session->get_source_position(regs.eip); + if (!source_position.has_value()) + return Debug::DebugSession::DebugDecision::SingleStep; + + // We currently do no support stepping through assembly source + if (source_position.value().file_path.ends_with(".S")) + return Debug::DebugSession::DebugDecision::SingleStep; + + ASSERT(source_position.has_value()); if (m_state.get() == Debugger::DebuggingState::SingleStepping) { - ASSERT(source_position.has_value()); if (m_state.should_stop_single_stepping(source_position.value())) { m_state.set_normal(); } else { @@ -241,11 +251,18 @@ void Debugger::do_step_over(const PtraceRegisters& regs) { // To step over, we insert a temporary breakpoint at each line in the current function, // as well as at the current function's return point, and continue execution. - auto current_function = m_debug_session->debug_info().get_containing_function(regs.eip); + auto lib = m_debug_session->library_at(regs.eip); + if (!lib) + return; + auto current_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address); + if (!current_function.has_value()) { + dbgln("cannot perform step_over, failed to find containing function of: {:p}", regs.eip); + return; + } ASSERT(current_function.has_value()); - auto lines_in_current_function = m_debug_session->debug_info().source_lines_in_scope(current_function.value()); + auto lines_in_current_function = lib->debug_info->source_lines_in_scope(current_function.value()); for (const auto& line : lines_in_current_function) { - insert_temporary_breakpoint(line.address_of_first_statement); + insert_temporary_breakpoint(line.address_of_first_statement.value() + lib->base_address); } insert_temporary_breakpoint_at_return_address(regs); } diff --git a/DevTools/HackStudio/Debugger/Debugger.h b/DevTools/HackStudio/Debugger/Debugger.h index 5c38d4bbcef..0d2371f86e1 100644 --- a/DevTools/HackStudio/Debugger/Debugger.h +++ b/DevTools/HackStudio/Debugger/Debugger.h @@ -45,6 +45,7 @@ public: }; static void initialize( + String source_root, Function on_stop_callback, Function on_continue_callback, Function on_exit_callback); @@ -102,6 +103,7 @@ private: }; explicit Debugger( + String source_root, Function on_stop_callback, Function on_continue_callback, Function on_exit_callback); @@ -118,6 +120,7 @@ private: void insert_temporary_breakpoint_at_return_address(const PtraceRegisters&); OwnPtr m_debug_session; + String m_source_root; DebuggingState m_state; pthread_mutex_t m_ui_action_mutex {}; diff --git a/DevTools/HackStudio/Debugger/DisassemblyModel.cpp b/DevTools/HackStudio/Debugger/DisassemblyModel.cpp index 394abdd13ff..fe800df23cf 100644 --- a/DevTools/HackStudio/Debugger/DisassemblyModel.cpp +++ b/DevTools/HackStudio/Debugger/DisassemblyModel.cpp @@ -38,7 +38,10 @@ namespace HackStudio { DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, const PtraceRegisters& regs) { - auto containing_function = debug_session.debug_info().get_containing_function(regs.eip); + auto lib = debug_session.library_at(regs.eip); + if (!lib) + return; + auto containing_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address); if (!containing_function.has_value()) { dbgln("Cannot disassemble as the containing function was not found."); return; @@ -54,7 +57,7 @@ DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, con kernel_elf = make((const u8*)kernel_file->data(), kernel_file->size()); elf = kernel_elf.ptr(); } else { - elf = &debug_session.elf(); + elf = &lib->debug_info->elf(); } auto symbol = elf->find_symbol(containing_function.value().address_low); diff --git a/DevTools/HackStudio/Debugger/DisassemblyWidget.cpp b/DevTools/HackStudio/Debugger/DisassemblyWidget.cpp index 9602d903920..89a670b2a20 100644 --- a/DevTools/HackStudio/Debugger/DisassemblyWidget.cpp +++ b/DevTools/HackStudio/Debugger/DisassemblyWidget.cpp @@ -64,7 +64,10 @@ void DisassemblyWidget::update_state(const Debug::DebugSession& debug_session, c m_disassembly_view->set_model(DisassemblyModel::create(debug_session, regs)); if (m_disassembly_view->model()->row_count() > 0) { - auto containing_function = debug_session.debug_info().get_containing_function(regs.eip); + auto lib = debug_session.library_at(regs.eip); + if (!lib) + return; + auto containing_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address); if (containing_function.has_value()) m_function_name_label->set_text(containing_function.value().name); else diff --git a/DevTools/HackStudio/Debugger/VariablesModel.cpp b/DevTools/HackStudio/Debugger/VariablesModel.cpp index b3d3cbf6bd0..b166154d250 100644 --- a/DevTools/HackStudio/Debugger/VariablesModel.cpp +++ b/DevTools/HackStudio/Debugger/VariablesModel.cpp @@ -184,7 +184,10 @@ void VariablesModel::update() RefPtr VariablesModel::create(const PtraceRegisters& regs) { - auto variables = Debugger::the().session()->debug_info().get_variables_in_current_scope(regs); + auto lib = Debugger::the().session()->library_at(regs.eip); + if (!lib) + return nullptr; + auto variables = lib->debug_info->get_variables_in_current_scope(regs); return adopt(*new VariablesModel(move(variables), regs)); } diff --git a/DevTools/HackStudio/HackStudioWidget.cpp b/DevTools/HackStudio/HackStudioWidget.cpp index bf149391f65..7ef0eb33d29 100644 --- a/DevTools/HackStudio/HackStudioWidget.cpp +++ b/DevTools/HackStudio/HackStudioWidget.cpp @@ -522,14 +522,16 @@ NonnullRefPtr HackStudioWidget::create_debug_action() void HackStudioWidget::initialize_debugger() { Debugger::initialize( + m_project->root_path(), [this](const PtraceRegisters& regs) { ASSERT(Debugger::the().session()); const auto& debug_session = *Debugger::the().session(); - auto source_position = debug_session.debug_info().get_source_position(regs.eip); + auto source_position = debug_session.get_source_position(regs.eip); if (!source_position.has_value()) { dbgln("Could not find source position for address: {:p}", regs.eip); return Debugger::HasControlPassedToUser::No; } + dbgln("Debugger stopped at source position: {}:{}", source_position.value().file_path, source_position.value().line_number); Core::EventLoop::main().post_event( *window(),