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 <sstream> |
40 | |
41 | #include "common/scoped_ptr.h" |
42 | #include "processor/postfix_evaluator-inl.h" |
43 | |
44 | namespace google_breakpad { |
45 | |
46 | #ifdef _MSC_VER |
47 | #define strtok_r strtok_s |
48 | #endif |
49 | |
50 | template<typename V> |
51 | bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V>& registers, |
52 | const MemoryRegion& memory, |
53 | RegisterValueMap<V>* caller_registers) const { |
54 | // If there are not rules for both .ra and .cfa in effect at this address, |
55 | // don't use this CFI data for stack walking. |
56 | if (cfa_rule_.empty() || ra_rule_.empty()) |
57 | return false; |
58 | |
59 | RegisterValueMap<V> working; |
60 | PostfixEvaluator<V> evaluator(&working, &memory); |
61 | |
62 | caller_registers->clear(); |
63 | |
64 | // First, compute the CFA. |
65 | V cfa; |
66 | working = registers; |
67 | if (!evaluator.EvaluateForValue(cfa_rule_, &cfa)) |
68 | return false; |
69 | |
70 | // Then, compute the return address. |
71 | V ra; |
72 | working = registers; |
73 | working[".cfa" ] = cfa; |
74 | if (!evaluator.EvaluateForValue(ra_rule_, &ra)) |
75 | return false; |
76 | |
77 | // Now, compute values for all the registers register_rules_ mentions. |
78 | for (RuleMap::const_iterator it = register_rules_.begin(); |
79 | it != register_rules_.end(); it++) { |
80 | V value; |
81 | working = registers; |
82 | working[".cfa" ] = cfa; |
83 | if (!evaluator.EvaluateForValue(it->second, &value)) |
84 | return false; |
85 | (*caller_registers)[it->first] = value; |
86 | } |
87 | |
88 | (*caller_registers)[".ra" ] = ra; |
89 | (*caller_registers)[".cfa" ] = cfa; |
90 | |
91 | return true; |
92 | } |
93 | |
94 | // Explicit instantiations for 32-bit and 64-bit architectures. |
95 | template bool CFIFrameInfo::FindCallerRegs<uint32_t>( |
96 | const RegisterValueMap<uint32_t>& registers, |
97 | const MemoryRegion& memory, |
98 | RegisterValueMap<uint32_t>* caller_registers) const; |
99 | template bool CFIFrameInfo::FindCallerRegs<uint64_t>( |
100 | const RegisterValueMap<uint64_t>& registers, |
101 | const MemoryRegion& memory, |
102 | RegisterValueMap<uint64_t>* caller_registers) const; |
103 | |
104 | string CFIFrameInfo::Serialize() const { |
105 | std::ostringstream stream; |
106 | |
107 | if (!cfa_rule_.empty()) { |
108 | stream << ".cfa: " << cfa_rule_; |
109 | } |
110 | if (!ra_rule_.empty()) { |
111 | if (static_cast<std::streamoff>(stream.tellp()) != 0) |
112 | stream << " " ; |
113 | stream << ".ra: " << ra_rule_; |
114 | } |
115 | for (RuleMap::const_iterator iter = register_rules_.begin(); |
116 | iter != register_rules_.end(); |
117 | ++iter) { |
118 | if (static_cast<std::streamoff>(stream.tellp()) != 0) |
119 | stream << " " ; |
120 | stream << iter->first << ": " << iter->second; |
121 | } |
122 | |
123 | return stream.str(); |
124 | } |
125 | |
126 | bool CFIRuleParser::Parse(const string& rule_set) { |
127 | size_t rule_set_len = rule_set.size(); |
128 | scoped_array<char> working_copy(new char[rule_set_len + 1]); |
129 | memcpy(working_copy.get(), rule_set.data(), rule_set_len); |
130 | working_copy[rule_set_len] = '\0'; |
131 | |
132 | name_.clear(); |
133 | expression_.clear(); |
134 | |
135 | char* cursor; |
136 | static const char token_breaks[] = " \t\r\n" ; |
137 | char* token = strtok_r(working_copy.get(), token_breaks, &cursor); |
138 | |
139 | for (;;) { |
140 | // End of rule set? |
141 | if (!token) return Report(); |
142 | |
143 | // Register/pseudoregister name? |
144 | size_t token_len = strlen(token); |
145 | if (token_len >= 1 && token[token_len - 1] == ':') { |
146 | // Names can't be empty. |
147 | if (token_len < 2) return false; |
148 | // If there is any pending content, report it. |
149 | if (!name_.empty() || !expression_.empty()) { |
150 | if (!Report()) return false; |
151 | } |
152 | name_.assign(token, token_len - 1); |
153 | expression_.clear(); |
154 | } else { |
155 | // Another expression component. |
156 | assert(token_len > 0); // strtok_r guarantees this, I think. |
157 | if (!expression_.empty()) |
158 | expression_ += ' '; |
159 | expression_ += token; |
160 | } |
161 | token = strtok_r(NULL, token_breaks, &cursor); |
162 | } |
163 | } |
164 | |
165 | bool CFIRuleParser::Report() { |
166 | if (name_.empty() || expression_.empty()) return false; |
167 | if (name_ == ".cfa" ) handler_->CFARule(expression_); |
168 | else if (name_ == ".ra" ) handler_->RARule(expression_); |
169 | else handler_->RegisterRule(name_, expression_); |
170 | return true; |
171 | } |
172 | |
173 | void CFIFrameInfoParseHandler::CFARule(const string& expression) { |
174 | frame_info_->SetCFARule(expression); |
175 | } |
176 | |
177 | void CFIFrameInfoParseHandler::RARule(const string& expression) { |
178 | frame_info_->SetRARule(expression); |
179 | } |
180 | |
181 | void CFIFrameInfoParseHandler::RegisterRule(const string& name, |
182 | const string& expression) { |
183 | frame_info_->SetRegisterRule(name, expression); |
184 | } |
185 | |
186 | } // namespace google_breakpad |
187 | |