Serenity Operating System
1/*
2 * Copyright (c) 2020-2021, Itamar S. <itamar8910@gmail.com>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include "DwarfInfo.h"
8#include "AddressRanges.h"
9#include "AttributeValue.h"
10#include "CompilationUnit.h"
11
12#include <AK/ByteReader.h>
13#include <AK/LEB128.h>
14#include <AK/MemoryStream.h>
15#include <LibDebug/DebugInfo.h>
16
17namespace Debug::Dwarf {
18
19DwarfInfo::DwarfInfo(ELF::Image const& elf)
20 : m_elf(elf)
21{
22 m_debug_info_data = section_data(".debug_info"sv);
23 m_abbreviation_data = section_data(".debug_abbrev"sv);
24 m_debug_strings_data = section_data(".debug_str"sv);
25 m_debug_line_data = section_data(".debug_line"sv);
26 m_debug_line_strings_data = section_data(".debug_line_str"sv);
27 m_debug_range_lists_data = section_data(".debug_rnglists"sv);
28 m_debug_str_offsets_data = section_data(".debug_str_offsets"sv);
29 m_debug_addr_data = section_data(".debug_addr"sv);
30 m_debug_ranges_data = section_data(".debug_ranges"sv);
31
32 populate_compilation_units().release_value_but_fixme_should_propagate_errors();
33}
34
35DwarfInfo::~DwarfInfo() = default;
36
37ReadonlyBytes DwarfInfo::section_data(StringView section_name) const
38{
39 auto section = m_elf.lookup_section(section_name);
40 if (!section.has_value())
41 return {};
42 return section->bytes();
43}
44
45ErrorOr<void> DwarfInfo::populate_compilation_units()
46{
47 if (!m_debug_info_data.data())
48 return {};
49
50 FixedMemoryStream debug_info_stream { m_debug_info_data };
51 FixedMemoryStream line_info_stream { m_debug_line_data };
52
53 while (!debug_info_stream.is_eof()) {
54 auto unit_offset = TRY(debug_info_stream.tell());
55
56 auto compilation_unit_header = TRY(debug_info_stream.read_value<CompilationUnitHeader>());
57 VERIFY(compilation_unit_header.common.version <= 5);
58 VERIFY(compilation_unit_header.address_size() == sizeof(FlatPtr));
59
60 u32 length_after_header = compilation_unit_header.length() - (compilation_unit_header.header_size() - offsetof(CompilationUnitHeader, common.version));
61
62 auto line_program = make<LineProgram>(*this, line_info_stream);
63
64 // HACK: Clang generates line programs for embedded resource assembly files, but not compile units.
65 // Meaning that for graphical applications, some line info data would be unread, triggering the assertion below.
66 // As a fix, we don't create compilation units for line programs that come from resource files.
67#if defined(AK_COMPILER_CLANG)
68 if (line_program->looks_like_embedded_resource()) {
69 TRY(debug_info_stream.seek(unit_offset));
70 } else
71#endif
72 {
73 m_compilation_units.append(make<CompilationUnit>(*this, unit_offset, compilation_unit_header, move(line_program)));
74 TRY(debug_info_stream.discard(length_after_header));
75 }
76 }
77
78 VERIFY(line_info_stream.is_eof());
79 return {};
80}
81
82ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value,
83 SeekableStream& debug_info_stream, CompilationUnit const* unit) const
84{
85 AttributeValue value;
86 value.m_form = form;
87 value.m_compilation_unit = unit;
88
89 auto assign_raw_bytes_value = [&](size_t length) -> ErrorOr<void> {
90 value.m_data.as_raw_bytes = { debug_info_data().offset_pointer(TRY(debug_info_stream.tell())), length };
91 TRY(debug_info_stream.discard(length));
92 return {};
93 };
94
95 switch (form) {
96 case AttributeDataForm::StringPointer: {
97 auto offset = TRY(debug_info_stream.read_value<u32>());
98 value.m_type = AttributeValue::Type::String;
99
100 auto strings_data = debug_strings_data();
101 value.m_data.as_string = bit_cast<char const*>(strings_data.offset_pointer(offset));
102 break;
103 }
104 case AttributeDataForm::Data1: {
105 auto data = TRY(debug_info_stream.read_value<u8>());
106 value.m_type = AttributeValue::Type::UnsignedNumber;
107 value.m_data.as_unsigned = data;
108 break;
109 }
110 case AttributeDataForm::Data2: {
111 auto data = TRY(debug_info_stream.read_value<u16>());
112 value.m_type = AttributeValue::Type::UnsignedNumber;
113 value.m_data.as_signed = data;
114 break;
115 }
116 case AttributeDataForm::Addr: {
117 auto address = TRY(debug_info_stream.read_value<FlatPtr>());
118 value.m_type = AttributeValue::Type::Address;
119 value.m_data.as_addr = address;
120 break;
121 }
122 case AttributeDataForm::SData: {
123 i64 data = TRY(debug_info_stream.read_value<LEB128<i64>>());
124 value.m_type = AttributeValue::Type::SignedNumber;
125 value.m_data.as_signed = data;
126 break;
127 }
128 case AttributeDataForm::UData: {
129 u64 data = TRY(debug_info_stream.read_value<LEB128<u64>>());
130 value.m_type = AttributeValue::Type::UnsignedNumber;
131 value.m_data.as_unsigned = data;
132 break;
133 }
134 case AttributeDataForm::SecOffset: {
135 auto data = TRY(debug_info_stream.read_value<u32>());
136 value.m_type = AttributeValue::Type::SecOffset;
137 value.m_data.as_unsigned = data;
138 break;
139 }
140 case AttributeDataForm::Data4: {
141 auto data = TRY(debug_info_stream.read_value<u32>());
142 value.m_type = AttributeValue::Type::UnsignedNumber;
143 value.m_data.as_unsigned = data;
144 break;
145 }
146 case AttributeDataForm::Data8: {
147 auto data = TRY(debug_info_stream.read_value<u64>());
148 value.m_type = AttributeValue::Type::UnsignedNumber;
149 value.m_data.as_unsigned = data;
150 break;
151 }
152 case AttributeDataForm::Data16: {
153 value.m_type = AttributeValue::Type::RawBytes;
154 TRY(assign_raw_bytes_value(16));
155 break;
156 }
157 case AttributeDataForm::Ref4: {
158 auto data = TRY(debug_info_stream.read_value<u32>());
159 value.m_type = AttributeValue::Type::DieReference;
160 VERIFY(unit);
161 value.m_data.as_unsigned = data + unit->offset();
162 break;
163 }
164 case AttributeDataForm::FlagPresent: {
165 value.m_type = AttributeValue::Type::Boolean;
166 value.m_data.as_bool = true;
167 break;
168 }
169 case AttributeDataForm::ExprLoc: {
170 size_t length = TRY(debug_info_stream.read_value<LEB128<size_t>>());
171 value.m_type = AttributeValue::Type::DwarfExpression;
172 TRY(assign_raw_bytes_value(length));
173 break;
174 }
175 case AttributeDataForm::String: {
176 u32 str_offset = TRY(debug_info_stream.tell());
177 value.m_type = AttributeValue::Type::String;
178 value.m_data.as_string = bit_cast<char const*>(debug_info_data().offset_pointer(str_offset));
179 TRY(debug_info_stream.discard(strlen(value.m_data.as_string) + 1));
180 break;
181 }
182 case AttributeDataForm::Block1: {
183 value.m_type = AttributeValue::Type::RawBytes;
184 auto length = TRY(debug_info_stream.read_value<u8>());
185 TRY(assign_raw_bytes_value(length));
186 break;
187 }
188 case AttributeDataForm::Block2: {
189 value.m_type = AttributeValue::Type::RawBytes;
190 auto length = TRY(debug_info_stream.read_value<u16>());
191 TRY(assign_raw_bytes_value(length));
192 break;
193 }
194 case AttributeDataForm::Block4: {
195 value.m_type = AttributeValue::Type::RawBytes;
196 auto length = TRY(debug_info_stream.read_value<u32>());
197 TRY(assign_raw_bytes_value(length));
198 break;
199 }
200 case AttributeDataForm::Block: {
201 value.m_type = AttributeValue::Type::RawBytes;
202 size_t length = TRY(debug_info_stream.read_value<LEB128<size_t>>());
203 TRY(assign_raw_bytes_value(length));
204 break;
205 }
206 case AttributeDataForm::LineStrP: {
207 auto offset = TRY(debug_info_stream.read_value<u32>());
208 value.m_type = AttributeValue::Type::String;
209
210 auto strings_data = debug_line_strings_data();
211 value.m_data.as_string = bit_cast<char const*>(strings_data.offset_pointer(offset));
212 break;
213 }
214 case AttributeDataForm::ImplicitConst: {
215 /* Value is part of the abbreviation record. */
216 value.m_type = AttributeValue::Type::SignedNumber;
217 value.m_data.as_signed = implicit_const_value;
218 break;
219 }
220 case AttributeDataForm::StrX1: {
221 auto index = TRY(debug_info_stream.read_value<u8>());
222 value.m_type = AttributeValue::Type::String;
223 value.m_data.as_unsigned = index;
224 break;
225 }
226 case AttributeDataForm::StrX2: {
227 auto index = TRY(debug_info_stream.read_value<u16>());
228 value.m_type = AttributeValue::Type::String;
229 value.m_data.as_unsigned = index;
230 break;
231 }
232 case AttributeDataForm::StrX4: {
233 auto index = TRY(debug_info_stream.read_value<u32>());
234 value.m_type = AttributeValue::Type::String;
235 value.m_data.as_unsigned = index;
236 break;
237 }
238 case AttributeDataForm::StrX: {
239 size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
240 value.m_type = AttributeValue::Type::String;
241 value.m_data.as_unsigned = index;
242 break;
243 }
244 case AttributeDataForm::AddrX1: {
245 auto index = TRY(debug_info_stream.read_value<u8>());
246 value.m_type = AttributeValue::Type::Address;
247 value.m_data.as_unsigned = index;
248 break;
249 }
250 case AttributeDataForm::AddrX2: {
251 auto index = TRY(debug_info_stream.read_value<u16>());
252 value.m_type = AttributeValue::Type::Address;
253 value.m_data.as_unsigned = index;
254 break;
255 }
256 case AttributeDataForm::AddrX4: {
257 auto index = TRY(debug_info_stream.read_value<u32>());
258 value.m_type = AttributeValue::Type::Address;
259 value.m_data.as_unsigned = index;
260 break;
261 }
262 case AttributeDataForm::AddrX: {
263 size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
264 value.m_type = AttributeValue::Type::Address;
265 value.m_data.as_unsigned = index;
266 break;
267 }
268 case AttributeDataForm::RngListX: {
269 size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
270 value.m_type = AttributeValue::Type::UnsignedNumber;
271 value.m_data.as_unsigned = index;
272 break;
273 }
274 default:
275 dbgln("Unimplemented AttributeDataForm: {}", to_underlying(form));
276 VERIFY_NOT_REACHED();
277 }
278 return value;
279}
280
281ErrorOr<void> DwarfInfo::build_cached_dies() const
282{
283 auto insert_to_cache = [this](DIE const& die, DIERange const& range) {
284 m_cached_dies_by_range.insert(range.start_address, DIEAndRange { die, range });
285 m_cached_dies_by_offset.insert(die.offset(), die);
286 };
287 auto get_ranges_of_die = [this](DIE const& die) -> ErrorOr<Vector<DIERange>> {
288 auto ranges = TRY(die.get_attribute(Attribute::Ranges));
289 if (ranges.has_value()) {
290 size_t offset;
291 if (ranges->form() == AttributeDataForm::SecOffset) {
292 offset = ranges->as_unsigned();
293 } else {
294 auto index = ranges->as_unsigned();
295 auto base = TRY(die.compilation_unit().range_lists_base());
296 // FIXME: This assumes that the format is DWARf32
297 auto offsets = debug_range_lists_data().slice(base);
298 offset = ByteReader::load32(offsets.offset_pointer(index * sizeof(u32))) + base;
299 }
300
301 Vector<DIERange> entries;
302 if (die.compilation_unit().dwarf_version() == 5) {
303 auto range_lists_stream = TRY(try_make<FixedMemoryStream>(debug_range_lists_data()));
304 TRY(range_lists_stream->seek(offset));
305 AddressRangesV5 address_ranges(move(range_lists_stream), die.compilation_unit());
306 TRY(address_ranges.for_each_range([&entries](auto range) {
307 entries.empend(range.start, range.end);
308 }));
309 } else {
310 auto ranges_stream = TRY(try_make<FixedMemoryStream>(debug_ranges_data()));
311 TRY(ranges_stream->seek(offset));
312 AddressRangesV4 address_ranges(move(ranges_stream), die.compilation_unit());
313 TRY(address_ranges.for_each_range([&entries](auto range) {
314 entries.empend(range.start, range.end);
315 }));
316 }
317 return entries;
318 }
319
320 auto start = TRY(die.get_attribute(Attribute::LowPc));
321 auto end = TRY(die.get_attribute(Attribute::HighPc));
322
323 if (!start.has_value() || !end.has_value())
324 return Vector<DIERange> {};
325
326 VERIFY(start->type() == Dwarf::AttributeValue::Type::Address);
327
328 // DW_AT_high_pc attribute can have different meanings depending on the attribute form.
329 // (Dwarf version 5, section 2.17.2).
330
331 uint32_t range_end = 0;
332 if (end->form() == Dwarf::AttributeDataForm::Addr)
333 range_end = TRY(end->as_addr());
334 else
335 range_end = TRY(start->as_addr()) + end->as_unsigned();
336
337 return Vector<DIERange> { DIERange { TRY(start.value().as_addr()), range_end } };
338 };
339
340 // If we simply use a lambda, type deduction fails because it's used recursively.
341 Function<ErrorOr<void>(DIE const& die)> insert_to_cache_recursively;
342 insert_to_cache_recursively = [&](DIE const& die) -> ErrorOr<void> {
343 if (die.offset() == 0 || die.parent_offset().has_value()) {
344 auto ranges = TRY(get_ranges_of_die(die));
345 for (auto& range : ranges) {
346 insert_to_cache(die, range);
347 }
348 }
349 TRY(die.for_each_child([&](DIE const& child) -> ErrorOr<void> {
350 if (!child.is_null()) {
351 TRY(insert_to_cache_recursively(child));
352 }
353 return {};
354 }));
355 return {};
356 };
357
358 TRY(for_each_compilation_unit([&](CompilationUnit const& compilation_unit) -> ErrorOr<void> {
359 TRY(insert_to_cache_recursively(compilation_unit.root_die()));
360 return {};
361 }));
362
363 m_built_cached_dies = true;
364 return {};
365}
366
367ErrorOr<Optional<DIE>> DwarfInfo::get_die_at_address(FlatPtr address) const
368{
369 if (!m_built_cached_dies)
370 TRY(build_cached_dies());
371
372 auto iter = m_cached_dies_by_range.find_largest_not_above_iterator(address);
373 while (!iter.is_end() && !iter.is_begin() && iter->range.end_address < address) {
374 --iter;
375 }
376
377 if (iter.is_end())
378 return Optional<DIE> {};
379
380 if (iter->range.start_address > address || iter->range.end_address < address) {
381 return Optional<DIE> {};
382 }
383
384 return iter->die;
385}
386
387ErrorOr<Optional<DIE>> DwarfInfo::get_cached_die_at_offset(FlatPtr offset) const
388{
389 if (!m_built_cached_dies)
390 TRY(build_cached_dies());
391
392 auto* die = m_cached_dies_by_offset.find(offset);
393 if (!die)
394 return Optional<DIE> {};
395 return *die;
396}
397
398}