1 : // -*- mode: c++ -*-
2 :
3 : // Copyright (c) 2010, Google Inc.
4 : // All rights reserved.
5 : //
6 : // Redistribution and use in source and binary forms, with or without
7 : // modification, are permitted provided that the following conditions are
8 : // met:
9 : //
10 : // * Redistributions of source code must retain the above copyright
11 : // notice, this list of conditions and the following disclaimer.
12 : // * Redistributions in binary form must reproduce the above
13 : // copyright notice, this list of conditions and the following disclaimer
14 : // in the documentation and/or other materials provided with the
15 : // distribution.
16 : // * Neither the name of Google Inc. nor the names of its
17 : // contributors may be used to endorse or promote products derived from
18 : // this software without specific prior written permission.
19 : //
20 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 :
32 : // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
33 :
34 : // Implementation of google_breakpad::DwarfCFIToModule.
35 : // See dwarf_cfi_to_module.h for details.
36 :
37 : #include <sstream>
38 :
39 : #include "common/dwarf_cfi_to_module.h"
40 :
41 : namespace google_breakpad {
42 :
43 : using std::ostringstream;
44 :
45 248 : vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
46 : const char * const *strings,
47 : size_t size) {
48 248 : vector<string> names(strings, strings + size);
49 : return names;
50 : }
51 :
52 248 : vector<string> DwarfCFIToModule::RegisterNames::I386() {
53 : static const char *const names[] = {
54 : "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
55 : "$eip", "$eflags", "$unused1",
56 : "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
57 : "$unused2", "$unused3",
58 : "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
59 : "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
60 : "$fcw", "$fsw", "$mxcsr",
61 : "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
62 : "$tr", "$ldtr"
63 : };
64 :
65 248 : return MakeVector(names, sizeof(names) / sizeof(names[0]));
66 : }
67 :
68 0 : vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
69 : static const char *const names[] = {
70 : "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
71 : "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
72 : "$rip",
73 : "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
74 : "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
75 : "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
76 : "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
77 : "$rflags",
78 : "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
79 : "$fs.base", "$gs.base", "$unused3", "$unused4",
80 : "$tr", "$ldtr",
81 : "$mxcsr", "$fcw", "$fsw"
82 : };
83 :
84 0 : return MakeVector(names, sizeof(names) / sizeof(names[0]));
85 : }
86 :
87 0 : vector<string> DwarfCFIToModule::RegisterNames::ARM() {
88 : static const char *const names[] = {
89 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
90 : "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
91 : "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
92 : "fps", "cpsr"
93 : };
94 :
95 0 : return MakeVector(names, sizeof(names) / sizeof(names[0]));
96 : }
97 :
98 691722 : bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
99 : uint8 version, const string &augmentation,
100 : unsigned return_address) {
101 691722 : assert(!entry_);
102 :
103 : // If dwarf2reader::CallFrameInfo can handle this version and
104 : // augmentation, then we should be okay with that, so there's no
105 : // need to check them here.
106 :
107 : // Get ready to collect entries.
108 691722 : entry_ = new Module::StackFrameEntry;
109 691722 : entry_->address = address;
110 691722 : entry_->size = length;
111 691722 : entry_offset_ = offset;
112 691722 : return_address_ = return_address;
113 :
114 : // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
115 : // may not establish any rule for .ra if the return address column
116 : // is an ordinary register, and that register holds the return
117 : // address on entry to the function. So establish an initial .ra
118 : // rule citing the return address register.
119 691722 : if (return_address_ < register_names_.size())
120 691722 : entry_->initial_rules[ra_name_] = register_names_[return_address_];
121 :
122 691722 : return true;
123 : }
124 :
125 12650766 : string DwarfCFIToModule::RegisterName(int i) {
126 12650766 : assert(entry_);
127 12650766 : if (i < 0) {
128 4868051 : assert(i == kCFARegister);
129 4868051 : return cfa_name_;
130 : }
131 7782715 : unsigned reg = i;
132 7782715 : if (reg == return_address_)
133 691722 : return ra_name_;
134 :
135 7090993 : if (0 <= reg && reg < register_names_.size())
136 7090993 : return register_names_[reg];
137 :
138 0 : reporter_->UnnamedRegister(entry_offset_, reg);
139 : char buf[30];
140 0 : sprintf(buf, "unnamed_register%u", reg);
141 0 : return buf;
142 : }
143 :
144 6325237 : void DwarfCFIToModule::Record(Module::Address address, int reg,
145 : const string &rule) {
146 6325237 : assert(entry_);
147 :
148 : // Place the name in our global set of strings, and then use the string
149 : // from the set. Even though the assignment looks like a copy, all the
150 : // major std::string implementations use reference counting internally,
151 : // so the effect is to have all our data structures share copies of rules
152 : // whenever possible. Since register names are drawn from a
153 : // vector<string>, register names are already shared.
154 12650474 : string shared_rule = *common_strings_.insert(rule).first;
155 :
156 : // Is this one of this entry's initial rules?
157 6325237 : if (address == entry_->address)
158 1383444 : entry_->initial_rules[RegisterName(reg)] = shared_rule;
159 : // File it under the appropriate address.
160 : else
161 4941793 : entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
162 6325237 : }
163 :
164 0 : bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
165 0 : reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
166 : // Treat this as a non-fatal error.
167 0 : return true;
168 : }
169 :
170 1457223 : bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
171 2914446 : ostringstream s;
172 1457223 : s << RegisterName(reg);
173 1457223 : Record(address, reg, s.str());
174 1457223 : return true;
175 : }
176 :
177 2189720 : bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
178 : int base_register, long offset) {
179 4379440 : ostringstream s;
180 2189720 : s << RegisterName(base_register) << " " << offset << " + ^";
181 2189720 : Record(address, reg, s.str());
182 2189720 : return true;
183 : }
184 :
185 2678294 : bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
186 : int base_register, long offset) {
187 5356588 : ostringstream s;
188 2678294 : s << RegisterName(base_register) << " " << offset << " +";
189 2678294 : Record(address, reg, s.str());
190 2678294 : return true;
191 : }
192 :
193 0 : bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
194 : int base_register) {
195 0 : ostringstream s;
196 0 : s << RegisterName(base_register);
197 0 : Record(address, reg, s.str());
198 0 : return true;
199 : }
200 :
201 255 : bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
202 : const string &expression) {
203 255 : reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
204 : // Treat this as a non-fatal error.
205 255 : return true;
206 : }
207 :
208 37 : bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
209 : const string &expression) {
210 37 : reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
211 : // Treat this as a non-fatal error.
212 37 : return true;
213 : }
214 :
215 691722 : bool DwarfCFIToModule::End() {
216 691722 : module_->AddStackFrameEntry(entry_);
217 691722 : entry_ = NULL;
218 691722 : return true;
219 : }
220 :
221 0 : void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
222 : fprintf(stderr, "%s, section '%s': "
223 : "the call frame entry at offset 0x%zx refers to register %d,"
224 : " whose name we don't know\n",
225 0 : file_.c_str(), section_.c_str(), offset, reg);
226 0 : }
227 :
228 0 : void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
229 : const string ®) {
230 : fprintf(stderr, "%s, section '%s': "
231 : "the call frame entry at offset 0x%zx sets the rule for "
232 : "register '%s' to 'undefined', but the Breakpad symbol file format"
233 : " cannot express this\n",
234 0 : file_.c_str(), section_.c_str(), offset, reg.c_str());
235 0 : }
236 :
237 292 : void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
238 : const string ®) {
239 : fprintf(stderr, "%s, section '%s': "
240 : "the call frame entry at offset 0x%zx uses a DWARF expression to"
241 : " describe how to recover register '%s', "
242 : " but this translator cannot yet translate DWARF expressions to"
243 : " Breakpad postfix expressions\n",
244 292 : file_.c_str(), section_.c_str(), offset, reg.c_str());
245 292 : }
246 :
247 : } // namespace google_breakpad
|