16d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Copyright (c) 2010, Google Inc.
26d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// All rights reserved.
36d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
46d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Redistribution and use in source and binary forms, with or without
56d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// modification, are permitted provided that the following conditions are
66d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// met:
76d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
86d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Redistributions of source code must retain the above copyright
96d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// notice, this list of conditions and the following disclaimer.
106d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Redistributions in binary form must reproduce the above
116d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// copyright notice, this list of conditions and the following disclaimer
126d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// in the documentation and/or other materials provided with the
136d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// distribution.
146d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//     * Neither the name of Google Inc. nor the names of its
156d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// contributors may be used to endorse or promote products derived from
166d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// this software without specific prior written permission.
176d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy//
186d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
196d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
206d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
216d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
226d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
236d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
246d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
256d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// cfi_frame_info.cc: Implementation of CFIFrameInfo class.
336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// See cfi_frame_info.h for details.
346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
35e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek#include "processor/cfi_frame_info.h"
36e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek
37e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek#include <string.h>
38e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek
39b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek#include <sstream>
406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
412cc15ba4327831f917ff55b87e6d5fc3c7750085ted.mielczarek@gmail.com#include "common/scoped_ptr.h"
426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy#include "processor/postfix_evaluator-inl.h"
436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandynamespace google_breakpad {
456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
46f2e56b1fde88a521971cb6e74d53ce6ac04aa186ted.mielczarek@gmail.com#ifdef _WIN32
47f2e56b1fde88a521971cb6e74d53ce6ac04aa186ted.mielczarek@gmail.com#define strtok_r strtok_s
48f2e56b1fde88a521971cb6e74d53ce6ac04aa186ted.mielczarek@gmail.com#endif
49f2e56b1fde88a521971cb6e74d53ce6ac04aa186ted.mielczarek@gmail.com
506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandytemplate<typename V>
516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandybool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                  const MemoryRegion &memory,
536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                  RegisterValueMap<V> *caller_registers) const {
546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // If there are not rules for both .ra and .cfa in effect at this address,
556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // don't use this CFI data for stack walking.
566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  if (cfa_rule_.empty() || ra_rule_.empty())
576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    return false;
586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  RegisterValueMap<V> working;
606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  PostfixEvaluator<V> evaluator(&working, &memory);
616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  caller_registers->clear();
636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // First, compute the CFA.
656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  V cfa;
666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  working = registers;
676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  if (!evaluator.EvaluateForValue(cfa_rule_, &cfa))
686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    return false;
696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Then, compute the return address.
716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  V ra;
726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  working = registers;
736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  working[".cfa"] = cfa;
746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  if (!evaluator.EvaluateForValue(ra_rule_, &ra))
756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    return false;
766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  // Now, compute values for all the registers register_rules_ mentions.
786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  for (RuleMap::const_iterator it = register_rules_.begin();
796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy       it != register_rules_.end(); it++) {
806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    V value;
816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    working = registers;
826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    working[".cfa"] = cfa;
836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    if (!evaluator.EvaluateForValue(it->second, &value))
846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      return false;
856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    (*caller_registers)[it->first] = value;
866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
876d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
886d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  (*caller_registers)[".ra"] = ra;
896d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  (*caller_registers)[".cfa"] = cfa;
906d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
916d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  return true;
926d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
936d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
946d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy// Explicit instantiations for 32-bit and 64-bit architectures.
956162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comtemplate bool CFIFrameInfo::FindCallerRegs<uint32_t>(
966162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    const RegisterValueMap<uint32_t> &registers,
976d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    const MemoryRegion &memory,
986162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    RegisterValueMap<uint32_t> *caller_registers) const;
996162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comtemplate bool CFIFrameInfo::FindCallerRegs<uint64_t>(
1006162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    const RegisterValueMap<uint64_t> &registers,
1016d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    const MemoryRegion &memory,
1026162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.com    RegisterValueMap<uint64_t> *caller_registers) const;
1036d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
104b223627d81c083a64f2ccecf2651a18111421280ted.mielczarekstring CFIFrameInfo::Serialize() const {
105b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  std::ostringstream stream;
106b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek
107b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  if (!cfa_rule_.empty()) {
108b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek    stream << ".cfa: " << cfa_rule_;
109b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  }
110b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  if (!ra_rule_.empty()) {
111089003b7f67758da12b5b8f2c97b4e306259b65ejimblandy    if (static_cast<std::streamoff>(stream.tellp()) != 0)
112b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek      stream << " ";
113b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek    stream << ".ra: " << ra_rule_;
114b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  }
115b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  for (RuleMap::const_iterator iter = register_rules_.begin();
116b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek       iter != register_rules_.end();
117b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek       ++iter) {
118089003b7f67758da12b5b8f2c97b4e306259b65ejimblandy    if (static_cast<std::streamoff>(stream.tellp()) != 0)
119b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek      stream << " ";
120b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek    stream << iter->first << ": " << iter->second;
121b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  }
122b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek
123b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek  return stream.str();
124b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek}
125b223627d81c083a64f2ccecf2651a18111421280ted.mielczarek
1266d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandybool CFIRuleParser::Parse(const string &rule_set) {
1276d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  size_t rule_set_len = rule_set.size();
1286d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  scoped_array<char> working_copy(new char[rule_set_len + 1]);
1296d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  memcpy(working_copy.get(), rule_set.data(), rule_set_len);
1306d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  working_copy[rule_set_len] = '\0';
1316d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1326d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  name_.clear();
1336d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  expression_.clear();
1346d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1356d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  char *cursor;
1366d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  static const char token_breaks[] = " \t\r\n";
1376d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  char *token = strtok_r(working_copy.get(), token_breaks, &cursor);
1386d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1396d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  for (;;) {
1406d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // End of rule set?
1416d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    if (!token) return Report();
1426d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1436d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    // Register/pseudoregister name?
1446d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    size_t token_len = strlen(token);
1456d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    if (token_len >= 1 && token[token_len - 1] == ':') {
1466d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      // Names can't be empty.
1476d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      if (token_len < 2) return false;
1486d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      // If there is any pending content, report it.
1496d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      if (!name_.empty() || !expression_.empty()) {
1506d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy        if (!Report()) return false;
1516d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      }
1526d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      name_.assign(token, token_len - 1);
1536d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      expression_.clear();
1546d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    } else {
1556d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      // Another expression component.
1566d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      assert(token_len > 0); // strtok_r guarantees this, I think.
1576d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      if (!expression_.empty())
1586d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy        expression_ += ' ';
1596d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy      expression_ += token;
1606d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    }
1616d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy    token = strtok_r(NULL, token_breaks, &cursor);
1626d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  }
1636d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1646d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1656d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandybool CFIRuleParser::Report() {
1666d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  if (name_.empty() || expression_.empty()) return false;
1676d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  if (name_ == ".cfa") handler_->CFARule(expression_);
1686d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  else if (name_ == ".ra") handler_->RARule(expression_);
1696d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  else handler_->RegisterRule(name_, expression_);
1706d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  return true;
1716d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1726d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1736d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyvoid CFIFrameInfoParseHandler::CFARule(const string &expression) {
1746d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  frame_info_->SetCFARule(expression);
1756d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1766d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1776d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyvoid CFIFrameInfoParseHandler::RARule(const string &expression) {
1786d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  frame_info_->SetRARule(expression);
1796d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1806d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1816d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandyvoid CFIFrameInfoParseHandler::RegisterRule(const string &name,
1826d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy                                            const string &expression) {
1836d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy  frame_info_->SetRegisterRule(name, expression);
1846d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy}
1856d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy
1866d3a825dbf5b924c2e754309b3008e462af1d8d2jimblandy} // namespace google_breakpad
187