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
41namespace google_breakpad {
42
43using std::ostringstream;
44
45vector<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
87// Per ARM IHI 0040A, section 3.1
88vector<string> DwarfCFIToModule::RegisterNames::ARM() {
89  static const char *const names[] = {
90    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
91    "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
92    "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
93    "fps", "cpsr", "",   "",    "",    "",    "",    "",
94    "",    "",    "",    "",    "",    "",    "",    "",
95    "",    "",    "",    "",    "",    "",    "",    "",
96    "",    "",    "",    "",    "",    "",    "",    "",
97    "",    "",    "",    "",    "",    "",    "",    "",
98    "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
99    "s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
100    "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
101    "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
102    "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7"
103  };
104
105  return MakeVector(names, sizeof(names) / sizeof(names[0]));
106}
107
108// Per ARM IHI 0057A, section 3.1
109vector<string> DwarfCFIToModule::RegisterNames::ARM64() {
110  static const char *const names[] = {
111    "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
112    "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
113    "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
114    "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
115    "",    "",    "",    "",    "",    "",    "",    "",
116    "",    "",    "",    "",    "",    "",    "",    "",
117    "",    "",    "",    "",    "",    "",    "",    "",
118    "",    "",    "",    "",    "",    "",    "",    "",
119    "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
120    "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
121    "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
122    "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
123  };
124
125  return MakeVector(names, sizeof(names) / sizeof(names[0]));
126}
127
128vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
129  static const char* const kRegisterNames[] = {
130    "$zero", "$at",  "$v0",  "$v1",  "$a0",   "$a1",  "$a2",  "$a3",
131    "$t0",   "$t1",  "$t2",  "$t3",  "$t4",   "$t5",  "$t6",  "$t7",
132    "$s0",   "$s1",  "$s2",  "$s3",  "$s4",   "$s5",  "$s6",  "$s7",
133    "$t8",   "$t9",  "$k0",  "$k1",  "$gp",   "$sp",  "$fp",  "$ra",
134    "$lo",   "$hi",  "$pc",  "$f0",  "$f2",   "$f3",  "$f4",  "$f5",
135    "$f6",   "$f7",  "$f8",  "$f9",  "$f10",  "$f11", "$f12", "$f13",
136    "$f14",  "$f15", "$f16", "$f17", "$f18",  "$f19", "$f20",
137    "$f21",  "$f22", "$f23", "$f24", "$f25",  "$f26", "$f27",
138    "$f28",  "$f29", "$f30", "$f31", "$fcsr", "$fir"
139  };
140
141  return MakeVector(kRegisterNames,
142                    sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
143}
144
145bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
146                             uint8 version, const string &augmentation,
147                             unsigned return_address) {
148  assert(!entry_);
149
150  // If dwarf2reader::CallFrameInfo can handle this version and
151  // augmentation, then we should be okay with that, so there's no
152  // need to check them here.
153
154  // Get ready to collect entries.
155  entry_ = new Module::StackFrameEntry;
156  entry_->address = address;
157  entry_->size = length;
158  entry_offset_ = offset;
159  return_address_ = return_address;
160
161  // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
162  // may not establish any rule for .ra if the return address column
163  // is an ordinary register, and that register holds the return
164  // address on entry to the function. So establish an initial .ra
165  // rule citing the return address register.
166  if (return_address_ < register_names_.size())
167    entry_->initial_rules[ra_name_] = register_names_[return_address_];
168
169  return true;
170}
171
172string DwarfCFIToModule::RegisterName(int i) {
173  assert(entry_);
174  if (i < 0) {
175    assert(i == kCFARegister);
176    return cfa_name_;
177  }
178  unsigned reg = i;
179  if (reg == return_address_)
180    return ra_name_;
181
182  // Ensure that a non-empty name exists for this register value.
183  if (reg < register_names_.size() && !register_names_[reg].empty())
184    return register_names_[reg];
185
186  reporter_->UnnamedRegister(entry_offset_, reg);
187  char buf[30];
188  sprintf(buf, "unnamed_register%u", reg);
189  return buf;
190}
191
192void DwarfCFIToModule::Record(Module::Address address, int reg,
193                              const string &rule) {
194  assert(entry_);
195
196  // Place the name in our global set of strings, and then use the string
197  // from the set. Even though the assignment looks like a copy, all the
198  // major std::string implementations use reference counting internally,
199  // so the effect is to have all our data structures share copies of rules
200  // whenever possible. Since register names are drawn from a
201  // vector<string>, register names are already shared.
202  string shared_rule = *common_strings_.insert(rule).first;
203
204  // Is this one of this entry's initial rules?
205  if (address == entry_->address)
206    entry_->initial_rules[RegisterName(reg)] = shared_rule;
207  // File it under the appropriate address.
208  else
209    entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
210}
211
212bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
213  reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
214  // Treat this as a non-fatal error.
215  return true;
216}
217
218bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
219  ostringstream s;
220  s << RegisterName(reg);
221  Record(address, reg, s.str());
222  return true;
223}
224
225bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
226                                  int base_register, long offset) {
227  ostringstream s;
228  s << RegisterName(base_register) << " " << offset << " + ^";
229  Record(address, reg, s.str());
230  return true;
231}
232
233bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
234                                     int base_register, long offset) {
235  ostringstream s;
236  s << RegisterName(base_register) << " " << offset << " +";
237  Record(address, reg, s.str());
238  return true;
239}
240
241bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
242                                    int base_register) {
243  ostringstream s;
244  s << RegisterName(base_register);
245  Record(address, reg, s.str());
246  return true;
247}
248
249bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
250                                      const string &expression) {
251  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
252  // Treat this as a non-fatal error.
253  return true;
254}
255
256bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
257                                         const string &expression) {
258  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
259  // Treat this as a non-fatal error.
260  return true;
261}
262
263bool DwarfCFIToModule::End() {
264  module_->AddStackFrameEntry(entry_);
265  entry_ = NULL;
266  return true;
267}
268
269void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
270  fprintf(stderr, "%s, section '%s': "
271          "the call frame entry at offset 0x%zx refers to register %d,"
272          " whose name we don't know\n",
273          file_.c_str(), section_.c_str(), offset, reg);
274}
275
276void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
277                                                       const string &reg) {
278  fprintf(stderr, "%s, section '%s': "
279          "the call frame entry at offset 0x%zx sets the rule for "
280          "register '%s' to 'undefined', but the Breakpad symbol file format"
281          " cannot express this\n",
282          file_.c_str(), section_.c_str(), offset, reg.c_str());
283}
284
285void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
286                                                         const string &reg) {
287  fprintf(stderr, "%s, section '%s': "
288          "the call frame entry at offset 0x%zx uses a DWARF expression to"
289          " describe how to recover register '%s', "
290          " but this translator cannot yet translate DWARF expressions to"
291          " Breakpad postfix expressions\n",
292          file_.c_str(), section_.c_str(), offset, reg.c_str());
293}
294
295} // namespace google_breakpad
296