Serenity Operating System
1/*
2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "BacktraceModel.h"
8#include "Debugger.h"
9#include <LibDebug/StackFrameUtils.h>
10
11namespace HackStudio {
12
13NonnullRefPtr<BacktraceModel> BacktraceModel::create(Debug::ProcessInspector const& inspector, PtraceRegisters const& regs)
14{
15 return adopt_ref(*new BacktraceModel(create_backtrace(inspector, regs)));
16}
17
18GUI::Variant BacktraceModel::data(const GUI::ModelIndex& index, GUI::ModelRole role) const
19{
20 if (role == GUI::ModelRole::Display) {
21 auto& frame = m_frames.at(index.row());
22 return frame.function_name;
23 }
24 return {};
25}
26
27GUI::ModelIndex BacktraceModel::index(int row, int column, const GUI::ModelIndex&) const
28{
29 if (row < 0 || row >= static_cast<int>(m_frames.size()))
30 return {};
31 return create_index(row, column, &m_frames.at(row));
32}
33
34Vector<BacktraceModel::FrameInfo> BacktraceModel::create_backtrace(Debug::ProcessInspector const& inspector, PtraceRegisters const& regs)
35{
36 FlatPtr current_ebp = regs.bp();
37 FlatPtr current_instruction = regs.ip();
38 Vector<BacktraceModel::FrameInfo> frames;
39 size_t frame_index = 0;
40 do {
41 auto lib = inspector.library_at(current_instruction);
42 if (!lib)
43 continue;
44
45 // After the first frame, current_instruction holds the return address from the function call.
46 // We need to go back to the 'call' instruction to get accurate source position information.
47 if (frame_index > 0)
48 --current_instruction;
49 DeprecatedString name = lib->debug_info->elf().symbolicate(current_instruction - lib->base_address);
50 if (name.is_null()) {
51 dbgln("BacktraceModel: couldn't find containing function for address: {:p} (library={})", current_instruction, lib->name);
52 name = "<missing>";
53 }
54
55 auto source_position = lib->debug_info->get_source_position(current_instruction - lib->base_address);
56
57 frames.append({ name, current_instruction, current_ebp, source_position });
58 auto frame_info = Debug::StackFrameUtils::get_info(inspector, current_ebp);
59 VERIFY(frame_info.has_value());
60 current_instruction = frame_info.value().return_address;
61 current_ebp = frame_info.value().next_ebp;
62 ++frame_index;
63 } while (current_ebp && current_instruction);
64 return frames;
65}
66
67}