• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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