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