diff --git a/Libraries/LibDebug/DebugInfo.cpp b/Libraries/LibDebug/DebugInfo.cpp index 85c2a4bb2f..c684b190ec 100644 --- a/Libraries/LibDebug/DebugInfo.cpp +++ b/Libraries/LibDebug/DebugInfo.cpp @@ -50,7 +50,7 @@ void DebugInfo::prepare_lines() for (auto& line_info : all_lines) { String file_path = line_info.file; - if (file_path.contains("Toolchain/")) + if (file_path.contains("Toolchain/") || file_path.contains("libgcc")) continue; if (file_path.contains("serenity/")) { auto start_index = file_path.index_of("serenity/").value() + String("serenity/").length(); @@ -74,7 +74,7 @@ Optional DebugInfo::get_source_position(u32 target_ad // TODO: We can do a binray search here for (size_t i = 0; i < m_sorted_lines.size() - 1; ++i) { if (m_sorted_lines[i + 1].address > target_address) { - return Optional({ m_sorted_lines[i].file, m_sorted_lines[i].line }); + return Optional({ m_sorted_lines[i].file, m_sorted_lines[i].line, m_sorted_lines[i].address }); } } return {}; @@ -83,7 +83,6 @@ Optional DebugInfo::get_source_position(u32 target_ad Optional DebugInfo::get_instruction_from_source(const String& file, size_t line) const { for (const auto& line_entry : m_sorted_lines) { - dbg() << line_entry.file; if (line_entry.file == file && line_entry.line == line) return Optional(line_entry.address); } diff --git a/Libraries/LibDebug/DebugInfo.h b/Libraries/LibDebug/DebugInfo.h index 150820c4f0..825a27e073 100644 --- a/Libraries/LibDebug/DebugInfo.h +++ b/Libraries/LibDebug/DebugInfo.h @@ -39,6 +39,7 @@ public: struct SourcePosition { String file_path; size_t line_number { 0 }; + u32 address_of_first_statement { 0 }; bool operator==(const SourcePosition& other) const { return file_path == other.file_path && line_number == other.line_number; } bool operator!=(const SourcePosition& other) const { return !(*this == other); } @@ -47,6 +48,20 @@ public: Optional get_source_position(u32 address) const; Optional get_instruction_from_source(const String& file, size_t line) const; + template + void for_each_source_position(Callback callback) const + { + String previous_file = ""; + size_t previous_line = 0; + for (const auto& line_info : m_sorted_lines) { + if (line_info.file == previous_file && line_info.line == previous_line) + continue; + previous_file = line_info.file; + previous_line = line_info.line; + callback({ line_info.file, line_info.line, line_info.address }); + } + } + private: void prepare_lines(); diff --git a/Libraries/LibDebug/DebugSession.cpp b/Libraries/LibDebug/DebugSession.cpp index 8dbeda895d..91c6f38dcc 100644 --- a/Libraries/LibDebug/DebugSession.cpp +++ b/Libraries/LibDebug/DebugSession.cpp @@ -133,40 +133,58 @@ bool DebugSession::insert_breakpoint(void* address) if (!original_bytes.has_value()) return false; + ASSERT((original_bytes.value() & 0xff) != BREAKPOINT_INSTRUCTION); + BreakPoint breakpoint { address, original_bytes.value(), BreakPointState::Disabled }; m_breakpoints.set(address, breakpoint); - enable_breakpoint(breakpoint); + enable_breakpoint(breakpoint.address); return true; } -bool DebugSession::disable_breakpoint(const BreakPoint& breakpoint) +bool DebugSession::disable_breakpoint(void* address) { - ASSERT(m_breakpoints.contains(breakpoint.address)); - if (!poke(reinterpret_cast(reinterpret_cast(breakpoint.address)), breakpoint.original_first_word)) + auto breakpoint = m_breakpoints.get(address); + ASSERT(breakpoint.has_value()); + if (!poke(reinterpret_cast(reinterpret_cast(breakpoint.value().address)), breakpoint.value().original_first_word)) return false; - auto bp = m_breakpoints.get(breakpoint.address).value(); + auto bp = m_breakpoints.get(breakpoint.value().address).value(); bp.state = BreakPointState::Disabled; m_breakpoints.set(bp.address, bp); return true; } -bool DebugSession::enable_breakpoint(const BreakPoint& breakpoint) +bool DebugSession::enable_breakpoint(void* address) { - ASSERT(m_breakpoints.contains(breakpoint.address)); + auto breakpoint = m_breakpoints.get(address); + ASSERT(breakpoint.has_value()); - if (!poke(reinterpret_cast(breakpoint.address), (breakpoint.original_first_word & ~(uint32_t)0xff) | BREAKPOINT_INSTRUCTION)) + if (!poke(reinterpret_cast(breakpoint.value().address), (breakpoint.value().original_first_word & ~(uint32_t)0xff) | BREAKPOINT_INSTRUCTION)) return false; - auto bp = m_breakpoints.get(breakpoint.address).value(); + auto bp = m_breakpoints.get(breakpoint.value().address).value(); bp.state = BreakPointState::Enabled; m_breakpoints.set(bp.address, bp); return true; } +bool DebugSession::remove_breakpoint(void* address) +{ + if (!disable_breakpoint(address)) + return false; + + m_breakpoints.remove(address); + return true; +} + +bool DebugSession::breakpoint_exists(void* address) const +{ + return m_breakpoints.contains(address); +} + PtraceRegisters DebugSession::get_registers() const { PtraceRegisters regs; diff --git a/Libraries/LibDebug/DebugSession.h b/Libraries/LibDebug/DebugSession.h index 207496aec3..20a549f777 100644 --- a/Libraries/LibDebug/DebugSession.h +++ b/Libraries/LibDebug/DebugSession.h @@ -67,8 +67,17 @@ public: }; bool insert_breakpoint(void* address); - bool disable_breakpoint(const BreakPoint&); - bool enable_breakpoint(const BreakPoint&); + bool disable_breakpoint(void* address); + bool enable_breakpoint(void* address); + bool remove_breakpoint(void* address); + bool breakpoint_exists(void* address) const; + + void dump_breakpoints() + { + for (auto addr : m_breakpoints.keys()) { + dbg() << addr; + } + } PtraceRegisters get_registers() const; void set_registers(const PtraceRegisters&); @@ -167,7 +176,7 @@ void DebugSession::run(Callback callback) // We want to make the breakpoint transparrent to the user of the debugger regs.eip = reinterpret_cast(current_breakpoint.value().address); set_registers(regs); - disable_breakpoint(current_breakpoint.value()); + disable_breakpoint(current_breakpoint.value().address); } DebugBreakReason reason = (state == State::Syscall && !current_breakpoint.has_value()) ? DebugBreakReason::Syscall : DebugBreakReason::Breakpoint; @@ -185,10 +194,10 @@ void DebugSession::run(Callback callback) state = State::Syscall; } - if (current_breakpoint.has_value()) { - // Re-enable the breakpoint + // Re-enable the breakpoint if it wasn't removed by the user + if (current_breakpoint.has_value() && m_breakpoints.contains(current_breakpoint.value().address)) { auto stopped_address = single_step(); - enable_breakpoint(current_breakpoint.value()); + enable_breakpoint(current_breakpoint.value().address); // If there is another breakpoint after the current one, // Then we are already on it (because of single_step) auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address);