Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(15)

Side by Side Diff: src/processor/network_source_line_resolver.cc

Issue 36001: Implement a network daemon + networked implementation of SymbolSupplier and SourceLineResolver (Closed) Base URL: http://google-breakpad.googlecode.com/svn/trunk/
Patch Set: Updated patch Created 15 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1004:630ec63f810e-tainted