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