OLD | NEW |
---|---|
1 // Copyright (c) 2009, Google Inc. | 1 // Copyright (c) 2009, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 | 73 |
74 // Resume a thread by detaching from it. | 74 // Resume a thread by detaching from it. |
75 static bool ResumeThread(pid_t pid) { | 75 static bool ResumeThread(pid_t pid) { |
76 return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; | 76 return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; |
77 } | 77 } |
78 | 78 |
79 namespace google_breakpad { | 79 namespace google_breakpad { |
80 | 80 |
81 LinuxDumper::LinuxDumper(int pid) | 81 LinuxDumper::LinuxDumper(int pid) |
82 : pid_(pid), | 82 : pid_(pid), |
83 threads_suspened_(false), | 83 threads_suspended_(false), |
84 threads_(&allocator_, 8), | 84 threads_(&allocator_, 8), |
85 mappings_(&allocator_) { | 85 mappings_(&allocator_) { |
86 } | 86 } |
87 | 87 |
88 bool LinuxDumper::Init() { | 88 bool LinuxDumper::Init() { |
89 return EnumerateThreads(&threads_) && | 89 return EnumerateThreads(&threads_) && |
90 EnumerateMappings(&mappings_); | 90 EnumerateMappings(&mappings_); |
91 } | 91 } |
92 | 92 |
93 bool LinuxDumper::ThreadsSuspend() { | 93 bool LinuxDumper::ThreadsSuspend() { |
94 if (threads_suspened_) | 94 if (threads_suspended_) |
95 return true; | 95 return true; |
96 bool good = true; | 96 bool good = true; |
97 for (size_t i = 0; i < threads_.size(); ++i) | 97 for (size_t i = 0; i < threads_.size(); ++i) |
98 good &= SuspendThread(threads_[i]); | 98 good &= SuspendThread(threads_[i]); |
99 threads_suspened_ = true; | 99 threads_suspended_ = true; |
100 return good; | 100 return good; |
101 } | 101 } |
102 | 102 |
103 bool LinuxDumper::ThreadsResume() { | 103 bool LinuxDumper::ThreadsResume() { |
104 if (!threads_suspened_) | 104 if (!threads_suspended_) |
105 return false; | 105 return false; |
106 bool good = true; | 106 bool good = true; |
107 for (size_t i = 0; i < threads_.size(); ++i) | 107 for (size_t i = 0; i < threads_.size(); ++i) |
108 good &= ResumeThread(threads_[i]); | 108 good &= ResumeThread(threads_[i]); |
109 threads_suspened_ = false; | 109 threads_suspended_ = false; |
110 return good; | 110 return good; |
111 } | 111 } |
112 | 112 |
113 void | 113 void |
114 LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const { | 114 LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const { |
115 assert(path); | 115 assert(path); |
116 if (!path) { | 116 if (!path) { |
117 return; | 117 return; |
118 } | 118 } |
119 | 119 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
273 } | 273 } |
274 } | 274 } |
275 dir_reader->PopEntry(); | 275 dir_reader->PopEntry(); |
276 } | 276 } |
277 | 277 |
278 sys_close(fd); | 278 sys_close(fd); |
279 return true; | 279 return true; |
280 } | 280 } |
281 | 281 |
282 // Read thread info from /proc/$pid/status. | 282 // Read thread info from /proc/$pid/status. |
283 // Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailible, | 283 // Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable, |
284 // these members are set to -1. Returns true iff all three members are | 284 // these members are set to -1. Returns true iff all three members are |
285 // availible. | 285 // available. |
286 bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) { | 286 bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) { |
287 assert(info != NULL); | 287 assert(info != NULL); |
288 char status_path[80]; | 288 char status_path[80]; |
289 BuildProcPath(status_path, tid, "status"); | 289 BuildProcPath(status_path, tid, "status"); |
290 | 290 |
291 const int fd = open(status_path, O_RDONLY); | 291 const int fd = open(status_path, O_RDONLY); |
292 if (fd < 0) | 292 if (fd < 0) |
293 return false; | 293 return false; |
294 | 294 |
295 LineReader* const line_reader = new(allocator_) LineReader(fd); | 295 LineReader* const line_reader = new(allocator_) LineReader(fd); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
330 return false; | 330 return false; |
331 } | 331 } |
332 } | 332 } |
333 #endif | 333 #endif |
334 | 334 |
335 const uint8_t* stack_pointer; | 335 const uint8_t* stack_pointer; |
336 #if defined(__i386) | 336 #if defined(__i386) |
337 memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); | 337 memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); |
338 #elif defined(__x86_64) | 338 #elif defined(__x86_64) |
339 memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); | 339 memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); |
340 #elif defined(__ARM_EABI__) | |
341 memcpy(&stack_pointer, &info->regs.uregs[R13], sizeof(info->regs.uregs[R13])); | |
340 #else | 342 #else |
341 #error "This code hasn't been ported to your platform yet." | 343 #error "This code hasn't been ported to your platform yet." |
342 #endif | 344 #endif |
343 | 345 |
344 if (!GetStackInfo(&info->stack, &info->stack_len, | 346 if (!GetStackInfo(&info->stack, &info->stack_len, |
345 (uintptr_t) stack_pointer)) | 347 (uintptr_t) stack_pointer)) |
346 return false; | 348 return false; |
347 | 349 |
348 return true; | 350 return true; |
349 } | 351 } |
350 | 352 |
351 // Get information about the stack, given the stack pointer. We don't try to | 353 // Get information about the stack, given the stack pointer. We don't try to |
352 // walk the stack since we might not have all the information needed to do | 354 // walk the stack since we might not have all the information needed to do |
353 // unwind. So we just grab, up to, 32k of stack. | 355 // unwind. So we just grab, up to, 32k of stack. |
354 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, | 356 bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, |
355 uintptr_t int_stack_pointer) { | 357 uintptr_t int_stack_pointer) { |
356 #if defined(__i386) || defined(__x86_64) | |
357 static const bool stack_grows_down = true; | |
358 static const uintptr_t page_size = 4096; | |
359 #else | |
360 #error "This code has not been ported to your platform yet." | |
361 #endif | |
362 // Move the stack pointer to the bottom of the page that it's in. | 358 // Move the stack pointer to the bottom of the page that it's in. |
359 const uintptr_t page_size = getpagesize(); | |
360 | |
363 uint8_t* const stack_pointer = | 361 uint8_t* const stack_pointer = |
364 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); | 362 reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1)); |
365 | 363 |
366 // The number of bytes of stack which we try to capture. | 364 // The number of bytes of stack which we try to capture. |
367 static unsigned kStackToCapture = 32 * 1024; | 365 static int kStackToCapture = 32 * 1024; |
368 | 366 |
369 const MappingInfo* mapping = FindMapping(stack_pointer); | 367 const MappingInfo* mapping = FindMapping(stack_pointer); |
370 if (!mapping) | 368 if (!mapping) |
371 return false; | 369 return false; |
372 if (stack_grows_down) { | 370 const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr; |
awong
2010/02/08 20:52:55
so...we're assuming a single stack direction now?
| |
373 const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr; | 371 const ptrdiff_t distance_to_end = |
374 const ptrdiff_t distance_to_end = | 372 static_cast<ptrdiff_t>(mapping->size) - offset; |
375 static_cast<ptrdiff_t>(mapping->size) - offset; | 373 *stack_len = distance_to_end > kStackToCapture ? |
376 *stack_len = distance_to_end > kStackToCapture ? | 374 kStackToCapture : distance_to_end; |
377 kStackToCapture : distance_to_end; | 375 *stack = stack_pointer; |
378 *stack = stack_pointer; | |
379 } else { | |
380 const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr; | |
381 *stack_len = offset > kStackToCapture ? kStackToCapture : offset; | |
382 *stack = stack_pointer - *stack_len; | |
383 } | |
384 | |
385 return true; | 376 return true; |
386 } | 377 } |
387 | 378 |
388 // static | 379 // static |
389 void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src, | 380 void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src, |
390 size_t length) { | 381 size_t length) { |
391 unsigned long tmp; | 382 unsigned long tmp = 55; |
awong
2010/02/08 20:52:55
Magic number alert! What's this number for?
| |
392 size_t done = 0; | 383 size_t done = 0; |
393 static const size_t word_size = sizeof(tmp); | 384 static const size_t word_size = sizeof(tmp); |
394 uint8_t* const local = (uint8_t*) dest; | 385 uint8_t* const local = (uint8_t*) dest; |
395 uint8_t* const remote = (uint8_t*) src; | 386 uint8_t* const remote = (uint8_t*) src; |
396 | 387 |
397 while (done < length) { | 388 while (done < length) { |
398 const size_t l = length - done > word_size ? word_size : length - done; | 389 const size_t l = length - done > word_size ? word_size : length - done; |
399 if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) | 390 if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) { |
400 tmp = 0; | 391 tmp = 0; |
392 } | |
401 memcpy(local + done, &tmp, l); | 393 memcpy(local + done, &tmp, l); |
402 done += l; | 394 done += l; |
403 } | 395 } |
404 } | 396 } |
405 | 397 |
406 // Find the mapping which the given memory address falls in. | 398 // Find the mapping which the given memory address falls in. |
407 const MappingInfo* LinuxDumper::FindMapping(const void* address) const { | 399 const MappingInfo* LinuxDumper::FindMapping(const void* address) const { |
408 const uintptr_t addr = (uintptr_t) address; | 400 const uintptr_t addr = (uintptr_t) address; |
409 | 401 |
410 for (size_t i = 0; i < mappings_.size(); ++i) { | 402 for (size_t i = 0; i < mappings_.size(); ++i) { |
411 const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr); | 403 const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr); |
412 if (addr >= start && addr - start < mappings_[i]->size) | 404 if (addr >= start && addr - start < mappings_[i]->size) |
413 return mappings_[i]; | 405 return mappings_[i]; |
414 } | 406 } |
415 | 407 |
416 return NULL; | 408 return NULL; |
417 } | 409 } |
418 | 410 |
419 } // namespace google_breakpad | 411 } // namespace google_breakpad |
OLD | NEW |