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 <[email protected]> <[email protected]>
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>
FindCallerRegs(const RegisterValueMap<V> & registers,const MemoryRegion & memory,RegisterValueMap<V> * caller_registers) const54 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
Serialize() const107 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
Parse(const string & rule_set)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
Report()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
CFARule(const string & expression)176 void CFIFrameInfoParseHandler::CFARule(const string& expression) {
177 frame_info_->SetCFARule(expression);
178 }
179
RARule(const string & expression)180 void CFIFrameInfoParseHandler::RARule(const string& expression) {
181 frame_info_->SetRARule(expression);
182 }
183
RegisterRule(const string & name,const string & expression)184 void CFIFrameInfoParseHandler::RegisterRule(const string& name,
185 const string& expression) {
186 frame_info_->SetRegisterRule(name, expression);
187 }
188
189 } // namespace google_breakpad
190