1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dwarf_builder.h"
17 #include "compiler/optimizer/ir/graph.h"
18 #include "compiler/optimizer/ir/basicblock.h"
19 #include "function.h"
20
21 #ifdef PANDA_COMPILER_DEBUG_INFO
22 #include <libdwarf/dwarf.h>
23 #endif
24
25 #include <numeric>
26
27 namespace ark::irtoc {
28 template <typename T>
IsDwarfBadAddr(T v)29 static constexpr bool IsDwarfBadAddr(T v)
30 {
31 return reinterpret_cast<Dwarf_Addr>(v) == DW_DLV_BADADDR;
32 }
33
CreateSectionCallback(char * name,int size,Dwarf_Unsigned type,Dwarf_Unsigned flags,Dwarf_Unsigned link,Dwarf_Unsigned info,Dwarf_Unsigned * sectNameIndex,void * userData,int * error)34 int DwarfBuilder::CreateSectionCallback([[maybe_unused]] char *name, [[maybe_unused]] int size,
35 [[maybe_unused]] Dwarf_Unsigned type, [[maybe_unused]] Dwarf_Unsigned flags,
36 [[maybe_unused]] Dwarf_Unsigned link, [[maybe_unused]] Dwarf_Unsigned info,
37 [[maybe_unused]] Dwarf_Unsigned *sectNameIndex, [[maybe_unused]] void *userData,
38 [[maybe_unused]] int *error)
39 {
40 auto self = reinterpret_cast<DwarfBuilder *>(userData);
41 ELFIO::section *section = self->GetElfBuilder()->sections.add(name);
42 if (strncmp(name, ".rel", 4U) == 0) {
43 self->relMap_.insert(
44 {section->get_index(), ELFIO::relocation_section_accessor(*self->GetElfBuilder(), section)});
45 section->set_entry_size(self->GetElfBuilder()->get_default_entry_size(ELFIO::SHT_REL));
46 }
47 self->indexMap_[section->get_index()] = self->sections_.size();
48 self->sections_.push_back(section);
49
50 section->set_type(type);
51 section->set_flags(flags);
52 section->set_link(3U);
53 section->set_info(info);
54
55 return section->get_index();
56 }
57
DwarfBuilder(Arch arch,ELFIO::elfio * elf)58 DwarfBuilder::DwarfBuilder(Arch arch, ELFIO::elfio *elf) : elfBuilder_(elf), arch_(arch)
59 {
60 auto toU {[](int n) { return static_cast<Dwarf_Unsigned>(n); }};
61
62 Dwarf_Error error {nullptr};
63 dwarf_producer_init(toU(DW_DLC_WRITE) | toU(DW_DLC_POINTER64) | toU(DW_DLC_OFFSET32) | toU(DW_DLC_SIZE_64) |
64 toU(DW_DLC_SYMBOLIC_RELOCATIONS) | toU(DW_DLC_TARGET_LITTLEENDIAN),
65 reinterpret_cast<Dwarf_Callback_Func>(DwarfBuilder::CreateSectionCallback), nullptr, nullptr,
66 this, GetIsaName(GetArch()), "V4", nullptr, &dwarf_, &error);
67 if (error != DW_DLV_OK) {
68 LOG(FATAL, COMPILER) << "Dwarf initialization failed: " << dwarf_errmsg(error);
69 }
70
71 int res = dwarf_pro_set_default_string_form(dwarf_, DW_FORM_string, &error);
72 if (res != DW_DLV_OK) {
73 LOG(FATAL, COMPILER) << "dwarf_pro_set_default_string_form failed: " << dwarf_errmsg(error);
74 }
75
76 compileUnitDie_ = dwarf_new_die(dwarf_, DW_TAG_compile_unit, nullptr, nullptr, nullptr, nullptr, &error);
77 if (error != DW_DLV_OK || IsDwarfBadAddr(compileUnitDie_)) {
78 LOG(FATAL, COMPILER) << "dwarf_new_die failed: " << dwarf_errmsg(error);
79 }
80
81 dwarf_add_AT_producer(compileUnitDie_, const_cast<char *>("ASD"), &error);
82 if (error != DW_DLV_OK) {
83 LOG(FATAL, COMPILER) << "dwarf_add_AT_producer failed: " << dwarf_errmsg(error);
84 }
85
86 dwarf_add_die_to_debug(dwarf_, compileUnitDie_, &error);
87 if (error != DW_DLV_OK) {
88 LOG(FATAL, COMPILER) << "dwarf_add_die_to_debug_a failed: " << dwarf_errmsg(error);
89 }
90
91 dwarf_pro_set_default_string_form(dwarf_, DW_FORM_strp, &error);
92
93 dwarf_add_AT_unsigned_const(dwarf_, compileUnitDie_, DW_AT_language, DW_LANG_C, &error);
94 if (error != DW_DLV_OK) {
95 LOG(FATAL, COMPILER) << "DW_AT_language failed: " << dwarf_errmsg(error);
96 }
97 }
98
BuildGraphNestedFunction(unsigned symbol,const Function * func,Dwarf_Error & error,Dwarf_P_Die & die)99 bool DwarfBuilder::BuildGraphNestedFunction(unsigned symbol, const Function *func, Dwarf_Error &error, Dwarf_P_Die &die)
100 {
101 auto graph = func->GetGraph();
102
103 auto sourceDirs {func->GetSourceDirs()};
104 auto sourceFiles {func->GetSourceFiles()};
105
106 if (dwarf_lne_set_address(dwarf_, 0, symbol, &error) != DW_DLV_OK) {
107 LOG(FATAL, COMPILER) << "dwarf_lne_set_address failed: " << dwarf_errmsg(error);
108 }
109
110 for (auto bb : *graph) {
111 if (bb == nullptr) {
112 continue;
113 }
114 for (auto inst : bb->Insts()) {
115 auto debugInfo = inst->GetDebugInfo();
116 if (debugInfo == nullptr) {
117 continue;
118 }
119
120 auto dirIndex {AddDir(sourceDirs[debugInfo->GetDirIndex()])};
121 auto fileIndex {AddFile(sourceFiles[debugInfo->GetFileIndex()], dirIndex)};
122 if (dwarf_add_line_entry(dwarf_, fileIndex, debugInfo->GetOffset(), debugInfo->GetLineNumber(), 0, 1, 0,
123 &error) != DW_DLV_OK) {
124 LOG(ERROR, COMPILER) << "dwarf_add_line_entry failed: " << dwarf_errmsg(error);
125 return false;
126 }
127 }
128 }
129
130 if (dwarf_lne_end_sequence(dwarf_, graph->GetCode().size(), &error) != DW_DLV_OK) {
131 LOG(ERROR, COMPILER) << "dwarf_lne_end_sequence failed: " << dwarf_errmsg(error);
132 return false;
133 }
134
135 auto attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_low_pc, 0, symbol, &error);
136 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
137 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
138 return false;
139 }
140
141 attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_high_pc, graph->GetCode().size(), symbol, &error);
142 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
143 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
144 return false;
145 }
146
147 return true;
148 }
149
BuildGraph(const Function * func,uint32_t codeOffset,unsigned symbol)150 bool DwarfBuilder::BuildGraph(const Function *func, uint32_t codeOffset, unsigned symbol)
151 {
152 auto graph = func->GetGraph();
153 if (!graph->IsLineDebugInfoEnabled()) {
154 return true;
155 }
156
157 Dwarf_Error error = nullptr;
158 auto die = dwarf_new_die(dwarf_, DW_TAG_subprogram, nullptr, nullptr, nullptr, nullptr, &error);
159 if (error != DW_DLV_OK || IsDwarfBadAddr(die)) {
160 LOG(ERROR, COMPILER) << "dwarf_new_die failed: " << dwarf_errmsg(error);
161 return false;
162 }
163
164 Dwarf_P_Die res;
165 if (prevProgramDie_ != nullptr) {
166 res = dwarf_die_link(die, nullptr, nullptr, prevProgramDie_, nullptr, &error);
167 } else {
168 res = dwarf_die_link(die, compileUnitDie_, nullptr, nullptr, nullptr, &error);
169 }
170 if (error != DW_DLV_OK || IsDwarfBadAddr(res)) {
171 LOG(ERROR, COMPILER) << "dwarf_die_link failed: " << dwarf_errmsg(error);
172 }
173 prevProgramDie_ = die;
174
175 Dwarf_P_Attribute a = dwarf_add_AT_name(die, const_cast<char *>(func->GetName()), &error);
176 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
177 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b failed: " << dwarf_errmsg(error);
178 }
179
180 a = dwarf_add_AT_flag(dwarf_, die, DW_AT_external, static_cast<Dwarf_Small>(true), &error);
181 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
182 LOG(ERROR, COMPILER) << "dwarf_add_AT_flag failed: " << dwarf_errmsg(error);
183 }
184
185 if (!BuildGraphNestedFunction(symbol, func, error, die)) {
186 return false;
187 }
188
189 codeSize_ = codeOffset + graph->GetCode().size();
190 return true;
191 }
192
FinalizeNestedFunction(Dwarf_Error & error)193 bool DwarfBuilder::FinalizeNestedFunction(Dwarf_Error &error)
194 {
195 Dwarf_Unsigned relSectionsCount;
196 int bufVersion;
197 auto res = dwarf_get_relocation_info_count(dwarf_, &relSectionsCount, &bufVersion, &error);
198 if (res != DW_DLV_OK) {
199 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info_count failed: " << dwarf_errmsg(error);
200 return false;
201 }
202 for (Dwarf_Unsigned i = 0; i < relSectionsCount; ++i) {
203 Dwarf_Signed elfIndex = 0;
204 Dwarf_Signed linkIndex = 0;
205 Dwarf_Unsigned bufCount;
206 Dwarf_Relocation_Data data;
207 if (dwarf_get_relocation_info(dwarf_, &elfIndex, &linkIndex, &bufCount, &data, &error) != DW_DLV_OK) {
208 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info failed: " << dwarf_errmsg(error);
209 return false;
210 }
211 auto &relWriter = relMap_.at(elfIndex);
212 for (Dwarf_Unsigned j = 0; j < bufCount; j++, data++) {
213 if (data->drd_symbol_index == 0) {
214 continue;
215 }
216 relWriter.add_entry(data->drd_offset,
217 // NOLINTNEXTLINE (hicpp-signed-bitwise)
218 static_cast<ELFIO::Elf_Xword>(ELF64_R_INFO(data->drd_symbol_index, data->drd_type)));
219 }
220 }
221
222 if (dwarf_producer_finish(dwarf_, &error) != DW_DLV_OK) {
223 LOG(ERROR, COMPILER) << "dwarf_producer_finish failed: " << dwarf_errmsg(error);
224 return false;
225 }
226
227 return true;
228 }
229
Finalize(uint32_t codeSize)230 bool DwarfBuilder::Finalize(uint32_t codeSize)
231 {
232 Dwarf_Error error {nullptr};
233
234 auto attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_low_pc, 0, 0, &error);
235 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
236 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
237 return false;
238 }
239
240 attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_high_pc, codeSize, 0, &error);
241 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
242 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
243 return false;
244 }
245
246 auto sections = dwarf_transform_to_disk_form(dwarf_, &error);
247 if (error != DW_DLV_OK || sections == DW_DLV_NOCOUNT) {
248 LOG(ERROR, COMPILER) << "dwarf_transform_to_disk_form failed: " << dwarf_errmsg(error);
249 return false;
250 }
251
252 for (decltype(sections) i = 0; i < sections; ++i) {
253 Dwarf_Unsigned len = 0;
254 Dwarf_Signed elfIdx = 0;
255 auto bytes = reinterpret_cast<const char *>(dwarf_get_section_bytes(dwarf_, i, &elfIdx, &len, &error));
256 ASSERT(error == DW_DLV_OK);
257 (void)bytes;
258 sections_[indexMap_[elfIdx]]->append_data(bytes, len);
259 }
260
261 return FinalizeNestedFunction(error);
262 }
263
AddFile(const std::string & fname,Dwarf_Unsigned dirIndex)264 Dwarf_Unsigned DwarfBuilder::AddFile(const std::string &fname, Dwarf_Unsigned dirIndex)
265 {
266 if (auto it = sourceFilesMap_.find(fname); it != sourceFilesMap_.end()) {
267 return it->second;
268 }
269 Dwarf_Error error {nullptr};
270 Dwarf_Unsigned index = dwarf_add_file_decl(dwarf_, const_cast<char *>(fname.data()), dirIndex, 0U, 0U, &error);
271 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
272 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
273 }
274 sourceFilesMap_[fname] = index;
275 return index;
276 }
277
AddDir(const std::string & dname)278 Dwarf_Unsigned DwarfBuilder::AddDir(const std::string &dname)
279 {
280 if (auto it = dirsMap_.find(dname); it != dirsMap_.end()) {
281 return it->second;
282 }
283 Dwarf_Error error {nullptr};
284 Dwarf_Unsigned index = dwarf_add_directory_decl(dwarf_, const_cast<char *>(dname.data()), &error);
285 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
286 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
287 }
288 dirsMap_[dname] = index;
289 return index;
290 }
291 } // namespace ark::irtoc
292