summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorItamar <itamar8910@gmail.com>2021-11-19 16:13:07 +0200
committerLinus Groh <mail@linusgroh.de>2021-11-20 21:22:24 +0000
commit7950f5cb51549dc304e51616597b96dc4c273b51 (patch)
treebb6a05c3ceac4f44f378cbbe6d1b84615665468b
parent38ddf301f63011992209baeb4bafd8f8047a2b9d (diff)
downloadserenity-7950f5cb51549dc304e51616597b96dc4c273b51.zip
LibDebug: Add ProcessInspector base class
ProcessInspector is an abstract base class for an object that can inspect the address space of a process. Concrete sub classes need to implement methods for peeking & poking memory and walking the loaded libraries. It is currently only implemented by DebugSession.
-rw-r--r--Userland/Libraries/LibDebug/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibDebug/DebugSession.cpp92
-rw-r--r--Userland/Libraries/LibDebug/DebugSession.h65
-rw-r--r--Userland/Libraries/LibDebug/LoadedLibrary.h32
-rw-r--r--Userland/Libraries/LibDebug/ProcessInspector.cpp62
-rw-r--r--Userland/Libraries/LibDebug/ProcessInspector.h37
-rw-r--r--Userland/Utilities/functrace.cpp2
7 files changed, 173 insertions, 118 deletions
diff --git a/Userland/Libraries/LibDebug/CMakeLists.txt b/Userland/Libraries/LibDebug/CMakeLists.txt
index f823a550d5..e2cc975fd8 100644
--- a/Userland/Libraries/LibDebug/CMakeLists.txt
+++ b/Userland/Libraries/LibDebug/CMakeLists.txt
@@ -9,6 +9,7 @@ set(SOURCES
Dwarf/DwarfInfo.cpp
Dwarf/Expression.cpp
Dwarf/LineProgram.cpp
+ ProcessInspector.cpp
StackFrameUtils.cpp
)
diff --git a/Userland/Libraries/LibDebug/DebugSession.cpp b/Userland/Libraries/LibDebug/DebugSession.cpp
index b91b0b801d..41b579dacf 100644
--- a/Userland/Libraries/LibDebug/DebugSession.cpp
+++ b/Userland/Libraries/LibDebug/DebugSession.cpp
@@ -44,6 +44,15 @@ DebugSession::~DebugSession()
}
}
+void DebugSession::for_each_loaded_library(Function<IterationDecision(LoadedLibrary const&)> func) const
+{
+ for (const auto& lib_name : m_loaded_libraries.keys()) {
+ const auto& lib = *m_loaded_libraries.get(lib_name).value();
+ if (func(lib) == IterationDecision::Break)
+ break;
+ }
+}
+
OwnPtr<DebugSession> DebugSession::exec_and_attach(String const& command, String source_root)
{
auto pid = fork();
@@ -110,39 +119,39 @@ OwnPtr<DebugSession> DebugSession::exec_and_attach(String const& command, String
return debug_session;
}
-bool DebugSession::poke(u32* address, u32 data)
+bool DebugSession::poke(void* address, FlatPtr data)
{
- if (ptrace(PT_POKE, m_debuggee_pid, (void*)address, data) < 0) {
+ if (ptrace(PT_POKE, m_debuggee_pid, (void*)address, (void*)data) < 0) {
perror("PT_POKE");
return false;
}
return true;
}
-Optional<u32> DebugSession::peek(u32* address) const
+Optional<FlatPtr> DebugSession::peek(void* address) const
{
- Optional<u32> result;
- int rc = ptrace(PT_PEEK, m_debuggee_pid, (void*)address, 0);
+ Optional<FlatPtr> result;
+ auto rc = ptrace(PT_PEEK, m_debuggee_pid, address, nullptr);
if (errno == 0)
- result = static_cast<u32>(rc);
+ result = static_cast<FlatPtr>(rc);
return result;
}
-bool DebugSession::poke_debug(u32 register_index, u32 data)
+bool DebugSession::poke_debug(u32 register_index, FlatPtr data)
{
- if (ptrace(PT_POKEDEBUG, m_debuggee_pid, reinterpret_cast<u32*>(register_index), data) < 0) {
+ if (ptrace(PT_POKEDEBUG, m_debuggee_pid, reinterpret_cast<void*>(register_index), (void*)data) < 0) {
perror("PT_POKEDEBUG");
return false;
}
return true;
}
-Optional<u32> DebugSession::peek_debug(u32 register_index) const
+Optional<FlatPtr> DebugSession::peek_debug(u32 register_index) const
{
- Optional<u32> result;
- int rc = ptrace(PT_PEEKDEBUG, m_debuggee_pid, reinterpret_cast<u32*>(register_index), 0);
+ Optional<FlatPtr> result;
+ int rc = ptrace(PT_PEEKDEBUG, m_debuggee_pid, reinterpret_cast<FlatPtr*>(register_index), nullptr);
if (errno == 0)
- result = static_cast<u32>(rc);
+ result = static_cast<FlatPtr>(rc);
return result;
}
@@ -155,7 +164,7 @@ bool DebugSession::insert_breakpoint(void* address)
if (m_breakpoints.contains(address))
return false;
- auto original_bytes = peek(reinterpret_cast<u32*>(address));
+ auto original_bytes = peek(reinterpret_cast<FlatPtr*>(address));
if (!original_bytes.has_value())
return false;
@@ -175,7 +184,7 @@ bool DebugSession::disable_breakpoint(void* address)
{
auto breakpoint = m_breakpoints.get(address);
VERIFY(breakpoint.has_value());
- if (!poke(reinterpret_cast<u32*>(reinterpret_cast<char*>(breakpoint.value().address)), breakpoint.value().original_first_word))
+ if (!poke(reinterpret_cast<FlatPtr*>(reinterpret_cast<char*>(breakpoint.value().address)), breakpoint.value().original_first_word))
return false;
auto bp = m_breakpoints.get(breakpoint.value().address).value();
@@ -191,7 +200,7 @@ bool DebugSession::enable_breakpoint(void* address)
VERIFY(breakpoint.value().state == BreakPointState::Disabled);
- if (!poke(reinterpret_cast<u32*>(breakpoint.value().address), (breakpoint.value().original_first_word & ~(uint32_t)0xff) | BREAKPOINT_INSTRUCTION))
+ if (!poke(reinterpret_cast<FlatPtr*>(breakpoint.value().address), (breakpoint.value().original_first_word & ~(FlatPtr)0xff) | BREAKPOINT_INSTRUCTION))
return false;
auto bp = m_breakpoints.get(breakpoint.value().address).value();
@@ -219,7 +228,8 @@ bool DebugSession::insert_watchpoint(void* address, u32 ebp)
auto current_register_status = peek_debug(DEBUG_CONTROL_REGISTER);
if (!current_register_status.has_value())
return false;
- u32 dr7_value = current_register_status.value();
+ // FIXME: 64 bit support
+ u32 dr7_value = static_cast<u32>(current_register_status.value());
u32 next_available_index;
for (next_available_index = 0; next_available_index < 4; next_available_index++) {
auto bitmask = 1 << (next_available_index * 2);
@@ -455,54 +465,4 @@ void DebugSession::update_loaded_libs()
});
}
-const DebugSession::LoadedLibrary* DebugSession::library_at(FlatPtr address) const
-{
- const LoadedLibrary* result = nullptr;
- for_each_loaded_library([&result, address](const auto& lib) {
- if (address >= lib.base_address && address < lib.base_address + lib.debug_info->elf().size()) {
- result = &lib;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- return result;
-}
-
-Optional<DebugSession::SymbolicationResult> DebugSession::symbolicate(FlatPtr address) const
-{
- auto* lib = library_at(address);
- if (!lib)
- return {};
- //FIXME: ELF::Image symlicate() API should return String::empty() if symbol is not found (It currently returns ??)
- auto symbol = lib->debug_info->elf().symbolicate(address - lib->base_address);
- return { { lib->name, symbol } };
-}
-
-Optional<DebugInfo::SourcePositionAndAddress> DebugSession::get_address_from_source_position(String const& file, size_t line) const
-{
- Optional<DebugInfo::SourcePositionAndAddress> result;
- for_each_loaded_library([file, line, &result](auto& lib) {
- // The loader contains its own definitions for LibC symbols, so we don't want to include it in the search.
- if (lib.name == "Loader.so")
- return IterationDecision::Continue;
-
- auto source_position_and_address = lib.debug_info->get_address_from_source_position(file, line);
- if (!source_position_and_address.has_value())
- return IterationDecision::Continue;
-
- result = source_position_and_address;
- result.value().address += lib.base_address;
- return IterationDecision::Break;
- });
- return result;
-}
-
-Optional<DebugInfo::SourcePosition> DebugSession::get_source_position(FlatPtr address) const
-{
- auto* lib = library_at(address);
- if (!lib)
- return {};
- return lib->debug_info->get_source_position(address - lib->base_address);
-}
-
}
diff --git a/Userland/Libraries/LibDebug/DebugSession.h b/Userland/Libraries/LibDebug/DebugSession.h
index c678917770..43f05fb67f 100644
--- a/Userland/Libraries/LibDebug/DebugSession.h
+++ b/Userland/Libraries/LibDebug/DebugSession.h
@@ -15,6 +15,7 @@
#include <AK/String.h>
#include <LibC/sys/arch/i386/regs.h>
#include <LibDebug/DebugInfo.h>
+#include <LibDebug/ProcessInspector.h>
#include <signal.h>
#include <stdio.h>
#include <sys/ptrace.h>
@@ -23,19 +24,23 @@
namespace Debug {
-class DebugSession {
+class DebugSession : public ProcessInspector {
public:
static OwnPtr<DebugSession> exec_and_attach(String const& command, String source_root = {});
- ~DebugSession();
+ virtual ~DebugSession() override;
- int pid() const { return m_debuggee_pid; }
+ // ^Debug::ProcessInspector
+ virtual bool poke(void* address, FlatPtr data) override;
+ virtual Optional<FlatPtr> peek(void* address) const override;
+ virtual PtraceRegisters get_registers() const override;
+ virtual void set_registers(PtraceRegisters const&) override;
+ virtual void for_each_loaded_library(Function<IterationDecision(LoadedLibrary const&)>) const override;
- bool poke(u32* address, u32 data);
- Optional<u32> peek(u32* address) const;
+ int pid() const { return m_debuggee_pid; }
- bool poke_debug(u32 register_index, u32 data);
- Optional<u32> peek_debug(u32 register_index) const;
+ bool poke_debug(u32 register_index, FlatPtr data);
+ Optional<FlatPtr> peek_debug(u32 register_index) const;
enum class BreakPointState {
Enabled,
@@ -44,7 +49,7 @@ public:
struct BreakPoint {
void* address { nullptr };
- u32 original_first_word { 0 };
+ FlatPtr original_first_word { 0 };
BreakPointState state { BreakPointState::Disabled };
};
@@ -88,9 +93,6 @@ public:
}
}
- PtraceRegisters get_registers() const;
- void set_registers(PtraceRegisters const&);
-
enum class ContinueType {
FreeRun,
Syscall,
@@ -126,45 +128,6 @@ public:
Exited,
};
- struct LoadedLibrary {
- String name;
- NonnullRefPtr<MappedFile> file;
- NonnullOwnPtr<ELF::Image> image;
- NonnullOwnPtr<DebugInfo> debug_info;
- FlatPtr base_address;
-
- LoadedLibrary(String const& name, NonnullRefPtr<MappedFile> file, NonnullOwnPtr<ELF::Image> image, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address)
- : name(name)
- , file(move(file))
- , image(move(image))
- , debug_info(move(debug_info))
- , base_address(base_address)
- {
- }
- };
-
- template<typename Func>
- void for_each_loaded_library(Func f) const
- {
- for (const auto& lib_name : m_loaded_libraries.keys()) {
- const auto& lib = *m_loaded_libraries.get(lib_name).value();
- if (f(lib) == IterationDecision::Break)
- break;
- }
- }
-
- const LoadedLibrary* library_at(FlatPtr address) const;
-
- struct SymbolicationResult {
- String library_name;
- String symbol;
- };
- Optional<SymbolicationResult> symbolicate(FlatPtr address) const;
-
- Optional<DebugInfo::SourcePositionAndAddress> get_address_from_source_position(String const& file, size_t line) const;
-
- Optional<DebugInfo::SourcePosition> get_source_position(FlatPtr address) const;
-
private:
explicit DebugSession(pid_t, String source_root);
@@ -180,7 +143,7 @@ private:
HashMap<void*, BreakPoint> m_breakpoints;
HashMap<void*, WatchPoint> m_watchpoints;
- // Maps from base address to loaded library
+ // Maps from library name to LoadedLibrary obect
HashMap<String, NonnullOwnPtr<LoadedLibrary>> m_loaded_libraries;
};
diff --git a/Userland/Libraries/LibDebug/LoadedLibrary.h b/Userland/Libraries/LibDebug/LoadedLibrary.h
new file mode 100644
index 0000000000..15141bae88
--- /dev/null
+++ b/Userland/Libraries/LibDebug/LoadedLibrary.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include "DebugInfo.h"
+#include <AK/MappedFile.h>
+#include <AK/Types.h>
+#include <LibELF/Image.h>
+
+namespace Debug {
+struct LoadedLibrary {
+ String name;
+ NonnullRefPtr<MappedFile> file;
+ NonnullOwnPtr<ELF::Image> image;
+ NonnullOwnPtr<DebugInfo> debug_info;
+ FlatPtr base_address {};
+
+ LoadedLibrary(String const& name, NonnullRefPtr<MappedFile> file, NonnullOwnPtr<ELF::Image> image, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address)
+ : name(name)
+ , file(move(file))
+ , image(move(image))
+ , debug_info(move(debug_info))
+ , base_address(base_address)
+ {
+ }
+};
+
+}
diff --git a/Userland/Libraries/LibDebug/ProcessInspector.cpp b/Userland/Libraries/LibDebug/ProcessInspector.cpp
new file mode 100644
index 0000000000..c13f78cd58
--- /dev/null
+++ b/Userland/Libraries/LibDebug/ProcessInspector.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "ProcessInspector.h"
+#include "DebugInfo.h"
+
+namespace Debug {
+
+const LoadedLibrary* ProcessInspector::library_at(FlatPtr address) const
+{
+ const LoadedLibrary* result = nullptr;
+ for_each_loaded_library([&result, address](const auto& lib) {
+ if (address >= lib.base_address && address < lib.base_address + lib.debug_info->elf().size()) {
+ result = &lib;
+ return IterationDecision::Break;
+ }
+ return IterationDecision::Continue;
+ });
+ return result;
+}
+
+Optional<ProcessInspector::SymbolicationResult> ProcessInspector::symbolicate(FlatPtr address) const
+{
+ auto* lib = library_at(address);
+ if (!lib)
+ return {};
+ // FIXME: ELF::Image symlicate() API should return String::empty() if symbol is not found (It currently returns ??)
+ auto symbol = lib->debug_info->elf().symbolicate(address - lib->base_address);
+ return { { lib->name, symbol } };
+}
+
+Optional<DebugInfo::SourcePositionAndAddress> ProcessInspector::get_address_from_source_position(String const& file, size_t line) const
+{
+ Optional<DebugInfo::SourcePositionAndAddress> result;
+ for_each_loaded_library([file, line, &result](auto& lib) {
+ // The loader contains its own definitions for LibC symbols, so we don't want to include it in the search.
+ if (lib.name == "Loader.so")
+ return IterationDecision::Continue;
+
+ auto source_position_and_address = lib.debug_info->get_address_from_source_position(file, line);
+ if (!source_position_and_address.has_value())
+ return IterationDecision::Continue;
+
+ result = source_position_and_address;
+ result.value().address += lib.base_address;
+ return IterationDecision::Break;
+ });
+ return result;
+}
+
+Optional<DebugInfo::SourcePosition> ProcessInspector::get_source_position(FlatPtr address) const
+{
+ auto* lib = library_at(address);
+ if (!lib)
+ return {};
+ return lib->debug_info->get_source_position(address - lib->base_address);
+}
+
+}
diff --git a/Userland/Libraries/LibDebug/ProcessInspector.h b/Userland/Libraries/LibDebug/ProcessInspector.h
new file mode 100644
index 0000000000..fd7731e9d8
--- /dev/null
+++ b/Userland/Libraries/LibDebug/ProcessInspector.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include "LoadedLibrary.h"
+#include <AK/Types.h>
+#include <LibC/sys/arch/i386/regs.h>
+
+namespace Debug {
+
+class ProcessInspector {
+public:
+ virtual ~ProcessInspector() { }
+ virtual bool poke(void* address, FlatPtr data) = 0;
+ virtual Optional<FlatPtr> peek(void* address) const = 0;
+ virtual PtraceRegisters get_registers() const = 0;
+ virtual void set_registers(PtraceRegisters const&) = 0;
+ virtual void for_each_loaded_library(Function<IterationDecision(LoadedLibrary const&)>) const = 0;
+
+ const LoadedLibrary* library_at(FlatPtr address) const;
+ struct SymbolicationResult {
+ String library_name;
+ String symbol;
+ };
+ Optional<SymbolicationResult> symbolicate(FlatPtr address) const;
+ Optional<DebugInfo::SourcePositionAndAddress> get_address_from_source_position(String const& file, size_t line) const;
+ Optional<DebugInfo::SourcePosition> get_source_position(FlatPtr address) const;
+
+protected:
+ ProcessInspector() = default;
+};
+
+};
diff --git a/Userland/Utilities/functrace.cpp b/Userland/Utilities/functrace.cpp
index 2ce14f0682..d81f3bf829 100644
--- a/Userland/Utilities/functrace.cpp
+++ b/Userland/Utilities/functrace.cpp
@@ -70,7 +70,7 @@ static void print_syscall(PtraceRegisters& regs, size_t depth)
static NonnullOwnPtr<HashMap<void*, X86::Instruction>> instrument_code()
{
auto instrumented = make<HashMap<void*, X86::Instruction>>();
- g_debug_session->for_each_loaded_library([&](const Debug::DebugSession::LoadedLibrary& lib) {
+ g_debug_session->for_each_loaded_library([&](const Debug::LoadedLibrary& lib) {
lib.debug_info->elf().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) {
if (section.name() != ".text")
return IterationDecision::Continue;