mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 10:22:05 -05:00
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:
parent
310063fed8
commit
7eac9fe10e
4 changed files with 69 additions and 32 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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(debug_session, regs);
|
||||
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";
|
||||
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";
|
||||
Core::EventLoop::main().post_event(*g_window, make<Core::DeferredInvocationEvent>([&](auto&) {
|
||||
debug_info_widget.program_stopped();
|
||||
hide_action_tabs();
|
||||
Core::EventLoop::main().post_event(*g_window, make<Core::DeferredInvocationEvent>([=](auto&) {
|
||||
GUI::MessageBox::show(g_window, "Program Exited", "Debugger", GUI::MessageBox::Type::Information);
|
||||
}));
|
||||
Core::EventLoop::wake();
|
||||
|
|
|
@ -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 {};
|
||||
|
|
Loading…
Add table
Reference in a new issue