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> ®isters, 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> ®isters, 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> ®isters, 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