HackStudio: Support debugging library code

We can now step into library code in the debugger.

Since we now need the whole source code of our libraries
(and not just the headers), we clone the whole serenity git repo into
/usr/share/serenity.
This commit is contained in:
Itamar 2020-08-15 10:58:16 +03:00 committed by Andreas Kling
parent 310063fed8
commit 7eac9fe10e
4 changed files with 69 additions and 32 deletions

View file

@ -57,12 +57,12 @@ Vector<BacktraceModel::FrameInfo> BacktraceModel::create_backtrace(const DebugSe
String name = debug_session.debug_info().name_of_containing_function(current_instruction);
if (name.is_null()) {
dbg() << "BacktraceModel: couldn't find containing function for address: " << (void*)current_instruction;
break;
name = "<missing>";
}
frames.append({ name, current_instruction, current_ebp });
current_instruction = Debugger::the().session()->peek(reinterpret_cast<u32*>(current_ebp + 4)).value();
current_ebp = Debugger::the().session()->peek(reinterpret_cast<u32*>(current_ebp)).value();
} while (current_ebp);
} while (current_ebp && current_instruction);
return frames;
}

View file

@ -96,7 +96,12 @@ void DebugInfoWidget::update_state(const DebugSession& debug_session, const Ptra
{
m_variables_view->set_model(VariablesModel::create(regs));
m_backtrace_view->set_model(BacktraceModel::create(debug_session, regs));
m_backtrace_view->selection().set(m_backtrace_view->model()->index(0));
auto selected_index = m_backtrace_view->model()->index(0);
if (!selected_index.is_valid()) {
dbg() << "Warning: DebugInfoWidget: backtrace selected index is invalid";
return;
}
m_backtrace_view->selection().set(selected_index);
}
void DebugInfoWidget::program_stopped()

View file

@ -119,7 +119,13 @@ static void set_edit_mode(EditMode mode)
}
}
static EditorWrapper& current_editor_wrapper()
static void build(TerminalWrapper&);
static void run(TerminalWrapper&);
void open_project(String);
void open_file(const String&);
bool make_is_available();
EditorWrapper& current_editor_wrapper()
{
ASSERT(g_current_editor_wrapper);
return *g_current_editor_wrapper;
@ -130,15 +136,30 @@ GUI::TextEditor& current_editor()
return current_editor_wrapper().editor();
}
static NonnullRefPtr<EditorWrapper> get_editor_of_file(const String& file)
static String get_full_path_of_serenity_source(const String& file)
{
for (auto& wrapper : g_all_editor_wrappers) {
String wrapper_file = wrapper.filename_label().text();
if (wrapper_file == file || String::format("./%s", wrapper_file.characters()) == file) {
return wrapper;
}
auto path_parts = LexicalPath(file).parts();
ASSERT(path_parts[0] == "..");
path_parts.remove(0);
StringBuilder relative_path_builder;
relative_path_builder.join("/", path_parts);
constexpr char SERENITY_LIBS_PREFIX[] = "/usr/src/serenity";
LexicalPath serenity_sources_base(SERENITY_LIBS_PREFIX);
return String::format("%s/%s", serenity_sources_base.string().characters(), relative_path_builder.to_string().characters());
}
NonnullRefPtr<EditorWrapper> get_editor_of_file(const String& file)
{
String file_path = file;
// TODO: We can probably do a more specific condition here, something like
// "if (file.starts_with("../Libraries/") || file.starts_with("../AK/"))"
if (file.starts_with("../")) {
file_path = get_full_path_of_serenity_source(file);
}
ASSERT_NOT_REACHED();
open_file(file_path);
return current_editor_wrapper();
}
static String get_project_executable_path()
@ -148,12 +169,6 @@ static String get_project_executable_path()
return g_project->path().substring(0, g_project->path().index_of(".").value());
}
static void build(TerminalWrapper&);
static void run(TerminalWrapper&);
void open_project(String);
void open_file(const String&);
bool make_is_available();
int main(int argc, char** argv)
{
if (pledge("stdio tty accept rpath cpath wpath shared_buffer proc exec unix fattr thread", nullptr) < 0) {
@ -620,27 +635,38 @@ int main(int argc, char** argv)
dbg() << "Could not find source position for address: " << (void*)regs.eip;
return Debugger::HasControlPassedToUser::No;
}
current_editor_in_execution = get_editor_of_file(source_position.value().file_path);
current_editor_in_execution->editor().set_execution_position(source_position.value().line_number - 1);
debug_info_widget.update_state(debug_session, regs);
continue_action->set_enabled(true);
single_step_action->set_enabled(true);
reveal_action_tab(debug_info_widget);
Core::EventLoop::main().post_event(
*g_window,
make<Core::DeferredInvocationEvent>(
[&, source_position](auto&) {
current_editor_in_execution = get_editor_of_file(source_position.value().file_path);
current_editor_in_execution->editor().set_execution_position(source_position.value().line_number - 1);
debug_info_widget.update_state(*Debugger::the().session(), regs);
continue_action->set_enabled(true);
single_step_action->set_enabled(true);
reveal_action_tab(debug_info_widget);
}));
Core::EventLoop::wake();
return Debugger::HasControlPassedToUser::Yes;
},
[&]() {
dbg() << "Program continued";
continue_action->set_enabled(false);
single_step_action->set_enabled(false);
if (current_editor_in_execution) {
current_editor_in_execution->editor().clear_execution_position();
}
Core::EventLoop::main().post_event(*g_window, make<Core::DeferredInvocationEvent>([&](auto&) {
continue_action->set_enabled(false);
single_step_action->set_enabled(false);
if (current_editor_in_execution) {
current_editor_in_execution->editor().clear_execution_position();
}
}));
Core::EventLoop::wake();
},
[&]() {
dbg() << "Program exited";
debug_info_widget.program_stopped();
hide_action_tabs();
Core::EventLoop::main().post_event(*g_window, make<Core::DeferredInvocationEvent>([=](auto&) {
Core::EventLoop::main().post_event(*g_window, make<Core::DeferredInvocationEvent>([&](auto&) {
debug_info_widget.program_stopped();
hide_action_tabs();
GUI::MessageBox::show(g_window, "Program Exited", "Debugger", GUI::MessageBox::Type::Information);
}));
Core::EventLoop::wake();

View file

@ -146,8 +146,14 @@ Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(u32 target_ad
Optional<u32> DebugInfo::get_instruction_from_source(const String& file, size_t line) const
{
String file_path = file;
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());
}
for (const auto& line_entry : m_sorted_lines) {
if (line_entry.file == file && line_entry.line == line)
if (line_entry.file == file_path && line_entry.line == line)
return Optional<u32>(line_entry.address);
}
return {};