Explorar el Código

LibDebug: Add remove_breakpoint

Also, change the interface of all breakpoint management functions to
only take the address of the breakpoint as an argument.
Itamar hace 5 años
padre
commit
009b4ea3f4

+ 2 - 3
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::SourcePosition> 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<SourcePosition>({ m_sorted_lines[i].file, m_sorted_lines[i].line });
+            return Optional<SourcePosition>({ m_sorted_lines[i].file, m_sorted_lines[i].line, m_sorted_lines[i].address });
         }
     }
     return {};
@@ -83,7 +83,6 @@ Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(u32 target_ad
 Optional<u32> 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<u32>(line_entry.address);
     }

+ 15 - 0
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<SourcePosition> get_source_position(u32 address) const;
     Optional<u32> get_instruction_from_source(const String& file, size_t line) const;
 
+    template<typename Callback>
+    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();
 

+ 27 - 9
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<u32*>(reinterpret_cast<char*>(breakpoint.address)), breakpoint.original_first_word))
+    auto breakpoint = m_breakpoints.get(address);
+    ASSERT(breakpoint.has_value());
+    if (!poke(reinterpret_cast<u32*>(reinterpret_cast<char*>(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<u32*>(breakpoint.address), (breakpoint.original_first_word & ~(uint32_t)0xff) | BREAKPOINT_INSTRUCTION))
+    if (!poke(reinterpret_cast<u32*>(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;

+ 15 - 6
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<u32>(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);