• 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 
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