blob: 9aeb8ed20d6ee620d4740fe4e112b91c1ec7ca63 [file] [log] [blame]
jimblandy3e768ed2010-03-16 16:31:49 +00001// -*- 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
jimblandy87855242010-04-05 19:40:17 +000039#include "common/dwarf_cfi_to_module.h"
jimblandy3e768ed2010-03-16 16:31:49 +000040
41namespace google_breakpad {
42
43using std::ostringstream;
44
jimblandy504280a2010-04-28 18:14:59 +000045vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
46 const char * const *strings,
47 size_t size) {
48 vector<string> names(strings, strings + size);
49 return names;
50}
51
52vector<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 return MakeVector(names, sizeof(names) / sizeof(names[0]));
66}
67
68vector<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 return MakeVector(names, sizeof(names) / sizeof(names[0]));
85}
86
87vector<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 return MakeVector(names, sizeof(names) / sizeof(names[0]));
96}
97
jimblandy3e768ed2010-03-16 16:31:49 +000098bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
99 uint8 version, const string &augmentation,
100 unsigned return_address) {
101 assert(!entry_);
jimblandya76aaa12010-03-16 16:37:50 +0000102
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.
jimblandy3e768ed2010-03-16 16:31:49 +0000106
107 // Get ready to collect entries.
108 entry_ = new Module::StackFrameEntry;
109 entry_->address = address;
110 entry_->size = length;
111 entry_offset_ = offset;
112 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 if (return_address_ < register_names_.size())
jimblandy786275e2010-07-17 15:14:30 +0000120 entry_->initial_rules[ra_name_] = register_names_[return_address_];
jimblandy3e768ed2010-03-16 16:31:49 +0000121
122 return true;
123}
124
125string DwarfCFIToModule::RegisterName(int i) {
126 assert(entry_);
127 if (i < 0) {
128 assert(i == kCFARegister);
jimblandy786275e2010-07-17 15:14:30 +0000129 return cfa_name_;
jimblandy3e768ed2010-03-16 16:31:49 +0000130 }
131 unsigned reg = i;
132 if (reg == return_address_)
jimblandy786275e2010-07-17 15:14:30 +0000133 return ra_name_;
jimblandy3e768ed2010-03-16 16:31:49 +0000134
mark@chromium.orgf699cee2011-10-11 17:38:35 +0000135 if (reg < register_names_.size())
jimblandy3e768ed2010-03-16 16:31:49 +0000136 return register_names_[reg];
137
138 reporter_->UnnamedRegister(entry_offset_, reg);
139 char buf[30];
140 sprintf(buf, "unnamed_register%u", reg);
141 return buf;
142}
143
144void DwarfCFIToModule::Record(Module::Address address, int reg,
145 const string &rule) {
146 assert(entry_);
jimblandy786275e2010-07-17 15:14:30 +0000147
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 string shared_rule = *common_strings_.insert(rule).first;
155
jimblandy3e768ed2010-03-16 16:31:49 +0000156 // Is this one of this entry's initial rules?
157 if (address == entry_->address)
jimblandy786275e2010-07-17 15:14:30 +0000158 entry_->initial_rules[RegisterName(reg)] = shared_rule;
jimblandy3e768ed2010-03-16 16:31:49 +0000159 // File it under the appropriate address.
160 else
jimblandy786275e2010-07-17 15:14:30 +0000161 entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
jimblandy3e768ed2010-03-16 16:31:49 +0000162}
163
164bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
165 reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
166 // Treat this as a non-fatal error.
167 return true;
168}
169
170bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
171 ostringstream s;
172 s << RegisterName(reg);
173 Record(address, reg, s.str());
174 return true;
175}
176
177bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
178 int base_register, long offset) {
179 ostringstream s;
180 s << RegisterName(base_register) << " " << offset << " + ^";
181 Record(address, reg, s.str());
182 return true;
183}
184
185bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
186 int base_register, long offset) {
187 ostringstream s;
188 s << RegisterName(base_register) << " " << offset << " +";
189 Record(address, reg, s.str());
190 return true;
191}
192
193bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
194 int base_register) {
195 ostringstream s;
196 s << RegisterName(base_register);
197 Record(address, reg, s.str());
198 return true;
199}
200
201bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
202 const string &expression) {
203 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
204 // Treat this as a non-fatal error.
205 return true;
206}
207
208bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
209 const string &expression) {
210 reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
211 // Treat this as a non-fatal error.
212 return true;
213}
214
215bool DwarfCFIToModule::End() {
216 module_->AddStackFrameEntry(entry_);
217 entry_ = NULL;
218 return true;
219}
220
221void 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 file_.c_str(), section_.c_str(), offset, reg);
226}
227
228void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
229 const string &reg) {
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 file_.c_str(), section_.c_str(), offset, reg.c_str());
235}
236
237void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
238 const string &reg) {
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 file_.c_str(), section_.c_str(), offset, reg.c_str());
245}
246
247} // namespace google_breakpad