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