1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:38:11 +00:00

LibDebug: Support shared libraries

DebugSession now makes the loader stop after loading the libraries,
and parses the loaded libraries of the program before continuing its
execution.

DebugSession now also supports inserting a breakpoint at a given symbol
or source position.
Additionally, DebugInfo now takes the base address of its object into
consideration.
This commit is contained in:
Itamar 2021-01-06 21:49:25 +02:00 committed by Andreas Kling
parent ca9d6d21b5
commit 4b91e7c821
6 changed files with 328 additions and 53 deletions

View file

@ -25,6 +25,7 @@
*/
#include "DebugInfo.h"
#include <AK/LexicalPath.h>
#include <AK/MemoryStream.h>
#include <AK/QuickSort.h>
#include <LibDebug/Dwarf/CompilationUnit.h>
@ -35,8 +36,10 @@
namespace Debug {
DebugInfo::DebugInfo(NonnullOwnPtr<const ELF::Image> elf)
DebugInfo::DebugInfo(NonnullOwnPtr<const ELF::Image> elf, String source_root, FlatPtr base_address)
: m_elf(move(elf))
, m_source_root(source_root)
, m_base_address(base_address)
, m_dwarf_info(*m_elf)
{
prepare_variable_scopes();
@ -124,6 +127,9 @@ void DebugInfo::prepare_lines()
auto start_index = file_path.index_of(serenity_slash).value() + serenity_slash.length();
file_path = file_path.substring(start_index, file_path.length() - start_index);
}
if (file_path.starts_with("./") && !m_source_root.is_null()) {
file_path = LexicalPath::canonicalized_path(String::formatted("{}/{}", m_source_root, file_path));
}
m_sorted_lines.append({ line_info.address, file_path, line_info.line });
}
quick_sort(m_sorted_lines, [](auto& a, auto& b) {
@ -147,19 +153,34 @@ Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(u32 target_ad
return {};
}
Optional<u32> DebugInfo::get_instruction_from_source(const String& file, size_t line) const
Optional<DebugInfo::SourcePositionAndAddress> DebugInfo::get_address_from_source_position(const String& file, size_t line) const
{
String file_path = file;
if (!file_path.starts_with("/"))
file_path = String::format("/%s", file_path.characters());
constexpr char SERENITY_LIBS_PREFIX[] = "/usr/src/serenity";
if (file.starts_with(SERENITY_LIBS_PREFIX)) {
file_path = file.substring(sizeof(SERENITY_LIBS_PREFIX), file.length() - sizeof(SERENITY_LIBS_PREFIX));
file_path = String::format("../%s", file_path.characters());
}
Optional<SourcePositionAndAddress> result;
for (const auto& line_entry : m_sorted_lines) {
if (line_entry.file == file_path && line_entry.line == line)
return Optional<u32>(line_entry.address);
if (!line_entry.file.ends_with(file_path))
continue;
if (line_entry.line > line)
continue;
// We look for the source position that is closest to the desired position, and is not after it.
// For example, get_address_of_source_position("main.cpp", 73) could return the address for an instruction whose location is ("main.cpp", 72)
// as there might not be an instruction mapped for "main.cpp", 73.
if (!result.has_value() || (line_entry.line > result.value().line)) {
result = SourcePositionAndAddress { line_entry.file, line_entry.line, line_entry.address };
}
}
return {};
return result;
}
NonnullOwnPtrVector<DebugInfo::VariableInfo> DebugInfo::get_variables_in_current_scope(const PtraceRegisters& regs) const
@ -168,7 +189,7 @@ NonnullOwnPtrVector<DebugInfo::VariableInfo> DebugInfo::get_variables_in_current
// TODO: We can store the scopes in a better data structure
for (const auto& scope : m_scopes) {
if (regs.eip < scope.address_low || regs.eip >= scope.address_high)
if (regs.eip - m_base_address < scope.address_low || regs.eip - m_base_address >= scope.address_high)
continue;
for (const auto& die_entry : scope.dies_of_variables) {
@ -336,7 +357,7 @@ Vector<DebugInfo::SourcePosition> DebugInfo::source_lines_in_scope(const Variabl
DebugInfo::SourcePosition DebugInfo::SourcePosition::from_line_info(const Dwarf::LineProgram::LineInfo& line)
{
return { line.file, line.line, line.address };
return { line.file, line.line, { line.address } };
}
}