Просмотр исходного кода

HackStudio: Make debugger support shared libraries

Itamar 4 лет назад
Родитель
Сommit
94db04fc12

+ 4 - 1
DevTools/HackStudio/Debugger/BacktraceModel.cpp

@@ -57,7 +57,10 @@ Vector<BacktraceModel::FrameInfo> BacktraceModel::create_backtrace(const Debug::
     u32 current_instruction = regs.eip;
     Vector<BacktraceModel::FrameInfo> 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 = "<missing>";

+ 32 - 15
DevTools/HackStudio/Debugger/Debugger.cpp

@@ -38,11 +38,12 @@ Debugger& Debugger::the()
 }
 
 void Debugger::initialize(
+    String source_root,
     Function<HasControlPassedToUser(const PtraceRegisters&)> on_stop_callback,
     Function<void()> on_continue_callback,
     Function<void()> 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<HasControlPassedToUser(const PtraceRegisters&)> on_stop_callback,
     Function<void()> on_continue_callback,
     Function<void()> 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<void*>(address.value()));
+        bool success = session->insert_breakpoint(reinterpret_cast<void*>(address.value().address));
         ASSERT(success);
     } else {
-        bool success = session->remove_breakpoint(reinterpret_cast<void*>(address.value()));
+        bool success = session->remove_breakpoint(reinterpret_cast<void*>(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<void*>(address.value()));
+            bool success = m_debug_session->insert_breakpoint(reinterpret_cast<void*>(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<PtraceRegisters> optional_regs) {
+    m_debug_session->run(Debug::DebugSession::DesiredInitialDebugeeState::Running, [this](Debug::DebugSession::DebugBreakReason reason, Optional<PtraceRegisters> 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);
 }

+ 3 - 0
DevTools/HackStudio/Debugger/Debugger.h

@@ -45,6 +45,7 @@ public:
     };
 
     static void initialize(
+        String source_root,
         Function<HasControlPassedToUser(const PtraceRegisters&)> on_stop_callback,
         Function<void()> on_continue_callback,
         Function<void()> on_exit_callback);
@@ -102,6 +103,7 @@ private:
     };
 
     explicit Debugger(
+        String source_root,
         Function<HasControlPassedToUser(const PtraceRegisters&)> on_stop_callback,
         Function<void()> on_continue_callback,
         Function<void()> on_exit_callback);
@@ -118,6 +120,7 @@ private:
     void insert_temporary_breakpoint_at_return_address(const PtraceRegisters&);
 
     OwnPtr<Debug::DebugSession> m_debug_session;
+    String m_source_root;
     DebuggingState m_state;
 
     pthread_mutex_t m_ui_action_mutex {};

+ 5 - 2
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<ELF::Image>((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);

+ 4 - 1
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

+ 4 - 1
DevTools/HackStudio/Debugger/VariablesModel.cpp

@@ -184,7 +184,10 @@ void VariablesModel::update()
 
 RefPtr<VariablesModel> 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));
 }
 

+ 3 - 1
DevTools/HackStudio/HackStudioWidget.cpp

@@ -522,14 +522,16 @@ NonnullRefPtr<GUI::Action> 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(),