Serenity Operating System
1/*
2 * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/DeprecatedFlyString.h>
10#include <AK/Vector.h>
11#include <LibDebug/Dwarf/DwarfTypes.h>
12
13namespace Debug::Dwarf {
14
15class DwarfInfo;
16
17struct [[gnu::packed]] LineProgramUnitHeader32Common {
18 u32 length;
19 u16 version;
20};
21
22struct [[gnu::packed]] LineProgramUnitHeader32V4Ext {
23 u32 header_length;
24 u8 min_instruction_length;
25 u8 max_instruction_length;
26 u8 default_is_stmt;
27 i8 line_base;
28 u8 line_range;
29 u8 opcode_base;
30};
31
32struct [[gnu::packed]] LineProgramUnitHeader32V5Ext {
33 u8 address_size;
34 u8 segment_selector_size;
35 u32 header_length;
36 u8 min_instruction_length;
37 u8 max_instruction_length;
38 u8 default_is_stmt;
39 i8 line_base;
40 u8 line_range;
41 u8 opcode_base;
42};
43
44struct [[gnu::packed]] LineProgramUnitHeader32 {
45 LineProgramUnitHeader32Common common;
46
47 union {
48 LineProgramUnitHeader32V4Ext v4;
49 LineProgramUnitHeader32V5Ext v5;
50 };
51
52 u8 std_opcode_lengths[13];
53
54 size_t header_size() const
55 {
56 return sizeof(common) + ((common.version <= 4) ? sizeof(v4) : sizeof(v5)) + (opcode_base() - 1) * sizeof(std_opcode_lengths[0]);
57 }
58
59 u32 length() const { return common.length; }
60 u16 version() const { return common.version; }
61 u32 header_length() const { return (common.version <= 4) ? v4.header_length : v5.header_length; }
62 u8 min_instruction_length() const { return (common.version <= 4) ? v4.min_instruction_length : v5.min_instruction_length; }
63 u8 default_is_stmt() const { return (common.version <= 4) ? v4.default_is_stmt : v5.default_is_stmt; }
64 i8 line_base() const { return (common.version <= 4) ? v4.line_base : v5.line_base; }
65 u8 line_range() const { return (common.version <= 4) ? v4.line_range : v5.line_range; }
66 u8 opcode_base() const { return (common.version <= 4) ? v4.opcode_base : v5.opcode_base; }
67
68 static ErrorOr<LineProgramUnitHeader32> read_from_stream(Stream& stream)
69 {
70 LineProgramUnitHeader32 header;
71 TRY(stream.read_until_filled(Bytes { &header.common, sizeof(header.common) }));
72 if (header.common.version <= 4)
73 TRY(stream.read_until_filled(Bytes { &header.v4, sizeof(header.v4) }));
74 else
75 TRY(stream.read_until_filled(Bytes { &header.v5, sizeof(header.v5) }));
76 TRY(stream.read_until_filled(Bytes { &header.std_opcode_lengths, min(sizeof(header.std_opcode_lengths), (header.opcode_base() - 1) * sizeof(header.std_opcode_lengths[0])) }));
77 return header;
78 }
79};
80
81enum class ContentType {
82 Path = 1,
83 DirectoryIndex = 2,
84 Timestamp = 3,
85 Size = 4,
86 MD5 = 5,
87 LoUser = 0x2000,
88 HiUser = 0x3fff,
89};
90
91struct PathEntryFormat {
92 ContentType type;
93 AttributeDataForm form;
94};
95
96struct PathEntry {
97 DeprecatedString path;
98 size_t directory_index { 0 };
99};
100
101enum class PathListType {
102 Directories,
103 Filenames,
104};
105
106class LineProgram {
107 AK_MAKE_NONCOPYABLE(LineProgram);
108 AK_MAKE_NONMOVABLE(LineProgram);
109
110public:
111 explicit LineProgram(DwarfInfo& dwarf_info, SeekableStream& stream);
112
113 struct LineInfo {
114 FlatPtr address { 0 };
115 DeprecatedFlyString file;
116 size_t line { 0 };
117 };
118
119 Vector<LineInfo> const& lines() const { return m_lines; }
120
121 struct DirectoryAndFile {
122 DeprecatedFlyString directory;
123 DeprecatedFlyString filename;
124 };
125 DirectoryAndFile get_directory_and_file(size_t file_index) const;
126
127 struct FileEntry {
128 DeprecatedFlyString name;
129 size_t directory_index { 0 };
130 };
131 Vector<FileEntry> const& source_files() const { return m_source_files; }
132
133 bool looks_like_embedded_resource() const;
134
135private:
136 ErrorOr<void> parse_unit_header();
137 ErrorOr<void> parse_source_directories();
138 ErrorOr<void> parse_source_files();
139 ErrorOr<void> run_program();
140
141 void append_to_line_info();
142 void reset_registers();
143
144 ErrorOr<void> handle_extended_opcode();
145 ErrorOr<void> handle_standard_opcode(u8 opcode);
146 void handle_special_opcode(u8 opcode);
147
148 ErrorOr<void> parse_path_entries(Function<void(PathEntry& entry)> callback, PathListType list_type);
149
150 enum StandardOpcodes {
151 Copy = 1,
152 AdvancePc,
153 AdvanceLine,
154 SetFile,
155 SetColumn,
156 NegateStatement,
157 SetBasicBlock,
158 ConstAddPc,
159 FixAdvancePc,
160 SetPrologueEnd,
161 SetEpilogueBegin,
162 SetIsa
163 };
164
165 enum ExtendedOpcodes {
166 EndSequence = 1,
167 SetAddress,
168 DefineFile,
169 SetDiscriminator,
170 };
171
172 static constexpr u16 MIN_DWARF_VERSION = 3;
173 static constexpr u16 MAX_DWARF_VERSION = 5;
174
175 DwarfInfo& m_dwarf_info;
176 SeekableStream& m_stream;
177
178 size_t m_unit_offset { 0 };
179 LineProgramUnitHeader32 m_unit_header {};
180 Vector<DeprecatedString> m_source_directories;
181 Vector<FileEntry> m_source_files;
182
183 // The registers of the "line program" virtual machine
184 FlatPtr m_address { 0 };
185 size_t m_line { 0 };
186 size_t m_file_index { 0 };
187 bool m_is_statement { false };
188 bool m_basic_block { false };
189 bool m_prologue_end { false };
190
191 Vector<LineInfo> m_lines;
192};
193
194}