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 "CompilationUnit.h"
8#include <AK/ByteReader.h>
9#include <LibDebug/Dwarf/DIE.h>
10#include <LibDebug/Dwarf/DwarfInfo.h>
11#include <LibDebug/Dwarf/LineProgram.h>
12
13namespace Debug::Dwarf {
14
15CompilationUnit::CompilationUnit(DwarfInfo const& dwarf_info, u32 offset, CompilationUnitHeader const& header, NonnullOwnPtr<LineProgram>&& line_program)
16 : m_dwarf_info(dwarf_info)
17 , m_offset(offset)
18 , m_header(header)
19 , m_abbreviations(dwarf_info, header.abbrev_offset())
20 , m_line_program(move(line_program))
21{
22 VERIFY(header.version() < 5 || header.unit_type() == CompilationUnitType::Full);
23}
24
25CompilationUnit::~CompilationUnit() = default;
26
27DIE CompilationUnit::root_die() const
28{
29 return DIE(*this, m_offset + m_header.header_size());
30}
31
32DIE CompilationUnit::get_die_at_offset(u32 die_offset) const
33{
34 VERIFY(die_offset >= offset() && die_offset < offset() + size());
35 return DIE(*this, die_offset);
36}
37
38LineProgram const& CompilationUnit::line_program() const
39{
40 return *m_line_program;
41}
42
43ErrorOr<Optional<FlatPtr>> CompilationUnit::base_address() const
44{
45 if (m_has_cached_base_address)
46 return m_cached_base_address;
47
48 auto die = root_die();
49 auto res = TRY(die.get_attribute(Attribute::LowPc));
50 if (res.has_value()) {
51 m_cached_base_address = TRY(res->as_addr());
52 }
53 m_has_cached_base_address = true;
54 return m_cached_base_address;
55}
56
57ErrorOr<u64> CompilationUnit::address_table_base() const
58{
59 if (m_has_cached_address_table_base)
60 return m_cached_address_table_base;
61
62 auto die = root_die();
63 auto res = TRY(die.get_attribute(Attribute::AddrBase));
64 if (res.has_value()) {
65 VERIFY(res->form() == AttributeDataForm::SecOffset);
66 m_cached_address_table_base = res->as_unsigned();
67 }
68 m_has_cached_address_table_base = true;
69 return m_cached_address_table_base;
70}
71
72ErrorOr<u64> CompilationUnit::string_offsets_base() const
73{
74 if (m_has_cached_string_offsets_base)
75 return m_cached_string_offsets_base;
76
77 auto die = root_die();
78 auto res = TRY(die.get_attribute(Attribute::StrOffsetsBase));
79 if (res.has_value()) {
80 VERIFY(res->form() == AttributeDataForm::SecOffset);
81 m_cached_string_offsets_base = res->as_unsigned();
82 }
83 m_has_cached_string_offsets_base = true;
84 return m_cached_string_offsets_base;
85}
86
87ErrorOr<u64> CompilationUnit::range_lists_base() const
88{
89 if (m_has_cached_range_lists_base)
90 return m_cached_range_lists_base;
91
92 auto die = root_die();
93 auto res = TRY(die.get_attribute(Attribute::RngListsBase));
94 if (res.has_value()) {
95 VERIFY(res->form() == AttributeDataForm::SecOffset);
96 m_cached_range_lists_base = res->as_unsigned();
97 }
98 m_has_cached_range_lists_base = true;
99 return m_cached_range_lists_base;
100}
101
102ErrorOr<FlatPtr> CompilationUnit::get_address(size_t index) const
103{
104 auto base = TRY(address_table_base());
105 auto debug_addr_data = dwarf_info().debug_addr_data();
106 VERIFY(base < debug_addr_data.size());
107 auto addresses = debug_addr_data.slice(base);
108 VERIFY(index * sizeof(FlatPtr) < addresses.size());
109 FlatPtr value { 0 };
110 ByteReader::load<FlatPtr>(addresses.offset_pointer(index * sizeof(FlatPtr)), value);
111 return value;
112}
113
114ErrorOr<char const*> CompilationUnit::get_string(size_t index) const
115{
116 auto base = TRY(string_offsets_base());
117 auto debug_str_offsets_data = dwarf_info().debug_str_offsets_data();
118 VERIFY(base < debug_str_offsets_data.size());
119 // FIXME: This assumes DWARF32
120 auto offsets = debug_str_offsets_data.slice(base);
121 VERIFY(index * sizeof(u32) < offsets.size());
122 auto offset = ByteReader::load32(offsets.offset_pointer(index * sizeof(u32)));
123 return bit_cast<char const*>(dwarf_info().debug_strings_data().offset(offset));
124}
125}