xref: /aosp_15_r20/external/google-breakpad/src/common/dwarf_cfi_to_module.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // -*- mode: c++ -*-
2 
3 // Copyright 2010 Google LLC
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google LLC nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Original author: Jim Blandy <[email protected]> <[email protected]>
32 
33 // Implementation of google_breakpad::DwarfCFIToModule.
34 // See dwarf_cfi_to_module.h for details.
35 
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>  // Must come first
38 #endif
39 
40 #include <memory>
41 #include <sstream>
42 #include <utility>
43 
44 #include "common/dwarf_cfi_to_module.h"
45 
46 namespace google_breakpad {
47 
48 using std::ostringstream;
49 
MakeVector(const char * const * strings,size_t size)50 vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
51     const char * const *strings,
52     size_t size) {
53   vector<string> names(strings, strings + size);
54   return names;
55 }
56 
I386()57 vector<string> DwarfCFIToModule::RegisterNames::I386() {
58   static const char *const names[] = {
59     "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
60     "$eip", "$eflags", "$unused1",
61     "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
62     "$unused2", "$unused3",
63     "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
64     "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
65     "$fcw", "$fsw", "$mxcsr",
66     "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
67     "$tr", "$ldtr"
68   };
69 
70   return MakeVector(names, sizeof(names) / sizeof(names[0]));
71 }
72 
X86_64()73 vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
74   static const char *const names[] = {
75     "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
76     "$r8",  "$r9",  "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
77     "$rip",
78     "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
79     "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
80     "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
81     "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
82     "$rflags",
83     "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
84     "$fs.base", "$gs.base", "$unused3", "$unused4",
85     "$tr", "$ldtr",
86     "$mxcsr", "$fcw", "$fsw"
87   };
88 
89   return MakeVector(names, sizeof(names) / sizeof(names[0]));
90 }
91 
92 // Per ARM IHI 0040A, section 3.1
ARM()93 vector<string> DwarfCFIToModule::RegisterNames::ARM() {
94   static const char *const names[] = {
95     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
96     "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
97     "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
98     "fps", "cpsr", "",   "",    "",    "",    "",    "",
99     "",    "",    "",    "",    "",    "",    "",    "",
100     "",    "",    "",    "",    "",    "",    "",    "",
101     "",    "",    "",    "",    "",    "",    "",    "",
102     "",    "",    "",    "",    "",    "",    "",    "",
103     "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
104     "s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
105     "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
106     "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
107     "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7"
108   };
109 
110   return MakeVector(names, sizeof(names) / sizeof(names[0]));
111 }
112 
113 // Per ARM IHI 0057A, section 3.1
ARM64()114 vector<string> DwarfCFIToModule::RegisterNames::ARM64() {
115   static const char *const names[] = {
116     "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
117     "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
118     "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
119     "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
120     "",    "",    "",    "",    "",    "",    "",    "",
121     "",    "",    "",    "",    "",    "",    "",    "",
122     "",    "",    "",    "",    "",    "",    "",    "",
123     "",    "",    "",    "",    "",    "",    "",    "",
124     "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
125     "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
126     "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
127     "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
128   };
129 
130   return MakeVector(names, sizeof(names) / sizeof(names[0]));
131 }
132 
MIPS()133 vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
134   static const char* const kRegisterNames[] = {
135     "$zero", "$at",  "$v0",  "$v1",  "$a0",   "$a1",  "$a2",  "$a3",
136     "$t0",   "$t1",  "$t2",  "$t3",  "$t4",   "$t5",  "$t6",  "$t7",
137     "$s0",   "$s1",  "$s2",  "$s3",  "$s4",   "$s5",  "$s6",  "$s7",
138     "$t8",   "$t9",  "$k0",  "$k1",  "$gp",   "$sp",  "$fp",  "$ra",
139     "$lo",   "$hi",  "$pc",  "$f0",  "$f2",   "$f3",  "$f4",  "$f5",
140     "$f6",   "$f7",  "$f8",  "$f9",  "$f10",  "$f11", "$f12", "$f13",
141     "$f14",  "$f15", "$f16", "$f17", "$f18",  "$f19", "$f20",
142     "$f21",  "$f22", "$f23", "$f24", "$f25",  "$f26", "$f27",
143     "$f28",  "$f29", "$f30", "$f31", "$fcsr", "$fir"
144   };
145 
146   return MakeVector(kRegisterNames,
147                     sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
148 }
149 
RISCV()150 vector<string> DwarfCFIToModule::RegisterNames::RISCV() {
151   static const char *const names[] = {
152     "pc",  "ra",  "sp",  "gp",  "tp",  "t0",  "t1",  "t2",
153     "s0",  "s1",  "a0",  "a1",  "a2",  "a3",  "a4",  "a5",
154     "a6",  "a7",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
155     "s8",  "s9",  "s10", "s11", "t3",  "t4",  "t5",  "t6",
156     "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
157     "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
158     "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
159     "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
160     "",    "",    "",    "",    "",    "",    "",    "",
161     "",    "",    "",    "",    "",    "",    "",    "",
162     "",    "",    "",    "",    "",    "",    "",    "",
163     "",    "",    "",    "",    "",    "",    "",    "",
164     "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
165     "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
166     "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
167     "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
168   };
169 
170   return MakeVector(names, sizeof(names) / sizeof(names[0]));
171 }
172 
Entry(size_t offset,uint64_t address,uint64_t length,uint8_t version,const string & augmentation,unsigned return_address)173 bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
174                              uint8_t version, const string& augmentation,
175                              unsigned return_address) {
176   assert(!entry_);
177 
178   // If CallFrameInfo can handle this version and
179   // augmentation, then we should be okay with that, so there's no
180   // need to check them here.
181 
182   // Get ready to collect entries.
183   entry_ = std::make_unique<Module::StackFrameEntry>();
184   entry_->address = address;
185   entry_->size = length;
186   entry_offset_ = offset;
187   return_address_ = return_address;
188 
189   // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
190   // may not establish any rule for .ra if the return address column
191   // is an ordinary register, and that register holds the return
192   // address on entry to the function. So establish an initial .ra
193   // rule citing the return address register.
194   if (return_address_ < register_names_.size())
195     entry_->initial_rules[ra_name_] = register_names_[return_address_];
196 
197   return true;
198 }
199 
RegisterName(int i)200 string DwarfCFIToModule::RegisterName(int i) {
201   assert(entry_);
202   if (i < 0) {
203     assert(i == kCFARegister);
204     return cfa_name_;
205   }
206   unsigned reg = i;
207   if (reg == return_address_)
208     return ra_name_;
209 
210   // Ensure that a non-empty name exists for this register value.
211   if (reg < register_names_.size() && !register_names_[reg].empty())
212     return register_names_[reg];
213 
214   reporter_->UnnamedRegister(entry_offset_, reg);
215   return string("unnamed_register") + std::to_string(reg);
216 }
217 
Record(Module::Address address,int reg,const string & rule)218 void DwarfCFIToModule::Record(Module::Address address, int reg,
219                               const string& rule) {
220   assert(entry_);
221 
222   // Place the name in our global set of strings, and then use the string
223   // from the set. Even though the assignment looks like a copy, all the
224   // major string implementations use reference counting internally,
225   // so the effect is to have all our data structures share copies of rules
226   // whenever possible. Since register names are drawn from a
227   // vector<string>, register names are already shared.
228   string shared_rule = *common_strings_.insert(rule).first;
229 
230   // Is this one of this entry's initial rules?
231   if (address == entry_->address)
232     entry_->initial_rules[RegisterName(reg)] = shared_rule;
233   // File it under the appropriate address.
234   else
235     entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
236 }
237 
UndefinedRule(uint64_t address,int reg)238 bool DwarfCFIToModule::UndefinedRule(uint64_t address, int reg) {
239   reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
240   // Treat this as a non-fatal error.
241   return true;
242 }
243 
SameValueRule(uint64_t address,int reg)244 bool DwarfCFIToModule::SameValueRule(uint64_t address, int reg) {
245   ostringstream s;
246   s << RegisterName(reg);
247   Record(address, reg, s.str());
248   return true;
249 }
250 
OffsetRule(uint64_t address,int reg,int base_register,long offset)251 bool DwarfCFIToModule::OffsetRule(uint64_t address, int reg,
252                                   int base_register, long offset) {
253   ostringstream s;
254   s << RegisterName(base_register) << " " << offset << " + ^";
255   Record(address, reg, s.str());
256   return true;
257 }
258 
ValOffsetRule(uint64_t address,int reg,int base_register,long offset)259 bool DwarfCFIToModule::ValOffsetRule(uint64_t address, int reg,
260                                      int base_register, long offset) {
261   ostringstream s;
262   s << RegisterName(base_register) << " " << offset << " +";
263   Record(address, reg, s.str());
264   return true;
265 }
266 
RegisterRule(uint64_t address,int reg,int base_register)267 bool DwarfCFIToModule::RegisterRule(uint64_t address, int reg,
268                                     int base_register) {
269   ostringstream s;
270   s << RegisterName(base_register);
271   Record(address, reg, s.str());
272   return true;
273 }
274 
ExpressionRule(uint64_t address,int reg,const string & expression)275 bool DwarfCFIToModule::ExpressionRule(uint64_t address, int reg,
276                                       const string& expression) {
277   reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
278   // Treat this as a non-fatal error.
279   return true;
280 }
281 
ValExpressionRule(uint64_t address,int reg,const string & expression)282 bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg,
283                                          const string& expression) {
284   reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
285   // Treat this as a non-fatal error.
286   return true;
287 }
288 
End()289 bool DwarfCFIToModule::End() {
290   module_->AddStackFrameEntry(std::move(entry_));
291   return true;
292 }
293 
Architecture()294 string DwarfCFIToModule::Architecture() {
295   return module_->architecture();
296 }
297 
UnnamedRegister(size_t offset,int reg)298 void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
299   fprintf(stderr, "%s, section '%s': "
300           "the call frame entry at offset 0x%zx refers to register %d,"
301           " whose name we don't know\n",
302           file_.c_str(), section_.c_str(), offset, reg);
303 }
304 
UndefinedNotSupported(size_t offset,const string & reg)305 void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
306                                                        const string& reg) {
307   fprintf(stderr, "%s, section '%s': "
308           "the call frame entry at offset 0x%zx sets the rule for "
309           "register '%s' to 'undefined', but the Breakpad symbol file format"
310           " cannot express this\n",
311           file_.c_str(), section_.c_str(), offset, reg.c_str());
312 }
313 
ExpressionsNotSupported(size_t offset,const string & reg)314 void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
315                                                          const string& reg) {
316   fprintf(stderr, "%s, section '%s': "
317           "the call frame entry at offset 0x%zx uses a DWARF expression to"
318           " describe how to recover register '%s', "
319           " but this translator cannot yet translate DWARF expressions to"
320           " Breakpad postfix expressions\n",
321           file_.c_str(), section_.c_str(), offset, reg.c_str());
322 }
323 
324 } // namespace google_breakpad
325