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
34 // CC-OFFNXT(G.FUN.01-CPP) depend on Dwarf_Callback_Func by DWARF Producer Interface. Should be suppress
CreateSectionCallback(char * name,int size,Dwarf_Unsigned type,Dwarf_Unsigned flags,Dwarf_Unsigned link,Dwarf_Unsigned info,Dwarf_Unsigned * sectNameIndex,void * userData,int * error)35 int DwarfBuilder::CreateSectionCallback([[maybe_unused]] char *name, [[maybe_unused]] int size,
36 [[maybe_unused]] Dwarf_Unsigned type, [[maybe_unused]] Dwarf_Unsigned flags,
37 [[maybe_unused]] Dwarf_Unsigned link, [[maybe_unused]] Dwarf_Unsigned info,
38 [[maybe_unused]] Dwarf_Unsigned *sectNameIndex, [[maybe_unused]] void *userData,
39 [[maybe_unused]] int *error)
40 {
41 auto self = reinterpret_cast<DwarfBuilder *>(userData);
42 ELFIO::section *section = self->GetElfBuilder()->sections.add(name);
43 if (strncmp(name, ".rel", 4U) == 0) {
44 self->relMap_.insert(
45 {section->get_index(), ELFIO::relocation_section_accessor(*self->GetElfBuilder(), section)});
46 section->set_entry_size(self->GetElfBuilder()->get_default_entry_size(ELFIO::SHT_REL));
47 }
48 self->indexMap_[section->get_index()] = self->sections_.size();
49 self->sections_.push_back(section);
50
51 section->set_type(type);
52 section->set_flags(flags);
53 section->set_link(3U);
54 section->set_info(info);
55
56 return section->get_index();
57 }
58
DwarfBuilder(Arch arch,ELFIO::elfio * elf)59 DwarfBuilder::DwarfBuilder(Arch arch, ELFIO::elfio *elf) : elfBuilder_(elf), arch_(arch)
60 {
61 auto toU {[](int n) { return static_cast<Dwarf_Unsigned>(n); }};
62
63 Dwarf_Error error {nullptr};
64 dwarf_producer_init(toU(DW_DLC_WRITE) | toU(DW_DLC_POINTER64) | toU(DW_DLC_OFFSET32) | toU(DW_DLC_SIZE_64) |
65 toU(DW_DLC_SYMBOLIC_RELOCATIONS) | toU(DW_DLC_TARGET_LITTLEENDIAN),
66 reinterpret_cast<Dwarf_Callback_Func>(DwarfBuilder::CreateSectionCallback), nullptr, nullptr,
67 this, GetIsaName(GetArch()), "V4", nullptr, &dwarf_, &error);
68 if (error != DW_DLV_OK) {
69 LOG(FATAL, COMPILER) << "Dwarf initialization failed: " << dwarf_errmsg(error);
70 }
71
72 int res = dwarf_pro_set_default_string_form(dwarf_, DW_FORM_string, &error);
73 if (res != DW_DLV_OK) {
74 LOG(FATAL, COMPILER) << "dwarf_pro_set_default_string_form failed: " << dwarf_errmsg(error);
75 }
76
77 compileUnitDie_ = dwarf_new_die(dwarf_, DW_TAG_compile_unit, nullptr, nullptr, nullptr, nullptr, &error);
78 if (error != DW_DLV_OK || IsDwarfBadAddr(compileUnitDie_)) {
79 LOG(FATAL, COMPILER) << "dwarf_new_die failed: " << dwarf_errmsg(error);
80 }
81
82 dwarf_add_AT_producer(compileUnitDie_, const_cast<char *>("ASD"), &error);
83 if (error != DW_DLV_OK) {
84 LOG(FATAL, COMPILER) << "dwarf_add_AT_producer failed: " << dwarf_errmsg(error);
85 }
86
87 dwarf_add_die_to_debug(dwarf_, compileUnitDie_, &error);
88 if (error != DW_DLV_OK) {
89 LOG(FATAL, COMPILER) << "dwarf_add_die_to_debug_a failed: " << dwarf_errmsg(error);
90 }
91
92 dwarf_pro_set_default_string_form(dwarf_, DW_FORM_strp, &error);
93
94 dwarf_add_AT_unsigned_const(dwarf_, compileUnitDie_, DW_AT_language, DW_LANG_C, &error);
95 if (error != DW_DLV_OK) {
96 LOG(FATAL, COMPILER) << "DW_AT_language failed: " << dwarf_errmsg(error);
97 }
98 }
99
BuildGraphNestedFunction(unsigned symbol,const Function * func,Dwarf_Error & error,Dwarf_P_Die & die)100 bool DwarfBuilder::BuildGraphNestedFunction(unsigned symbol, const Function *func, Dwarf_Error &error, Dwarf_P_Die &die)
101 {
102 auto graph = func->GetGraph();
103
104 auto sourceDirs {func->GetSourceDirs()};
105 auto sourceFiles {func->GetSourceFiles()};
106
107 if (dwarf_lne_set_address(dwarf_, 0, symbol, &error) != DW_DLV_OK) {
108 LOG(FATAL, COMPILER) << "dwarf_lne_set_address failed: " << dwarf_errmsg(error);
109 }
110
111 for (auto bb : *graph) {
112 if (bb == nullptr) {
113 continue;
114 }
115 for (auto inst : bb->Insts()) {
116 auto debugInfo = inst->GetDebugInfo();
117 if (debugInfo == nullptr) {
118 continue;
119 }
120
121 auto dirIndex {AddDir(sourceDirs[debugInfo->GetDirIndex()])};
122 auto fileIndex {AddFile(sourceFiles[debugInfo->GetFileIndex()], dirIndex)};
123 if (dwarf_add_line_entry(dwarf_, fileIndex, debugInfo->GetOffset(), debugInfo->GetLineNumber(), 0, 1, 0,
124 &error) != DW_DLV_OK) {
125 LOG(ERROR, COMPILER) << "dwarf_add_line_entry failed: " << dwarf_errmsg(error);
126 return false;
127 }
128 }
129 }
130
131 if (dwarf_lne_end_sequence(dwarf_, graph->GetCode().size(), &error) != DW_DLV_OK) {
132 LOG(ERROR, COMPILER) << "dwarf_lne_end_sequence failed: " << dwarf_errmsg(error);
133 return false;
134 }
135
136 auto attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_low_pc, 0, symbol, &error);
137 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
138 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
139 return false;
140 }
141
142 attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_high_pc, graph->GetCode().size(), symbol, &error);
143 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
144 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
145 return false;
146 }
147
148 return true;
149 }
150
BuildGraph(const Function * func,uint32_t codeOffset,unsigned symbol)151 bool DwarfBuilder::BuildGraph(const Function *func, uint32_t codeOffset, unsigned symbol)
152 {
153 auto graph = func->GetGraph();
154 if (!graph->IsLineDebugInfoEnabled()) {
155 return true;
156 }
157
158 Dwarf_Error error = nullptr;
159 auto die = dwarf_new_die(dwarf_, DW_TAG_subprogram, nullptr, nullptr, nullptr, nullptr, &error);
160 if (error != DW_DLV_OK || IsDwarfBadAddr(die)) {
161 LOG(ERROR, COMPILER) << "dwarf_new_die failed: " << dwarf_errmsg(error);
162 return false;
163 }
164
165 Dwarf_P_Die res;
166 if (prevProgramDie_ != nullptr) {
167 res = dwarf_die_link(die, nullptr, nullptr, prevProgramDie_, nullptr, &error);
168 } else {
169 res = dwarf_die_link(die, compileUnitDie_, nullptr, nullptr, nullptr, &error);
170 }
171 if (error != DW_DLV_OK || IsDwarfBadAddr(res)) {
172 LOG(ERROR, COMPILER) << "dwarf_die_link failed: " << dwarf_errmsg(error);
173 }
174 prevProgramDie_ = die;
175
176 Dwarf_P_Attribute a = dwarf_add_AT_name(die, const_cast<char *>(func->GetName()), &error);
177 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
178 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b failed: " << dwarf_errmsg(error);
179 }
180
181 a = dwarf_add_AT_flag(dwarf_, die, DW_AT_external, static_cast<Dwarf_Small>(true), &error);
182 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
183 LOG(ERROR, COMPILER) << "dwarf_add_AT_flag failed: " << dwarf_errmsg(error);
184 }
185
186 if (!BuildGraphNestedFunction(symbol, func, error, die)) {
187 return false;
188 }
189
190 codeSize_ = codeOffset + graph->GetCode().size();
191 return true;
192 }
193
FinalizeNestedFunction(Dwarf_Error & error)194 bool DwarfBuilder::FinalizeNestedFunction(Dwarf_Error &error)
195 {
196 Dwarf_Unsigned relSectionsCount;
197 int bufVersion;
198 auto res = dwarf_get_relocation_info_count(dwarf_, &relSectionsCount, &bufVersion, &error);
199 if (res != DW_DLV_OK) {
200 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info_count failed: " << dwarf_errmsg(error);
201 return false;
202 }
203 for (Dwarf_Unsigned i = 0; i < relSectionsCount; ++i) {
204 Dwarf_Signed elfIndex = 0;
205 Dwarf_Signed linkIndex = 0;
206 Dwarf_Unsigned bufCount;
207 Dwarf_Relocation_Data data;
208 if (dwarf_get_relocation_info(dwarf_, &elfIndex, &linkIndex, &bufCount, &data, &error) != DW_DLV_OK) {
209 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info failed: " << dwarf_errmsg(error);
210 return false;
211 }
212 auto &relWriter = relMap_.at(elfIndex);
213 for (Dwarf_Unsigned j = 0; j < bufCount; j++, data++) {
214 if (data->drd_symbol_index == 0) {
215 continue;
216 }
217 relWriter.add_entry(data->drd_offset,
218 // NOLINTNEXTLINE (hicpp-signed-bitwise)
219 static_cast<ELFIO::Elf_Xword>(ELF64_R_INFO(data->drd_symbol_index, data->drd_type)));
220 }
221 }
222
223 if (dwarf_producer_finish(dwarf_, &error) != DW_DLV_OK) {
224 LOG(ERROR, COMPILER) << "dwarf_producer_finish failed: " << dwarf_errmsg(error);
225 return false;
226 }
227
228 return true;
229 }
230
Finalize(uint32_t codeSize)231 bool DwarfBuilder::Finalize(uint32_t codeSize)
232 {
233 Dwarf_Error error {nullptr};
234
235 auto attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_low_pc, 0, 0, &error);
236 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
237 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
238 return false;
239 }
240
241 attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_high_pc, codeSize, 0, &error);
242 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
243 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
244 return false;
245 }
246
247 auto sections = dwarf_transform_to_disk_form(dwarf_, &error);
248 if (error != DW_DLV_OK || sections == DW_DLV_NOCOUNT) {
249 LOG(ERROR, COMPILER) << "dwarf_transform_to_disk_form failed: " << dwarf_errmsg(error);
250 return false;
251 }
252
253 for (decltype(sections) i = 0; i < sections; ++i) {
254 Dwarf_Unsigned len = 0;
255 Dwarf_Signed elfIdx = 0;
256 auto bytes = reinterpret_cast<const char *>(dwarf_get_section_bytes(dwarf_, i, &elfIdx, &len, &error));
257 ASSERT(error == DW_DLV_OK);
258 (void)bytes;
259 sections_[indexMap_[elfIdx]]->append_data(bytes, len);
260 }
261
262 return FinalizeNestedFunction(error);
263 }
264
AddFile(const std::string & fname,Dwarf_Unsigned dirIndex)265 Dwarf_Unsigned DwarfBuilder::AddFile(const std::string &fname, Dwarf_Unsigned dirIndex)
266 {
267 if (auto it = sourceFilesMap_.find(fname); it != sourceFilesMap_.end()) {
268 return it->second;
269 }
270 Dwarf_Error error {nullptr};
271 Dwarf_Unsigned index = dwarf_add_file_decl(dwarf_, const_cast<char *>(fname.data()), dirIndex, 0U, 0U, &error);
272 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
273 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
274 }
275 sourceFilesMap_[fname] = index;
276 return index;
277 }
278
AddDir(const std::string & dname)279 Dwarf_Unsigned DwarfBuilder::AddDir(const std::string &dname)
280 {
281 if (auto it = dirsMap_.find(dname); it != dirsMap_.end()) {
282 return it->second;
283 }
284 Dwarf_Error error {nullptr};
285 Dwarf_Unsigned index = dwarf_add_directory_decl(dwarf_, const_cast<char *>(dname.data()), &error);
286 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
287 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
288 }
289 dirsMap_[dname] = index;
290 return index;
291 }
292 } // namespace ark::irtoc
293