mirror of
https://github.com/RGBCube/serenity
synced 2025-07-23 14:07:42 +00:00
LibDebug: Add remove_breakpoint
Also, change the interface of all breakpoint management functions to only take the address of the breakpoint as an argument.
This commit is contained in:
parent
e00b85b8c0
commit
009b4ea3f4
4 changed files with 59 additions and 18 deletions
|
@ -50,7 +50,7 @@ void DebugInfo::prepare_lines()
|
||||||
|
|
||||||
for (auto& line_info : all_lines) {
|
for (auto& line_info : all_lines) {
|
||||||
String file_path = line_info.file;
|
String file_path = line_info.file;
|
||||||
if (file_path.contains("Toolchain/"))
|
if (file_path.contains("Toolchain/") || file_path.contains("libgcc"))
|
||||||
continue;
|
continue;
|
||||||
if (file_path.contains("serenity/")) {
|
if (file_path.contains("serenity/")) {
|
||||||
auto start_index = file_path.index_of("serenity/").value() + String("serenity/").length();
|
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
|
// TODO: We can do a binray search here
|
||||||
for (size_t i = 0; i < m_sorted_lines.size() - 1; ++i) {
|
for (size_t i = 0; i < m_sorted_lines.size() - 1; ++i) {
|
||||||
if (m_sorted_lines[i + 1].address > target_address) {
|
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 {};
|
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
|
Optional<u32> DebugInfo::get_instruction_from_source(const String& file, size_t line) const
|
||||||
{
|
{
|
||||||
for (const auto& line_entry : m_sorted_lines) {
|
for (const auto& line_entry : m_sorted_lines) {
|
||||||
dbg() << line_entry.file;
|
|
||||||
if (line_entry.file == file && line_entry.line == line)
|
if (line_entry.file == file && line_entry.line == line)
|
||||||
return Optional<u32>(line_entry.address);
|
return Optional<u32>(line_entry.address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
struct SourcePosition {
|
struct SourcePosition {
|
||||||
String file_path;
|
String file_path;
|
||||||
size_t line_number { 0 };
|
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 file_path == other.file_path && line_number == other.line_number; }
|
||||||
bool operator!=(const SourcePosition& other) const { return !(*this == other); }
|
bool operator!=(const SourcePosition& other) const { return !(*this == other); }
|
||||||
|
@ -47,6 +48,20 @@ public:
|
||||||
Optional<SourcePosition> get_source_position(u32 address) const;
|
Optional<SourcePosition> get_source_position(u32 address) const;
|
||||||
Optional<u32> get_instruction_from_source(const String& file, size_t line) 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:
|
private:
|
||||||
void prepare_lines();
|
void prepare_lines();
|
||||||
|
|
||||||
|
|
|
@ -133,40 +133,58 @@ bool DebugSession::insert_breakpoint(void* address)
|
||||||
if (!original_bytes.has_value())
|
if (!original_bytes.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
ASSERT((original_bytes.value() & 0xff) != BREAKPOINT_INSTRUCTION);
|
||||||
|
|
||||||
BreakPoint breakpoint { address, original_bytes.value(), BreakPointState::Disabled };
|
BreakPoint breakpoint { address, original_bytes.value(), BreakPointState::Disabled };
|
||||||
|
|
||||||
m_breakpoints.set(address, breakpoint);
|
m_breakpoints.set(address, breakpoint);
|
||||||
|
|
||||||
enable_breakpoint(breakpoint);
|
enable_breakpoint(breakpoint.address);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DebugSession::disable_breakpoint(const BreakPoint& breakpoint)
|
bool DebugSession::disable_breakpoint(void* address)
|
||||||
{
|
{
|
||||||
ASSERT(m_breakpoints.contains(breakpoint.address));
|
auto breakpoint = m_breakpoints.get(address);
|
||||||
if (!poke(reinterpret_cast<u32*>(reinterpret_cast<char*>(breakpoint.address)), breakpoint.original_first_word))
|
ASSERT(breakpoint.has_value());
|
||||||
|
if (!poke(reinterpret_cast<u32*>(reinterpret_cast<char*>(breakpoint.value().address)), breakpoint.value().original_first_word))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto bp = m_breakpoints.get(breakpoint.address).value();
|
auto bp = m_breakpoints.get(breakpoint.value().address).value();
|
||||||
bp.state = BreakPointState::Disabled;
|
bp.state = BreakPointState::Disabled;
|
||||||
m_breakpoints.set(bp.address, bp);
|
m_breakpoints.set(bp.address, bp);
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
|
||||||
auto bp = m_breakpoints.get(breakpoint.address).value();
|
auto bp = m_breakpoints.get(breakpoint.value().address).value();
|
||||||
bp.state = BreakPointState::Enabled;
|
bp.state = BreakPointState::Enabled;
|
||||||
m_breakpoints.set(bp.address, bp);
|
m_breakpoints.set(bp.address, bp);
|
||||||
return true;
|
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 DebugSession::get_registers() const
|
||||||
{
|
{
|
||||||
PtraceRegisters regs;
|
PtraceRegisters regs;
|
||||||
|
|
|
@ -67,8 +67,17 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
bool insert_breakpoint(void* address);
|
bool insert_breakpoint(void* address);
|
||||||
bool disable_breakpoint(const BreakPoint&);
|
bool disable_breakpoint(void* address);
|
||||||
bool enable_breakpoint(const BreakPoint&);
|
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;
|
PtraceRegisters get_registers() const;
|
||||||
void set_registers(const PtraceRegisters&);
|
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
|
// We want to make the breakpoint transparrent to the user of the debugger
|
||||||
regs.eip = reinterpret_cast<u32>(current_breakpoint.value().address);
|
regs.eip = reinterpret_cast<u32>(current_breakpoint.value().address);
|
||||||
set_registers(regs);
|
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;
|
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;
|
state = State::Syscall;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_breakpoint.has_value()) {
|
// Re-enable the breakpoint if it wasn't removed by the user
|
||||||
// Re-enable the breakpoint
|
if (current_breakpoint.has_value() && m_breakpoints.contains(current_breakpoint.value().address)) {
|
||||||
auto stopped_address = single_step();
|
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,
|
// If there is another breakpoint after the current one,
|
||||||
// Then we are already on it (because of single_step)
|
// Then we are already on it (because of single_step)
|
||||||
auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address);
|
auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue