michael@0: // Copyright (c) 2010, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // cfi_frame_info.cc: Implementation of CFIFrameInfo class. michael@0: // See cfi_frame_info.h for details. michael@0: michael@0: #include "processor/cfi_frame_info.h" michael@0: michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "common/scoped_ptr.h" michael@0: #include "processor/postfix_evaluator-inl.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: #ifdef _WIN32 michael@0: #define strtok_r strtok_s michael@0: #endif michael@0: michael@0: template michael@0: bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap ®isters, michael@0: const MemoryRegion &memory, michael@0: RegisterValueMap *caller_registers) const { michael@0: // If there are not rules for both .ra and .cfa in effect at this address, michael@0: // don't use this CFI data for stack walking. michael@0: if (cfa_rule_.isExprInvalid() || ra_rule_.isExprInvalid()) michael@0: return false; michael@0: michael@0: RegisterValueMap working; michael@0: PostfixEvaluator evaluator(&working, &memory); michael@0: michael@0: caller_registers->clear(); michael@0: michael@0: // First, compute the CFA. michael@0: V cfa; michael@0: working = registers; michael@0: if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) michael@0: return false; michael@0: michael@0: // Then, compute the return address. michael@0: V ra; michael@0: working = registers; michael@0: working.set(ustr__ZDcfa(), cfa); michael@0: if (!evaluator.EvaluateForValue(ra_rule_, &ra)) michael@0: return false; michael@0: michael@0: // Now, compute values for all the registers register_rules_ mentions. michael@0: for (RuleMap::const_iterator it = register_rules_.begin(); michael@0: it != register_rules_.end(); it++) { michael@0: V value; michael@0: working = registers; michael@0: working.set(ustr__ZDcfa(), cfa); michael@0: if (!evaluator.EvaluateForValue(it->second, &value)) michael@0: return false; michael@0: caller_registers->set(it->first, value); michael@0: } michael@0: michael@0: caller_registers->set(ustr__ZDra(), ra); michael@0: caller_registers->set(ustr__ZDcfa(), cfa); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // Explicit instantiations for 32-bit and 64-bit architectures. michael@0: template bool CFIFrameInfo::FindCallerRegs( michael@0: const RegisterValueMap ®isters, michael@0: const MemoryRegion &memory, michael@0: RegisterValueMap *caller_registers) const; michael@0: template bool CFIFrameInfo::FindCallerRegs( michael@0: const RegisterValueMap ®isters, michael@0: const MemoryRegion &memory, michael@0: RegisterValueMap *caller_registers) const; michael@0: michael@0: string CFIFrameInfo::Serialize() const { michael@0: std::ostringstream stream; michael@0: michael@0: if (!cfa_rule_.isExprInvalid()) { michael@0: stream << ".cfa: " << cfa_rule_; michael@0: } michael@0: if (!ra_rule_.isExprInvalid()) { michael@0: if (static_cast(stream.tellp()) != 0) michael@0: stream << " "; michael@0: stream << ".ra: " << ra_rule_; michael@0: } michael@0: michael@0: // Visit the register rules in alphabetical order. Because michael@0: // register_rules_ has the elements in some arbitrary order, michael@0: // get the names out into a vector, sort them, and visit in michael@0: // sorted order. michael@0: std::vector rr_names; michael@0: for (RuleMap::const_iterator iter = register_rules_.begin(); michael@0: iter != register_rules_.end(); michael@0: ++iter) { michael@0: rr_names.push_back(iter->first); michael@0: } michael@0: michael@0: std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString); michael@0: michael@0: // Now visit the register rules in alphabetical order. michael@0: for (std::vector::const_iterator name = rr_names.begin(); michael@0: name != rr_names.end(); michael@0: ++name) { michael@0: const UniqueString* nm = *name; michael@0: Module::Expr rule = register_rules_.find(nm)->second; michael@0: if (static_cast(stream.tellp()) != 0) michael@0: stream << " "; michael@0: stream << FromUniqueString(nm) << ": " << rule; michael@0: } michael@0: michael@0: return stream.str(); michael@0: } michael@0: michael@0: bool CFIRuleParser::Parse(const string &rule_set) { michael@0: size_t rule_set_len = rule_set.size(); michael@0: scoped_array working_copy(new char[rule_set_len + 1]); michael@0: memcpy(working_copy.get(), rule_set.data(), rule_set_len); michael@0: working_copy[rule_set_len] = '\0'; michael@0: michael@0: name_ = ustr__empty(); michael@0: expression_.clear(); michael@0: michael@0: char *cursor; michael@0: static const char token_breaks[] = " \t\r\n"; michael@0: char *token = strtok_r(working_copy.get(), token_breaks, &cursor); michael@0: michael@0: for (;;) { michael@0: // End of rule set? michael@0: if (!token) return Report(); michael@0: michael@0: // Register/pseudoregister name? michael@0: size_t token_len = strlen(token); michael@0: if (token_len >= 1 && token[token_len - 1] == ':') { michael@0: // Names can't be empty. michael@0: if (token_len < 2) return false; michael@0: // If there is any pending content, report it. michael@0: if (name_ != ustr__empty() || !expression_.empty()) { michael@0: if (!Report()) return false; michael@0: } michael@0: name_ = ToUniqueString_n(token, token_len - 1); michael@0: expression_.clear(); michael@0: } else { michael@0: // Another expression component. michael@0: assert(token_len > 0); // strtok_r guarantees this, I think. michael@0: if (!expression_.empty()) michael@0: expression_ += ' '; michael@0: expression_ += token; michael@0: } michael@0: token = strtok_r(NULL, token_breaks, &cursor); michael@0: } michael@0: } michael@0: michael@0: bool CFIRuleParser::Report() { michael@0: if (name_ == ustr__empty() || expression_.empty()) return false; michael@0: if (name_ == ustr__ZDcfa()) handler_->CFARule(expression_); michael@0: else if (name_ == ustr__ZDra()) handler_->RARule(expression_); michael@0: else handler_->RegisterRule(name_, expression_); michael@0: return true; michael@0: } michael@0: michael@0: void CFIFrameInfoParseHandler::CFARule(const string &expression) { michael@0: // 'expression' is a postfix expression string. michael@0: frame_info_->SetCFARule(Module::Expr(expression)); michael@0: } michael@0: michael@0: void CFIFrameInfoParseHandler::RARule(const string &expression) { michael@0: frame_info_->SetRARule(Module::Expr(expression)); michael@0: } michael@0: michael@0: void CFIFrameInfoParseHandler::RegisterRule(const UniqueString* name, michael@0: const string &expression) { michael@0: frame_info_->SetRegisterRule(name, Module::Expr(expression)); michael@0: } michael@0: michael@0: } // namespace google_breakpad