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:
Gunnar Beutner 2021-08-02 00:07:23 +02:00 committed by Andreas Kling
parent fb099ad38b
commit b81926d933
Notes: sideshowbarker 2024-07-18 07:36:53 +09:00
14 changed files with 110 additions and 29 deletions

View file

@ -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()

View file

@ -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);

View file

@ -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; }

View file

@ -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);

View file

@ -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);
}

View file

@ -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(

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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 });

View file

@ -14,7 +14,7 @@ namespace HackStudio {
struct RegisterData {
String name;
u32 value;
FlatPtr value;
bool changed { false };
};

View file

@ -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);

View file

@ -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);

View file

@ -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
};