1 /*
2 * Copyright (c) 2021-2022 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 panda::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
BuildGraph(const Function * func,uint32_t codeOffset,unsigned symbol)99 bool DwarfBuilder::BuildGraph(const Function *func, uint32_t codeOffset, unsigned symbol)
100 {
101 auto graph = func->GetGraph();
102 if (!graph->IsLineDebugInfoEnabled()) {
103 return true;
104 }
105
106 Dwarf_Error error = nullptr;
107 auto die = dwarf_new_die(dwarf_, DW_TAG_subprogram, nullptr, nullptr, nullptr, nullptr, &error);
108 if (error != DW_DLV_OK || IsDwarfBadAddr(die)) {
109 LOG(ERROR, COMPILER) << "dwarf_new_die failed: " << dwarf_errmsg(error);
110 return false;
111 }
112
113 Dwarf_P_Die res;
114 if (prevProgramDie_ != nullptr) {
115 res = dwarf_die_link(die, nullptr, nullptr, prevProgramDie_, nullptr, &error);
116 } else {
117 res = dwarf_die_link(die, compileUnitDie_, nullptr, nullptr, nullptr, &error);
118 }
119 if (error != DW_DLV_OK || IsDwarfBadAddr(res)) {
120 LOG(ERROR, COMPILER) << "dwarf_die_link failed: " << dwarf_errmsg(error);
121 }
122 prevProgramDie_ = die;
123
124 Dwarf_P_Attribute a = dwarf_add_AT_name(die, const_cast<char *>(func->GetName()), &error);
125 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
126 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b failed: " << dwarf_errmsg(error);
127 }
128
129 a = dwarf_add_AT_flag(dwarf_, die, DW_AT_external, static_cast<Dwarf_Small>(true), &error);
130 if (error != DW_DLV_OK || IsDwarfBadAddr(a)) {
131 LOG(ERROR, COMPILER) << "dwarf_add_AT_flag failed: " << dwarf_errmsg(error);
132 }
133
134 auto sourceDirs {func->GetSourceDirs()};
135 auto sourceFiles {func->GetSourceFiles()};
136
137 if (dwarf_lne_set_address(dwarf_, 0, symbol, &error) != DW_DLV_OK) {
138 LOG(FATAL, COMPILER) << "dwarf_lne_set_address failed: " << dwarf_errmsg(error);
139 }
140
141 for (auto bb : *graph) {
142 if (bb == nullptr) {
143 continue;
144 }
145 for (auto inst : bb->Insts()) {
146 auto debugInfo = inst->GetDebugInfo();
147 if (debugInfo == nullptr) {
148 continue;
149 }
150
151 auto dirIndex {AddDir(sourceDirs[debugInfo->GetDirIndex()])};
152 auto fileIndex {AddFile(sourceFiles[debugInfo->GetFileIndex()], dirIndex)};
153 if (dwarf_add_line_entry(dwarf_, fileIndex, debugInfo->GetOffset(), debugInfo->GetLineNumber(), 0, 1, 0,
154 &error) != DW_DLV_OK) {
155 LOG(ERROR, COMPILER) << "dwarf_add_line_entry failed: " << dwarf_errmsg(error);
156 return false;
157 }
158 }
159 }
160
161 if (dwarf_lne_end_sequence(dwarf_, graph->GetCode().size(), &error) != DW_DLV_OK) {
162 LOG(ERROR, COMPILER) << "dwarf_lne_end_sequence failed: " << dwarf_errmsg(error);
163 return false;
164 }
165
166 auto attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_low_pc, 0, symbol, &error);
167 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
168 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
169 return false;
170 }
171
172 attr = dwarf_add_AT_targ_address_b(dwarf_, die, DW_AT_high_pc, graph->GetCode().size(), symbol, &error);
173 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
174 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
175 return false;
176 }
177
178 codeSize_ = codeOffset + graph->GetCode().size();
179 return true;
180 }
181
Finalize(uint32_t codeSize)182 bool DwarfBuilder::Finalize(uint32_t codeSize)
183 {
184 Dwarf_Error error {nullptr};
185
186 auto attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_low_pc, 0, 0, &error);
187 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
188 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_low_pc) failed: " << dwarf_errmsg(error);
189 return false;
190 }
191
192 attr = dwarf_add_AT_targ_address_b(dwarf_, compileUnitDie_, DW_AT_high_pc, codeSize, 0, &error);
193 if (error != DW_DLV_OK || IsDwarfBadAddr(attr)) {
194 LOG(ERROR, COMPILER) << "dwarf_add_AT_targ_address_b(DW_AT_high_pc) failed: " << dwarf_errmsg(error);
195 return false;
196 }
197
198 auto sections = dwarf_transform_to_disk_form(dwarf_, &error);
199 if (error != DW_DLV_OK || sections == DW_DLV_NOCOUNT) {
200 LOG(ERROR, COMPILER) << "dwarf_transform_to_disk_form failed: " << dwarf_errmsg(error);
201 return false;
202 }
203
204 for (decltype(sections) i = 0; i < sections; ++i) {
205 Dwarf_Unsigned len = 0;
206 Dwarf_Signed elfIdx = 0;
207 auto bytes = reinterpret_cast<const char *>(dwarf_get_section_bytes(dwarf_, i, &elfIdx, &len, &error));
208 ASSERT(error == DW_DLV_OK);
209 (void)bytes;
210 sections_[indexMap_[elfIdx]]->append_data(bytes, len);
211 }
212
213 Dwarf_Unsigned relSectionsCount;
214 int bufVersion;
215 auto res = dwarf_get_relocation_info_count(dwarf_, &relSectionsCount, &bufVersion, &error);
216 if (res != DW_DLV_OK) {
217 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info_count failed: " << dwarf_errmsg(error);
218 return false;
219 }
220 for (Dwarf_Unsigned i = 0; i < relSectionsCount; ++i) {
221 Dwarf_Signed elfIndex = 0;
222 Dwarf_Signed linkIndex = 0;
223 Dwarf_Unsigned bufCount;
224 Dwarf_Relocation_Data data;
225 if (dwarf_get_relocation_info(dwarf_, &elfIndex, &linkIndex, &bufCount, &data, &error) != DW_DLV_OK) {
226 LOG(ERROR, COMPILER) << "dwarf_get_relocation_info failed: " << dwarf_errmsg(error);
227 return false;
228 }
229 auto &relWriter = relMap_.at(elfIndex);
230 for (Dwarf_Unsigned j = 0; j < bufCount; j++, data++) {
231 if (data->drd_symbol_index == 0) {
232 continue;
233 }
234 relWriter.add_entry(data->drd_offset,
235 // NOLINTNEXTLINE (hicpp-signed-bitwise)
236 static_cast<ELFIO::Elf_Xword>(ELF64_R_INFO(data->drd_symbol_index, data->drd_type)));
237 }
238 }
239
240 if (dwarf_producer_finish(dwarf_, &error) != DW_DLV_OK) {
241 LOG(ERROR, COMPILER) << "dwarf_producer_finish failed: " << dwarf_errmsg(error);
242 return false;
243 }
244
245 return true;
246 }
247
AddFile(const std::string & fname,Dwarf_Unsigned dirIndex)248 Dwarf_Unsigned DwarfBuilder::AddFile(const std::string &fname, Dwarf_Unsigned dirIndex)
249 {
250 if (auto it = sourceFilesMap_.find(fname); it != sourceFilesMap_.end()) {
251 return it->second;
252 }
253 Dwarf_Error error {nullptr};
254 Dwarf_Unsigned index = dwarf_add_file_decl(dwarf_, const_cast<char *>(fname.data()), dirIndex, 0U, 0U, &error);
255 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
256 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
257 }
258 sourceFilesMap_[fname] = index;
259 return index;
260 }
261
AddDir(const std::string & dname)262 Dwarf_Unsigned DwarfBuilder::AddDir(const std::string &dname)
263 {
264 if (auto it = dirsMap_.find(dname); it != dirsMap_.end()) {
265 return it->second;
266 }
267 Dwarf_Error error {nullptr};
268 Dwarf_Unsigned index = dwarf_add_directory_decl(dwarf_, const_cast<char *>(dname.data()), &error);
269 if (index == static_cast<Dwarf_Unsigned>(DW_DLV_NOCOUNT)) {
270 LOG(FATAL, COMPILER) << "dwarf_add_file_decl failed: " << dwarf_errmsg(error);
271 }
272 dirsMap_[dname] = index;
273 return index;
274 }
275 } // namespace panda::irtoc
276