mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
HackStudio: Enable building HackStudio on x86_64
This implements bits and pieces to get the debugging functionality to build. No testing has been done to check whether it actually works because GCC doesn't currently work.
This commit is contained in:
parent
fb099ad38b
commit
b81926d933
Notes:
sideshowbarker
2024-07-18 07:36:53 +09:00
Author: https://github.com/gunnarbeutner Commit: https://github.com/SerenityOS/serenity/commit/b81926d933b Pull-request: https://github.com/SerenityOS/serenity/pull/9166
14 changed files with 110 additions and 29 deletions
|
@ -1,8 +1,8 @@
|
|||
add_subdirectory(Inspector)
|
||||
add_subdirectory(Playground)
|
||||
add_subdirectory(Profiler)
|
||||
add_subdirectory(HackStudio)
|
||||
|
||||
if("${SERENITY_ARCH}" STREQUAL "i686")
|
||||
add_subdirectory(HackStudio)
|
||||
add_subdirectory(UserspaceEmulator)
|
||||
endif()
|
||||
|
|
|
@ -33,11 +33,11 @@ GUI::ModelIndex BacktraceModel::index(int row, int column, const GUI::ModelIndex
|
|||
|
||||
Vector<BacktraceModel::FrameInfo> BacktraceModel::create_backtrace(const Debug::DebugSession& debug_session, const PtraceRegisters& regs)
|
||||
{
|
||||
u32 current_ebp = regs.ebp;
|
||||
u32 current_instruction = regs.eip;
|
||||
FlatPtr current_ebp = regs.bp();
|
||||
FlatPtr current_instruction = regs.ip();
|
||||
Vector<BacktraceModel::FrameInfo> frames;
|
||||
do {
|
||||
auto lib = debug_session.library_at(regs.eip);
|
||||
auto lib = debug_session.library_at(regs.ip());
|
||||
if (!lib)
|
||||
continue;
|
||||
String name = lib->debug_info->name_of_containing_function(current_instruction - lib->base_address);
|
||||
|
|
|
@ -38,8 +38,8 @@ public:
|
|||
|
||||
struct FrameInfo {
|
||||
String function_name;
|
||||
u32 instruction_address;
|
||||
u32 frame_base;
|
||||
FlatPtr instruction_address;
|
||||
FlatPtr frame_base;
|
||||
};
|
||||
|
||||
const Vector<FrameInfo>& frames() const { return m_frames; }
|
||||
|
|
|
@ -77,8 +77,8 @@ DebugInfoWidget::DebugInfoWidget()
|
|||
// We currently only reconstruct eip & ebp. Ideally would also reconstruct the other registers somehow.
|
||||
// (Other registers may be needed to get the values of variables who are not stored on the stack)
|
||||
PtraceRegisters frame_regs {};
|
||||
frame_regs.eip = model.frames()[index.row()].instruction_address;
|
||||
frame_regs.ebp = model.frames()[index.row()].frame_base;
|
||||
frame_regs.set_ip(model.frames()[index.row()].instruction_address);
|
||||
frame_regs.set_bp(model.frames()[index.row()].frame_base);
|
||||
|
||||
m_variables_view->set_model(VariablesModel::create(frame_regs));
|
||||
};
|
||||
|
@ -108,7 +108,7 @@ RefPtr<GUI::Menu> DebugInfoWidget::get_context_menu_for_variable(const GUI::Mode
|
|||
}));
|
||||
}
|
||||
|
||||
auto variable_address = (u32*)variable->location_data.address;
|
||||
auto variable_address = (FlatPtr*)variable->location_data.address;
|
||||
if (Debugger::the().session()->watchpoint_exists(variable_address)) {
|
||||
context_menu->add_action(GUI::Action::create("Remove watchpoint", [variable_address](auto&) {
|
||||
Debugger::the().session()->remove_watchpoint(variable_address);
|
||||
|
|
|
@ -87,7 +87,7 @@ bool Debugger::set_execution_position(const String& file, size_t line)
|
|||
if (!address.has_value())
|
||||
return false;
|
||||
auto registers = session->get_registers();
|
||||
registers.eip = address.value().address;
|
||||
registers.set_ip(address.value().address);
|
||||
session->set_registers(registers);
|
||||
return true;
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ int Debugger::debugger_loop()
|
|||
VERIFY(optional_regs.has_value());
|
||||
const PtraceRegisters& regs = optional_regs.value();
|
||||
|
||||
auto source_position = m_debug_session->get_source_position(regs.eip);
|
||||
auto source_position = m_debug_session->get_source_position(regs.ip());
|
||||
if (!source_position.has_value())
|
||||
return Debug::DebugSession::DebugDecision::SingleStep;
|
||||
|
||||
|
@ -232,7 +232,7 @@ void Debugger::DebuggingState::clear_temporary_breakpoints()
|
|||
{
|
||||
m_addresses_of_temporary_breakpoints.clear();
|
||||
}
|
||||
void Debugger::DebuggingState::add_temporary_breakpoint(u32 address)
|
||||
void Debugger::DebuggingState::add_temporary_breakpoint(FlatPtr address)
|
||||
{
|
||||
m_addresses_of_temporary_breakpoints.append(address);
|
||||
}
|
||||
|
@ -249,12 +249,12 @@ void Debugger::do_step_over(const PtraceRegisters& regs)
|
|||
{
|
||||
// To step over, we insert a temporary breakpoint at each line in the current function,
|
||||
// as well as at the current function's return point, and continue execution.
|
||||
auto lib = m_debug_session->library_at(regs.eip);
|
||||
auto lib = m_debug_session->library_at(regs.ip());
|
||||
if (!lib)
|
||||
return;
|
||||
auto current_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address);
|
||||
auto current_function = lib->debug_info->get_containing_function(regs.ip() - lib->base_address);
|
||||
if (!current_function.has_value()) {
|
||||
dbgln("cannot perform step_over, failed to find containing function of: {:p}", regs.eip);
|
||||
dbgln("cannot perform step_over, failed to find containing function of: {:p}", regs.ip());
|
||||
return;
|
||||
}
|
||||
VERIFY(current_function.has_value());
|
||||
|
@ -267,9 +267,9 @@ void Debugger::do_step_over(const PtraceRegisters& regs)
|
|||
|
||||
void Debugger::insert_temporary_breakpoint_at_return_address(const PtraceRegisters& regs)
|
||||
{
|
||||
auto frame_info = Debug::StackFrameUtils::get_info(*m_debug_session, regs.ebp);
|
||||
auto frame_info = Debug::StackFrameUtils::get_info(*m_debug_session, regs.bp());
|
||||
VERIFY(frame_info.has_value());
|
||||
u32 return_address = frame_info.value().return_address;
|
||||
FlatPtr return_address = frame_info.value().return_address;
|
||||
insert_temporary_breakpoint(return_address);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,13 +78,13 @@ private:
|
|||
|
||||
bool should_stop_single_stepping(const Debug::DebugInfo::SourcePosition& current_source_position) const;
|
||||
void clear_temporary_breakpoints();
|
||||
void add_temporary_breakpoint(u32 address);
|
||||
const Vector<u32>& temporary_breakpoints() const { return m_addresses_of_temporary_breakpoints; }
|
||||
void add_temporary_breakpoint(FlatPtr address);
|
||||
const Vector<FlatPtr>& temporary_breakpoints() const { return m_addresses_of_temporary_breakpoints; }
|
||||
|
||||
private:
|
||||
State m_state { Normal };
|
||||
Optional<Debug::DebugInfo::SourcePosition> m_original_source_position; // The source position at which we started the current single step
|
||||
Vector<u32> m_addresses_of_temporary_breakpoints;
|
||||
Vector<FlatPtr> m_addresses_of_temporary_breakpoints;
|
||||
};
|
||||
|
||||
explicit Debugger(
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace HackStudio {
|
|||
DebuggerGlobalJSObject::DebuggerGlobalJSObject()
|
||||
{
|
||||
auto regs = Debugger::the().session()->get_registers();
|
||||
auto lib = Debugger::the().session()->library_at(regs.eip);
|
||||
auto lib = Debugger::the().session()->library_at(regs.ip());
|
||||
if (!lib)
|
||||
return;
|
||||
m_variables = lib->debug_info->get_variables_in_current_scope(regs);
|
||||
|
|
|
@ -18,10 +18,10 @@ namespace HackStudio {
|
|||
|
||||
DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, const PtraceRegisters& regs)
|
||||
{
|
||||
auto lib = debug_session.library_at(regs.eip);
|
||||
auto lib = debug_session.library_at(regs.ip());
|
||||
if (!lib)
|
||||
return;
|
||||
auto containing_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address);
|
||||
auto containing_function = lib->debug_info->get_containing_function(regs.ip() - lib->base_address);
|
||||
if (!containing_function.has_value()) {
|
||||
dbgln("Cannot disassemble as the containing function was not found.");
|
||||
return;
|
||||
|
|
|
@ -44,10 +44,10 @@ void DisassemblyWidget::update_state(const Debug::DebugSession& debug_session, c
|
|||
m_disassembly_view->set_model(DisassemblyModel::create(debug_session, regs));
|
||||
|
||||
if (m_disassembly_view->model()->row_count() > 0) {
|
||||
auto lib = debug_session.library_at(regs.eip);
|
||||
auto lib = debug_session.library_at(regs.ip());
|
||||
if (!lib)
|
||||
return;
|
||||
auto containing_function = lib->debug_info->get_containing_function(regs.eip - lib->base_address);
|
||||
auto containing_function = lib->debug_info->get_containing_function(regs.ip() - lib->base_address);
|
||||
if (containing_function.has_value())
|
||||
m_function_name_label->set_text(containing_function.value().name);
|
||||
else
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace HackStudio {
|
|||
RegistersModel::RegistersModel(const PtraceRegisters& regs)
|
||||
: m_raw_registers(regs)
|
||||
{
|
||||
#if ARCH(I386)
|
||||
m_registers.append({ "eax", regs.eax });
|
||||
m_registers.append({ "ebx", regs.ebx });
|
||||
m_registers.append({ "ecx", regs.ecx });
|
||||
|
@ -21,6 +22,27 @@ RegistersModel::RegistersModel(const PtraceRegisters& regs)
|
|||
m_registers.append({ "edi", regs.edi });
|
||||
m_registers.append({ "eip", regs.eip });
|
||||
m_registers.append({ "eflags", regs.eflags });
|
||||
#else
|
||||
m_registers.append({ "rax", regs.rax });
|
||||
m_registers.append({ "rbx", regs.rbx });
|
||||
m_registers.append({ "rcx", regs.rcx });
|
||||
m_registers.append({ "rdx", regs.rdx });
|
||||
m_registers.append({ "rsp", regs.rsp });
|
||||
m_registers.append({ "rbp", regs.rbp });
|
||||
m_registers.append({ "rsi", regs.rsi });
|
||||
m_registers.append({ "rdi", regs.rdi });
|
||||
m_registers.append({ "rip", regs.rip });
|
||||
m_registers.append({ "r8", regs.r8 });
|
||||
m_registers.append({ "r9", regs.r9 });
|
||||
m_registers.append({ "r10", regs.r10 });
|
||||
m_registers.append({ "r11", regs.r11 });
|
||||
m_registers.append({ "r12", regs.r12 });
|
||||
m_registers.append({ "r13", regs.r13 });
|
||||
m_registers.append({ "r14", regs.r14 });
|
||||
m_registers.append({ "r15", regs.r15 });
|
||||
m_registers.append({ "rflags", regs.rflags });
|
||||
#endif
|
||||
|
||||
m_registers.append({ "cs", regs.cs });
|
||||
m_registers.append({ "ss", regs.ss });
|
||||
m_registers.append({ "ds", regs.ds });
|
||||
|
@ -32,6 +54,7 @@ RegistersModel::RegistersModel(const PtraceRegisters& regs)
|
|||
RegistersModel::RegistersModel(const PtraceRegisters& current_regs, const PtraceRegisters& previous_regs)
|
||||
: m_raw_registers(current_regs)
|
||||
{
|
||||
#if ARCH(I386)
|
||||
m_registers.append({ "eax", current_regs.eax, current_regs.eax != previous_regs.eax });
|
||||
m_registers.append({ "ebx", current_regs.ebx, current_regs.ebx != previous_regs.ebx });
|
||||
m_registers.append({ "ecx", current_regs.ecx, current_regs.ecx != previous_regs.ecx });
|
||||
|
@ -42,6 +65,26 @@ RegistersModel::RegistersModel(const PtraceRegisters& current_regs, const Ptrace
|
|||
m_registers.append({ "edi", current_regs.edi, current_regs.edi != previous_regs.edi });
|
||||
m_registers.append({ "eip", current_regs.eip, current_regs.eip != previous_regs.eip });
|
||||
m_registers.append({ "eflags", current_regs.eflags, current_regs.eflags != previous_regs.eflags });
|
||||
#else
|
||||
m_registers.append({ "rax", current_regs.rax, current_regs.rax != previous_regs.rax });
|
||||
m_registers.append({ "rbx", current_regs.rbx, current_regs.rbx != previous_regs.rbx });
|
||||
m_registers.append({ "rcx", current_regs.rcx, current_regs.rcx != previous_regs.rcx });
|
||||
m_registers.append({ "rdx", current_regs.rdx, current_regs.rdx != previous_regs.rdx });
|
||||
m_registers.append({ "rsp", current_regs.rsp, current_regs.rsp != previous_regs.rsp });
|
||||
m_registers.append({ "rbp", current_regs.rbp, current_regs.rbp != previous_regs.rbp });
|
||||
m_registers.append({ "rsi", current_regs.rsi, current_regs.rsi != previous_regs.rsi });
|
||||
m_registers.append({ "rdi", current_regs.rdi, current_regs.rdi != previous_regs.rdi });
|
||||
m_registers.append({ "rip", current_regs.rip, current_regs.rip != previous_regs.rip });
|
||||
m_registers.append({ "r8", current_regs.r8, current_regs.r8 != previous_regs.r8 });
|
||||
m_registers.append({ "r9", current_regs.r9, current_regs.r9 != previous_regs.r9 });
|
||||
m_registers.append({ "r10", current_regs.r10, current_regs.r10 != previous_regs.r10 });
|
||||
m_registers.append({ "r11", current_regs.r11, current_regs.r11 != previous_regs.r11 });
|
||||
m_registers.append({ "r12", current_regs.r12, current_regs.r12 != previous_regs.r12 });
|
||||
m_registers.append({ "r13", current_regs.r13, current_regs.r13 != previous_regs.r13 });
|
||||
m_registers.append({ "r14", current_regs.r14, current_regs.r14 != previous_regs.r14 });
|
||||
m_registers.append({ "r15", current_regs.r15, current_regs.r15 != previous_regs.r15 });
|
||||
m_registers.append({ "rflags", current_regs.rflags, current_regs.rflags != previous_regs.rflags });
|
||||
#endif
|
||||
m_registers.append({ "cs", current_regs.cs, current_regs.cs != previous_regs.cs });
|
||||
m_registers.append({ "ss", current_regs.ss, current_regs.ss != previous_regs.ss });
|
||||
m_registers.append({ "ds", current_regs.ds, current_regs.ds != previous_regs.ds });
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace HackStudio {
|
|||
|
||||
struct RegisterData {
|
||||
String name;
|
||||
u32 value;
|
||||
FlatPtr value;
|
||||
bool changed { false };
|
||||
};
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ void VariablesModel::update()
|
|||
|
||||
RefPtr<VariablesModel> VariablesModel::create(const PtraceRegisters& regs)
|
||||
{
|
||||
auto lib = Debugger::the().session()->library_at(regs.eip);
|
||||
auto lib = Debugger::the().session()->library_at(regs.ip());
|
||||
if (!lib)
|
||||
return nullptr;
|
||||
auto variables = lib->debug_info->get_variables_in_current_scope(regs);
|
||||
|
|
|
@ -684,9 +684,9 @@ void HackStudioWidget::initialize_debugger()
|
|||
[this](const PtraceRegisters& regs) {
|
||||
VERIFY(Debugger::the().session());
|
||||
const auto& debug_session = *Debugger::the().session();
|
||||
auto source_position = debug_session.get_source_position(regs.eip);
|
||||
auto source_position = debug_session.get_source_position(regs.ip());
|
||||
if (!source_position.has_value()) {
|
||||
dbgln("Could not find source position for address: {:p}", regs.eip);
|
||||
dbgln("Could not find source position for address: {:p}", regs.ip());
|
||||
return Debugger::HasControlPassedToUser::No;
|
||||
}
|
||||
dbgln("Debugger stopped at source position: {}:{}", source_position.value().file_path, source_position.value().line_number);
|
||||
|
|
|
@ -46,4 +46,42 @@ struct [[gnu::packed]] PtraceRegisters {
|
|||
u32 es;
|
||||
u32 fs;
|
||||
u32 gs;
|
||||
|
||||
#ifdef __cplusplus
|
||||
FlatPtr ip() const
|
||||
{
|
||||
# if ARCH(I386)
|
||||
return eip;
|
||||
# else
|
||||
return rip;
|
||||
# endif
|
||||
}
|
||||
|
||||
void set_ip(FlatPtr ip)
|
||||
{
|
||||
# if ARCH(I386)
|
||||
eip = ip;
|
||||
# else
|
||||
rip = ip;
|
||||
# endif
|
||||
}
|
||||
|
||||
FlatPtr bp() const
|
||||
{
|
||||
# if ARCH(I386)
|
||||
return ebp;
|
||||
# else
|
||||
return rbp;
|
||||
# endif
|
||||
}
|
||||
|
||||
void set_bp(FlatPtr bp)
|
||||
{
|
||||
# if ARCH(I386)
|
||||
ebp = bp;
|
||||
# else
|
||||
rbp = bp;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue