Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
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 #include <string.h> | |
31 #include <stdlib.h> | |
32 | |
33 #include <cassert> | |
34 #include <sstream> | |
35 #include <vector> | |
36 | |
37 #include "google_breakpad/processor/network_source_line_resolver.h" | |
38 #include "google_breakpad/processor/stack_frame.h" | |
39 #include "processor/binarystream.h" | |
40 #include "processor/network_interface.h" | |
41 #include "processor/network_source_line_protocol.h" | |
42 #include "processor/logging.h" | |
43 #include "processor/tokenize.h" | |
44 #include "processor/udp_network.h" | |
45 #include "processor/windows_frame_info.h" | |
46 | |
47 namespace google_breakpad { | |
48 | |
49 using std::string; | |
50 using std::vector; | |
51 using std::dec; | |
52 using std::hex; | |
53 using namespace source_line_protocol; | |
54 | |
55 NetworkSourceLineResolver::NetworkSourceLineResolver(const string &server, | |
56 unsigned short port, | |
57 int wait_time) | |
58 : wait_time_(wait_time), | |
59 initialized_(false), | |
60 sequence_(0), | |
61 net_(new UDPNetwork(server, port)) | |
62 { | |
Mark Mentovai
2010/03/02 20:05:55
curly belongs on previous (also at 73 and 79)
| |
63 if (net_->Init(false)) | |
64 initialized_ = true; | |
65 } | |
66 | |
67 NetworkSourceLineResolver::NetworkSourceLineResolver(NetworkInterface *net, | |
68 int wait_time) | |
69 : wait_time_(wait_time), | |
70 initialized_(false), | |
71 sequence_(0), | |
72 net_(net) | |
73 { | |
74 if (net_ && net->Init(false)) | |
75 initialized_ = true; | |
76 } | |
77 | |
78 NetworkSourceLineResolver::~NetworkSourceLineResolver() | |
79 { | |
80 initialized_ = false; | |
81 } | |
82 | |
83 bool NetworkSourceLineResolver::LoadModule(const CodeModule *module, | |
84 const string &map_file) { | |
85 // Just lie here and say it was loaded. The server always loads | |
86 // symbols immediately when they're found, since clients always | |
87 // will want to load them after finding them anyway. Since this class | |
88 // acts as both the symbol supplier and source line resolver, | |
89 // it's just a little optimization. | |
90 return true; | |
91 } | |
92 | |
93 bool NetworkSourceLineResolver::LoadModuleUsingMapBuffer( | |
94 const CodeModule *module, | |
95 const string &map_buffer) { | |
96 // see above | |
97 return true; | |
98 } | |
99 | |
100 void NetworkSourceLineResolver::UnloadModule(const CodeModule *module) | |
101 { | |
102 // no-op | |
103 } | |
104 | |
105 bool NetworkSourceLineResolver::HasModule(const CodeModule *module) { | |
106 if (!initialized_ || !module) | |
107 return false; | |
108 | |
109 // cache seen modules so the network round trip can be skipped | |
110 if (module_cache_.find(module->code_file()) != module_cache_.end()) | |
111 return true; | |
112 | |
113 // also cache modules for which symbols aren't found | |
114 if (no_symbols_cache_.find(module->debug_file() + module->debug_identifier()) | |
115 != no_symbols_cache_.end()) | |
116 return false; | |
117 | |
118 binarystream message; | |
119 message << HAS | |
Mark Mentovai
2010/03/02 20:05:55
This comes out pretty nicely.
| |
120 << module->code_file() | |
121 << module->debug_file() | |
122 << module->debug_identifier(); | |
123 binarystream response; | |
124 bool got_response = SendMessageGetResponse(message, response); | |
125 u_int8_t response_data; | |
126 response >> response_data; | |
127 if (got_response && !response.eof() && response_data == MODULE_LOADED) { | |
128 module_cache_.insert(module->code_file()); | |
129 return true; | |
130 } | |
131 return false; | |
132 } | |
133 | |
134 void NetworkSourceLineResolver::FillSourceLineInfo( | |
135 StackFrame *frame) { | |
136 if (!initialized_) | |
137 return; | |
138 | |
139 // if don't this module isn't loaded, can't fill source line info | |
140 if (!frame->module || | |
141 module_cache_.find(frame->module->code_file()) == module_cache_.end()) | |
142 return; | |
143 | |
144 // if this frame has already been seen, return the cached copy | |
145 if (FindCachedSourceLineInfo(frame)) { | |
146 BPLOG(INFO) << "Using cached source line info"; | |
147 return; | |
148 } | |
149 | |
150 binarystream message; | |
151 message << GET | |
152 << frame->module->code_file() | |
153 << frame->module->debug_file() | |
154 << frame->module->debug_identifier() | |
155 << frame->module->base_address() | |
156 << frame->instruction; | |
157 binarystream response; | |
158 bool got_response = SendMessageGetResponse(message, response); | |
159 if (!got_response) | |
160 return; | |
161 | |
162 string function_name, source_file; | |
163 u_int32_t source_line; | |
164 u_int64_t function_base, source_line_base; | |
165 response >> function_name >> function_base | |
166 >> source_file >> source_line >> source_line_base; | |
167 | |
168 if (response.eof()) { | |
169 BPLOG(ERROR) << "GET response malformed"; | |
170 return; | |
171 } else { | |
172 BPLOG(INFO) << "GET response: " << function_name << " " | |
173 << hex << function_base << " " << source_file << " " | |
174 << dec << source_line << " " << hex | |
175 << source_line_base; | |
176 } | |
177 | |
178 frame->function_name = function_name; | |
179 frame->function_base = function_base; | |
180 frame->source_file_name = source_file; | |
181 frame->source_line = source_line; | |
182 frame->source_line_base = source_line_base; | |
183 | |
184 CacheSourceLineInfo(frame); | |
185 return; | |
186 } | |
187 | |
188 WindowsFrameInfo* | |
189 NetworkSourceLineResolver::FindWindowsFrameInfo(const StackFrame *frame) | |
190 { | |
191 if (!initialized_) | |
192 return NULL; | |
193 | |
194 // if this module isn't loaded, can't get frame info | |
195 if (!frame->module || | |
196 module_cache_.find(frame->module->code_file()) == module_cache_.end()) | |
197 return NULL; | |
198 | |
199 // check the cache first | |
200 WindowsFrameInfo *info = NULL; | |
201 if (FindCachedWindowsFrameInfo(frame, &info)) { | |
202 BPLOG(INFO) << "Using cached windows frame info"; | |
203 return info; | |
204 } | |
205 | |
206 binarystream message; | |
207 message << GETSTACKWIN | |
208 << frame->module->code_file() | |
209 << frame->module->debug_file() | |
210 << frame->module->debug_identifier() | |
211 << frame->module->base_address() | |
212 << frame->instruction; | |
213 binarystream response; | |
214 bool got_response = SendMessageGetResponse(message, response); | |
215 if (!got_response) | |
216 return NULL; | |
217 | |
218 string stack_info; | |
219 response >> stack_info; | |
220 | |
221 if (!stack_info.empty()) { | |
222 int type; | |
223 u_int64_t rva, code_size; | |
224 info = WindowsFrameInfo::ParseFromString(stack_info, | |
225 type, | |
226 rva, | |
227 code_size); | |
228 } | |
229 CacheWindowsFrameInfo(frame, info); | |
230 | |
231 return info; | |
232 } | |
233 | |
234 SymbolSupplier::SymbolResult | |
235 NetworkSourceLineResolver::GetSymbolFile(const CodeModule *module, | |
236 const SystemInfo *system_info, | |
237 string *symbol_file) | |
238 { | |
239 BPLOG_IF(ERROR, !symbol_file) << "NetworkSourceLineResolver::GetSymbolFile " | |
240 "requires |symbol_file|"; | |
241 assert(symbol_file); | |
242 | |
243 if (!initialized_) | |
244 return NOT_FOUND; | |
245 | |
246 if (no_symbols_cache_.find(module->debug_file() + module->debug_identifier()) | |
247 != no_symbols_cache_.end()) | |
248 return NOT_FOUND; | |
249 | |
250 binarystream message; | |
251 message << LOAD | |
252 << module->code_file() | |
253 << module->debug_file() | |
254 << module->debug_identifier(); | |
255 binarystream response; | |
256 bool got_response = SendMessageGetResponse(message, response); | |
257 if (!got_response) { | |
258 // Didn't get a response, which is the same as not having symbols. | |
259 // Don't cache this, though, to force a retry if the client asks for | |
260 // symbols for the same file again. | |
261 return NOT_FOUND; | |
262 } | |
263 u_int8_t response_data; | |
264 response >> response_data; | |
265 | |
266 if (response.eof()) { | |
267 BPLOG(ERROR) << "Malformed LOAD response"; | |
268 return NOT_FOUND; | |
269 } | |
270 | |
271 if (response_data == LOAD_NOT_FOUND || response_data == LOAD_FAIL) { | |
272 // Received NOT or FAIL, symbols not present or failed to load them. | |
273 // Same problem to the client any way you look at it. | |
274 // Cache this module to avoid pointless retry. | |
275 no_symbols_cache_.insert(module->debug_file() + module->debug_identifier()); | |
276 return NOT_FOUND; | |
277 } else if (response_data == LOAD_INTERRUPT) { | |
278 return INTERRUPT; | |
279 } | |
280 | |
281 // otherwise, OK | |
282 module_cache_.insert(module->code_file()); | |
283 *symbol_file = "<loaded on server>"; | |
284 return FOUND; | |
285 } | |
286 | |
287 SymbolSupplier::SymbolResult | |
288 NetworkSourceLineResolver::GetSymbolFile(const CodeModule *module, | |
289 const SystemInfo *system_info, | |
290 string *symbol_file, | |
291 string *symbol_data) | |
292 { | |
293 if(symbol_data) | |
294 symbol_data->clear(); | |
295 return GetSymbolFile(module, system_info, symbol_file); | |
296 } | |
297 | |
298 bool NetworkSourceLineResolver::SendMessageGetResponse( | |
299 const binarystream &message, | |
300 binarystream &response) | |
301 { | |
302 binarystream sequence_stream; | |
303 u_int16_t sent_sequence = sequence_; | |
304 sequence_stream << sequence_; | |
305 ++sequence_; | |
306 string message_string = sequence_stream.str(); | |
307 message_string.append(message.str()); | |
308 BPLOG(INFO) << "Sending " << message_string.length() << " bytes"; | |
309 if (!net_->Send(message_string.c_str(), message_string.length())) | |
310 return false; | |
311 | |
312 bool done = false; | |
313 while (!done) { | |
314 if (!net_->WaitToReceive(wait_time_)) | |
315 return false; | |
316 | |
317 vector<char> buffer(1024); | |
318 ssize_t received_bytes; | |
319 if (!net_->Receive(&buffer[0], buffer.size(), received_bytes)) | |
320 return false; | |
321 | |
322 BPLOG(INFO) << "received " << received_bytes << " bytes"; | |
323 buffer.resize(received_bytes); | |
324 | |
325 response.str(string(&buffer[0], buffer.size())); | |
326 response.rewind(); | |
327 u_int16_t read_sequence; | |
328 u_int8_t status; | |
329 response >> read_sequence >> status; | |
330 if (response.eof()) { | |
331 BPLOG(ERROR) << "malformed response, missing sequence number or status"; | |
332 return false; | |
333 } | |
334 if (read_sequence < sent_sequence) // old packet | |
335 continue; | |
336 | |
337 if (read_sequence != sent_sequence) { | |
338 // not expecting this packet, just error | |
339 BPLOG(ERROR) << "error, got sequence number " << read_sequence | |
340 << ", expected " << sent_sequence; | |
341 return false; | |
342 } | |
343 | |
344 // This is the expected packet, so even if it's an error this loop is done | |
345 done = true; | |
346 | |
347 if (status != OK) { | |
348 BPLOG(ERROR) << "received an ER response packet"; | |
349 return false; | |
350 } | |
351 // the caller will process the rest of response | |
352 } | |
353 return true; | |
354 } | |
355 | |
356 bool NetworkSourceLineResolver::FindCachedSourceLineInfo(StackFrame *frame) | |
357 const | |
358 { | |
359 SourceCache::const_iterator iter = | |
360 source_line_info_cache_.find(frame->instruction); | |
361 if (iter == source_line_info_cache_.end()) | |
362 return false; | |
363 | |
364 const StackFrame &f = iter->second; | |
365 frame->function_name = f.function_name; | |
366 frame->function_base = f.function_base; | |
367 frame->source_file_name = f.source_file_name; | |
368 frame->source_line = f.source_line; | |
369 frame->source_line_base = f.source_line_base; | |
370 return true; | |
371 } | |
372 | |
373 bool NetworkSourceLineResolver::FindCachedWindowsFrameInfo( | |
374 const StackFrame *frame, | |
375 WindowsFrameInfo **info) const | |
376 { | |
377 WindowsFrameCache::const_iterator iter = | |
378 windows_frame_cache_.find(frame->instruction); | |
379 if (iter == windows_frame_cache_.end()) | |
380 return false; | |
381 | |
382 *info = NULL; | |
383 // have to give the caller a new pointer | |
384 if (iter->second.get()) { | |
385 *info = new WindowsFrameInfo(); | |
386 (*info)->CopyFrom(*(iter->second.get())); | |
387 } | |
388 return true; | |
389 } | |
390 | |
391 void NetworkSourceLineResolver::CacheSourceLineInfo(const StackFrame *frame) | |
392 { | |
393 StackFrame f(*frame); | |
394 // can't hang onto this pointer, the caller owns it | |
395 f.module = NULL; | |
396 source_line_info_cache_[frame->instruction] = f; | |
397 } | |
398 | |
399 void NetworkSourceLineResolver::CacheWindowsFrameInfo( | |
400 const StackFrame *frame, | |
401 const WindowsFrameInfo *info) | |
402 { | |
403 WindowsFrameInfo *new_info = NULL; | |
404 if (info) { | |
405 // the caller owns info, so make a copy | |
406 new_info = new WindowsFrameInfo(); | |
407 new_info->CopyFrom(*info); | |
408 } | |
409 windows_frame_cache_[frame->instruction] = make_linked_ptr(new_info); | |
410 } | |
411 | |
412 } // namespace google_breakpad | |
OLD | NEW |