1// Copyright (c) 2010, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31
32// cfi_frame_info.cc: Implementation of CFIFrameInfo class.
33// See cfi_frame_info.h for details.
34
35#include "processor/cfi_frame_info.h"
36
37#include <string.h>
38
39#include <sstream>
40
41#include "common/scoped_ptr.h"
42#include "processor/postfix_evaluator-inl.h"
43
44namespace google_breakpad {
45
46#ifdef _WIN32
47#define strtok_r strtok_s
48#endif
49
50template<typename V>
51bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
52                                  const MemoryRegion &memory,
53                                  RegisterValueMap<V> *caller_registers) const {
54  // If there are not rules for both .ra and .cfa in effect at this address,
55  // don't use this CFI data for stack walking.
56  if (cfa_rule_.empty() || ra_rule_.empty())
57    return false;
58
59  RegisterValueMap<V> working;
60  PostfixEvaluator<V> evaluator(&working, &memory);
61
62  caller_registers->clear();
63
64  // First, compute the CFA.
65  V cfa;
66  working = registers;
67  if (!evaluator.EvaluateForValue(cfa_rule_, &cfa))
68    return false;
69
70  // Then, compute the return address.
71  V ra;
72  working = registers;
73  working[".cfa"] = cfa;
74  if (!evaluator.EvaluateForValue(ra_rule_, &ra))
75    return false;
76
77  // Now, compute values for all the registers register_rules_ mentions.
78  for (RuleMap::const_iterator it = register_rules_.begin();
79       it != register_rules_.end(); it++) {
80    V value;
81    working = registers;
82    working[".cfa"] = cfa;
83    if (!evaluator.EvaluateForValue(it->second, &value))
84      return false;
85    (*caller_registers)[it->first] = value;
86  }
87
88  (*caller_registers)[".ra"] = ra;
89  (*caller_registers)[".cfa"] = cfa;
90
91  return true;
92}
93
94// Explicit instantiations for 32-bit and 64-bit architectures.
95template bool CFIFrameInfo::FindCallerRegs<uint32_t>(
96    const RegisterValueMap<uint32_t> &registers,
97    const MemoryRegion &memory,
98    RegisterValueMap<uint32_t> *caller_registers) const;
99template bool CFIFrameInfo::FindCallerRegs<uint64_t>(
100    const RegisterValueMap<uint64_t> &registers,
101    const MemoryRegion &memory,
102    RegisterValueMap<uint64_t> *caller_registers) const;
103
104string CFIFrameInfo::Serialize() const {
105  std::ostringstream stream;
106
107  if (!cfa_rule_.empty()) {
108    stream << ".cfa: " << cfa_rule_;
109  }
110  if (!ra_rule_.empty()) {
111    if (static_cast<std::streamoff>(stream.tellp()) != 0)
112      stream << " ";
113    stream << ".ra: " << ra_rule_;
114  }
115  for (RuleMap::const_iterator iter = register_rules_.begin();
116       iter != register_rules_.end();
117       ++iter) {
118    if (static_cast<std::streamoff>(stream.tellp()) != 0)
119      stream << " ";
120    stream << iter->first << ": " << iter->second;
121  }
122
123  return stream.str();
124}
125
126bool CFIRuleParser::Parse(const string &rule_set) {
127  size_t rule_set_len = rule_set.size();
128  scoped_array<char> working_copy(new char[rule_set_len + 1]);
129  memcpy(working_copy.get(), rule_set.data(), rule_set_len);
130  working_copy[rule_set_len] = '\0';
131
132  name_.clear();
133  expression_.clear();
134
135  char *cursor;
136  static const char token_breaks[] = " \t\r\n";
137  char *token = strtok_r(working_copy.get(), token_breaks, &cursor);
138
139  for (;;) {
140    // End of rule set?
141    if (!token) return Report();
142
143    // Register/pseudoregister name?
144    size_t token_len = strlen(token);
145    if (token_len >= 1 && token[token_len - 1] == ':') {
146      // Names can't be empty.
147      if (token_len < 2) return false;
148      // If there is any pending content, report it.
149      if (!name_.empty() || !expression_.empty()) {
150        if (!Report()) return false;
151      }
152      name_.assign(token, token_len - 1);
153      expression_.clear();
154    } else {
155      // Another expression component.
156      assert(token_len > 0); // strtok_r guarantees this, I think.
157      if (!expression_.empty())
158        expression_ += ' ';
159      expression_ += token;
160    }
161    token = strtok_r(NULL, token_breaks, &cursor);
162  }
163}
164
165bool CFIRuleParser::Report() {
166  if (name_.empty() || expression_.empty()) return false;
167  if (name_ == ".cfa") handler_->CFARule(expression_);
168  else if (name_ == ".ra") handler_->RARule(expression_);
169  else handler_->RegisterRule(name_, expression_);
170  return true;
171}
172
173void CFIFrameInfoParseHandler::CFARule(const string &expression) {
174  frame_info_->SetCFARule(expression);
175}
176
177void CFIFrameInfoParseHandler::RARule(const string &expression) {
178  frame_info_->SetRARule(expression);
179}
180
181void CFIFrameInfoParseHandler::RegisterRule(const string &name,
182                                            const string &expression) {
183  frame_info_->SetRegisterRule(name, expression);
184}
185
186} // namespace google_breakpad
187