LEFT | RIGHT |
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ | 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 /* This Source Code Form is subject to the terms of the Mozilla Public | 3 /* This Source Code Form is subject to the terms of the Mozilla Public |
4 * License, v. 2.0. If a copy of the MPL was not distributed with this | 4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | 6 |
7 #include "ThreadStackHelper.h" | 7 #include "ThreadStackHelper.h" |
8 #include "MainThreadUtils.h" | 8 #include "MainThreadUtils.h" |
9 #include "nsJSPrincipals.h" | 9 #include "nsJSPrincipals.h" |
10 #include "nsScriptSecurityManager.h" | 10 #include "nsScriptSecurityManager.h" |
11 #include "jsfriendapi.h" | 11 #include "jsfriendapi.h" |
| 12 #include "prprf.h" |
12 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 13 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
13 #include "shared-libraries.h" | 14 #include "shared-libraries.h" |
14 #endif | 15 #endif |
15 | 16 |
16 #include "mozilla/Assertions.h" | 17 #include "mozilla/Assertions.h" |
17 #include "mozilla/Attributes.h" | 18 #include "mozilla/Attributes.h" |
18 #include "mozilla/IntegerPrintfMacros.h" | 19 #include "mozilla/IntegerPrintfMacros.h" |
19 #include "mozilla/Move.h" | 20 #include "mozilla/Move.h" |
20 #include "mozilla/Scoped.h" | 21 #include "mozilla/Scoped.h" |
21 #include "mozilla/UniquePtr.h" | 22 #include "mozilla/UniquePtr.h" |
22 #include "mozilla/MemoryChecking.h" | 23 #include "mozilla/MemoryChecking.h" |
23 #include "mozilla/Snprintf.h" | 24 |
24 | 25 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
25 #ifdef __GNUC__ | 26 #include "google_breakpad/processor/call_stack.h" |
26 # pragma GCC diagnostic push | 27 #include "google_breakpad/processor/basic_source_line_resolver.h" |
27 # pragma GCC diagnostic ignored "-Wshadow" | 28 #include "google_breakpad/processor/stack_frame_cpu.h" |
| 29 #include "processor/basic_code_module.h" |
| 30 #include "processor/basic_code_modules.h" |
| 31 #endif |
| 32 |
| 33 #if defined(MOZ_THREADSTACKHELPER_X86) |
| 34 #include "processor/stackwalker_x86.h" |
| 35 #elif defined(MOZ_THREADSTACKHELPER_X64) |
| 36 #include "processor/stackwalker_amd64.h" |
| 37 #elif defined(MOZ_THREADSTACKHELPER_ARM) |
| 38 #include "processor/stackwalker_arm.h" |
28 #endif | 39 #endif |
29 | 40 |
30 #if defined(MOZ_VALGRIND) | 41 #if defined(MOZ_VALGRIND) |
31 # include <valgrind/valgrind.h> | 42 # include <valgrind/valgrind.h> |
32 #endif | 43 #endif |
33 | 44 |
34 #include <string.h> | 45 #include <string.h> |
35 #include <vector> | 46 #include <vector> |
36 #include <cstdlib> | |
37 | 47 |
38 #ifdef XP_LINUX | 48 #ifdef XP_LINUX |
39 #ifdef ANDROID | 49 #ifdef ANDROID |
40 // Android NDK doesn't contain ucontext.h; use Breakpad's copy. | 50 // Android NDK doesn't contain ucontext.h; use Breakpad's copy. |
41 # include "common/android/include/sys/ucontext.h" | 51 # include "common/android/include/sys/ucontext.h" |
42 #else | 52 #else |
43 # include <ucontext.h> | 53 # include <ucontext.h> |
44 #endif | 54 #endif |
45 #include <unistd.h> | 55 #include <unistd.h> |
46 #include <sys/syscall.h> | 56 #include <sys/syscall.h> |
47 #endif | |
48 | |
49 #ifdef __GNUC__ | |
50 # pragma GCC diagnostic pop // -Wshadow | |
51 #endif | 57 #endif |
52 | 58 |
53 #if defined(XP_LINUX) || defined(XP_MACOSX) | 59 #if defined(XP_LINUX) || defined(XP_MACOSX) |
54 #include <pthread.h> | 60 #include <pthread.h> |
55 #endif | 61 #endif |
56 | 62 |
57 #ifdef ANDROID | 63 #ifdef ANDROID |
58 #ifndef SYS_gettid | 64 #ifndef SYS_gettid |
59 #define SYS_gettid __NR_gettid | 65 #define SYS_gettid __NR_gettid |
60 #endif | 66 #endif |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 namespace { | 209 namespace { |
204 template<typename T> | 210 template<typename T> |
205 class ScopedSetPtr | 211 class ScopedSetPtr |
206 { | 212 { |
207 private: | 213 private: |
208 T*& mPtr; | 214 T*& mPtr; |
209 public: | 215 public: |
210 ScopedSetPtr(T*& p, T* val) : mPtr(p) { mPtr = val; } | 216 ScopedSetPtr(T*& p, T* val) : mPtr(p) { mPtr = val; } |
211 ~ScopedSetPtr() { mPtr = nullptr; } | 217 ~ScopedSetPtr() { mPtr = nullptr; } |
212 }; | 218 }; |
213 } // namespace | 219 } |
214 | 220 |
215 void | 221 void |
216 ThreadStackHelper::GetStack(Stack& aStack) | 222 ThreadStackHelper::GetStack(Stack& aStack) |
217 { | 223 { |
218 // Always run PrepareStackBuffer first to clear aStack | 224 // Always run PrepareStackBuffer first to clear aStack |
219 if (!PrepareStackBuffer(aStack)) { | 225 if (!PrepareStackBuffer(aStack)) { |
220 // Skip and return empty aStack | 226 // Skip and return empty aStack |
221 return; | 227 return; |
222 } | 228 } |
223 | 229 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 | 279 |
274 FillStackBuffer(); | 280 FillStackBuffer(); |
275 FillThreadContext(); | 281 FillThreadContext(); |
276 | 282 |
277 MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS); | 283 MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS); |
278 | 284 |
279 #endif | 285 #endif |
280 } | 286 } |
281 | 287 |
282 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 288 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
| 289 class ThreadStackHelper::CodeModulesProvider |
| 290 : public google_breakpad::CodeModules |
| 291 { |
| 292 private: |
| 293 typedef google_breakpad::CodeModule CodeModule; |
| 294 typedef google_breakpad::BasicCodeModule BasicCodeModule; |
| 295 |
| 296 const SharedLibraryInfo mLibs; |
| 297 mutable ScopedDeletePtr<BasicCodeModule> mModule; |
| 298 |
| 299 public: |
| 300 CodeModulesProvider() : mLibs(SharedLibraryInfo::GetInfoForSelf()) {} |
| 301 virtual ~CodeModulesProvider() {} |
| 302 |
| 303 virtual unsigned int module_count() const |
| 304 { |
| 305 return mLibs.GetSize(); |
| 306 } |
| 307 |
| 308 virtual const CodeModule* GetModuleForAddress(uint64_t aAddress) const |
| 309 { |
| 310 MOZ_CRASH("Not implemented"); |
| 311 } |
| 312 |
| 313 virtual const CodeModule* GetMainModule() const |
| 314 { |
| 315 return nullptr; |
| 316 } |
| 317 |
| 318 virtual const CodeModule* GetModuleAtSequence(unsigned int aSequence) const |
| 319 { |
| 320 MOZ_CRASH("Not implemented"); |
| 321 } |
| 322 |
| 323 virtual const CodeModule* GetModuleAtIndex(unsigned int aIndex) const |
| 324 { |
| 325 const SharedLibrary& lib = mLibs.GetEntry(aIndex); |
| 326 mModule = new BasicCodeModule(lib.GetStart(), lib.GetEnd() - lib.GetStart(), |
| 327 lib.GetName(), lib.GetBreakpadId(), |
| 328 lib.GetName(), lib.GetBreakpadId(), ""); |
| 329 // Keep mModule valid until the next GetModuleAtIndex call. |
| 330 return mModule; |
| 331 } |
| 332 |
| 333 virtual const CodeModules* Copy() const |
| 334 { |
| 335 MOZ_CRASH("Not implemented"); |
| 336 } |
| 337 }; |
| 338 |
283 class ThreadStackHelper::ThreadContext final | 339 class ThreadStackHelper::ThreadContext final |
| 340 : public google_breakpad::MemoryRegion |
284 { | 341 { |
285 public: | 342 public: |
286 // TODO: provide per-platform definition of Context. | 343 #if defined(MOZ_THREADSTACKHELPER_X86) |
287 typedef struct {} Context; | 344 typedef MDRawContextX86 Context; |
288 | 345 #elif defined(MOZ_THREADSTACKHELPER_X64) |
| 346 typedef MDRawContextAMD64 Context; |
| 347 #elif defined(MOZ_THREADSTACKHELPER_ARM) |
| 348 typedef MDRawContextARM Context; |
| 349 #endif |
289 // Limit copied stack to 4kB | 350 // Limit copied stack to 4kB |
290 static const size_t kMaxStackSize = 0x1000; | 351 static const size_t kMaxStackSize = 0x1000; |
291 // Limit unwound stack to 32 frames | 352 // Limit unwound stack to 32 frames |
292 static const unsigned int kMaxStackFrames = 32; | 353 static const unsigned int kMaxStackFrames = 32; |
293 // Whether this structure contains valid data | 354 // Whether this structure contains valid data |
294 bool mValid; | 355 bool mValid; |
295 // Processor context | 356 // Processor context |
296 Context mContext; | 357 Context mContext; |
297 // Stack area | 358 // Stack area |
298 UniquePtr<uint8_t[]> mStack; | 359 UniquePtr<uint8_t[]> mStack; |
299 // Start of stack area | 360 // Start of stack area |
300 uintptr_t mStackBase; | 361 uintptr_t mStackBase; |
301 // Size of stack area | 362 // Size of stack area |
302 size_t mStackSize; | 363 size_t mStackSize; |
303 // End of stack area | 364 // End of stack area |
304 const void* mStackEnd; | 365 const void* mStackEnd; |
305 | 366 |
306 ThreadContext() | 367 ThreadContext() |
307 : mValid(false) | 368 : mValid(false) |
308 , mStackBase(0) | 369 , mStackBase(0) |
309 , mStackSize(0) | 370 , mStackSize(0) |
310 , mStackEnd(nullptr) {} | 371 , mStackEnd(nullptr) {} |
| 372 virtual ~ThreadContext() {} |
| 373 |
| 374 virtual uint64_t GetBase() const { return uint64_t(mStackBase); } |
| 375 virtual uint32_t GetSize() const { return mStackSize; } |
| 376 virtual bool GetMemoryAtAddress(uint64_t aAddress, uint8_t* aValue) const |
| 377 { |
| 378 return GetMemoryAtAddressInternal(aAddress, aValue); |
| 379 } |
| 380 virtual bool GetMemoryAtAddress(uint64_t aAddress, uint16_t* aValue) const |
| 381 { |
| 382 return GetMemoryAtAddressInternal(aAddress, aValue); |
| 383 } |
| 384 virtual bool GetMemoryAtAddress(uint64_t aAddress, uint32_t* aValue) const |
| 385 { |
| 386 return GetMemoryAtAddressInternal(aAddress, aValue); |
| 387 } |
| 388 virtual bool GetMemoryAtAddress(uint64_t aAddress, uint64_t* aValue) const |
| 389 { |
| 390 return GetMemoryAtAddressInternal(aAddress, aValue); |
| 391 } |
| 392 |
| 393 private: |
| 394 template<typename T> |
| 395 bool GetMemoryAtAddressInternal(uint64_t aAddress, T* aValue) const |
| 396 { |
| 397 const intptr_t offset = intptr_t(aAddress) - intptr_t(GetBase()); |
| 398 if (offset < 0 || uintptr_t(offset) > (GetSize() - sizeof(T))) { |
| 399 return false; |
| 400 } |
| 401 *aValue = *reinterpret_cast<const T*>(&mStack[offset]); |
| 402 return true; |
| 403 } |
311 }; | 404 }; |
312 #endif // MOZ_THREADSTACKHELPER_NATIVE | 405 #endif // MOZ_THREADSTACKHELPER_NATIVE |
313 | 406 |
314 void | 407 void |
315 ThreadStackHelper::GetNativeStack(Stack& aStack) | 408 ThreadStackHelper::GetNativeStack(Stack& aStack) |
316 { | 409 { |
317 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 410 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
318 ThreadContext context; | 411 ThreadContext context; |
319 context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize); | 412 context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize); |
320 | 413 |
321 ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context); | 414 ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context); |
322 | 415 |
323 // Get pseudostack first and fill the thread context. | 416 // Get pseudostack first and fill the thread context. |
324 GetStack(aStack); | 417 GetStack(aStack); |
325 NS_ENSURE_TRUE_VOID(context.mValid); | 418 NS_ENSURE_TRUE_VOID(context.mValid); |
326 | 419 |
327 // TODO: walk the saved stack frames. | |
328 #endif // MOZ_THREADSTACKHELPER_NATIVE | 420 #endif // MOZ_THREADSTACKHELPER_NATIVE |
329 } | 421 } |
330 | 422 |
331 #ifdef XP_LINUX | 423 #ifdef XP_LINUX |
332 | 424 |
333 int ThreadStackHelper::sInitialized; | 425 int ThreadStackHelper::sInitialized; |
334 int ThreadStackHelper::sFillStackSignum; | 426 int ThreadStackHelper::sFillStackSignum; |
335 | 427 |
336 void | 428 void |
337 ThreadStackHelper::FillStackHandler(int aSignal, siginfo_t* aInfo, | 429 ThreadStackHelper::FillStackHandler(int aSignal, siginfo_t* aInfo, |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 } | 547 } |
456 if (!basename) { | 548 if (!basename) { |
457 // If the (add-on) script is located under the {profile}/extensions | 549 // If the (add-on) script is located under the {profile}/extensions |
458 // directory, extract the path after the /extensions/ part. | 550 // directory, extract the path after the /extensions/ part. |
459 basename = GetPathAfterComponent(filename, "/extensions/"); | 551 basename = GetPathAfterComponent(filename, "/extensions/"); |
460 } | 552 } |
461 if (!basename) { | 553 if (!basename) { |
462 // Only keep the file base name for paths outside the above formats. | 554 // Only keep the file base name for paths outside the above formats. |
463 basename = strrchr(filename, '/'); | 555 basename = strrchr(filename, '/'); |
464 basename = basename ? basename + 1 : filename; | 556 basename = basename ? basename + 1 : filename; |
465 // Look for Windows path separator as well. | 557 } |
466 filename = strrchr(basename, '\\'); | 558 |
467 if (filename) { | 559 size_t len = PR_snprintf(buffer, sizeof(buffer), "%s:%u", basename, lineno); |
468 basename = filename + 1; | |
469 } | |
470 } | |
471 | |
472 size_t len = snprintf_literal(buffer, "%s:%u", basename, lineno); | |
473 if (len < sizeof(buffer)) { | 560 if (len < sizeof(buffer)) { |
474 if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { | 561 if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { |
475 return aPrevLabel; | 562 return aPrevLabel; |
476 } | 563 } |
477 | 564 |
478 // Keep track of the required buffer size | 565 // Keep track of the required buffer size |
479 aAvailableBufferSize -= (len + 1); | 566 aAvailableBufferSize -= (len + 1); |
480 if (aAvailableBufferSize >= 0) { | 567 if (aAvailableBufferSize >= 0) { |
481 // Buffer is big enough. | 568 // Buffer is big enough. |
482 return mStackToFill->InfallibleAppendViaBuffer(buffer, len); | 569 return mStackToFill->InfallibleAppendViaBuffer(buffer, len); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 } | 637 } |
551 | 638 |
552 MOZ_ASAN_BLACKLIST void | 639 MOZ_ASAN_BLACKLIST void |
553 ThreadStackHelper::FillThreadContext(void* aContext) | 640 ThreadStackHelper::FillThreadContext(void* aContext) |
554 { | 641 { |
555 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 642 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
556 if (!mContextToFill) { | 643 if (!mContextToFill) { |
557 return; | 644 return; |
558 } | 645 } |
559 | 646 |
560 #if 0 // TODO: remove dependency on Breakpad structs. | |
561 #if defined(XP_LINUX) | 647 #if defined(XP_LINUX) |
562 const ucontext_t& context = *reinterpret_cast<ucontext_t*>(aContext); | 648 const ucontext_t& context = *reinterpret_cast<ucontext_t*>(aContext); |
563 #if defined(MOZ_THREADSTACKHELPER_X86) | 649 #if defined(MOZ_THREADSTACKHELPER_X86) |
564 mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; | 650 mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; |
565 mContextToFill->mContext.edi = context.uc_mcontext.gregs[REG_EDI]; | 651 mContextToFill->mContext.edi = context.uc_mcontext.gregs[REG_EDI]; |
566 mContextToFill->mContext.esi = context.uc_mcontext.gregs[REG_ESI]; | 652 mContextToFill->mContext.esi = context.uc_mcontext.gregs[REG_ESI]; |
567 mContextToFill->mContext.ebx = context.uc_mcontext.gregs[REG_EBX]; | 653 mContextToFill->mContext.ebx = context.uc_mcontext.gregs[REG_EBX]; |
568 mContextToFill->mContext.edx = context.uc_mcontext.gregs[REG_EDX]; | 654 mContextToFill->mContext.edx = context.uc_mcontext.gregs[REG_EDX]; |
569 mContextToFill->mContext.ecx = context.uc_mcontext.gregs[REG_ECX]; | 655 mContextToFill->mContext.ecx = context.uc_mcontext.gregs[REG_ECX]; |
570 mContextToFill->mContext.eax = context.uc_mcontext.gregs[REG_EAX]; | 656 mContextToFill->mContext.eax = context.uc_mcontext.gregs[REG_EAX]; |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 intptr_t* dst = reinterpret_cast<intptr_t*>(&mContextToFill->mStack[0]); | 794 intptr_t* dst = reinterpret_cast<intptr_t*>(&mContextToFill->mStack[0]); |
709 const intptr_t* src = reinterpret_cast<intptr_t*>(sp); | 795 const intptr_t* src = reinterpret_cast<intptr_t*>(sp); |
710 for (intptr_t len = stackSize; len > 0; len -= sizeof(*src)) { | 796 for (intptr_t len = stackSize; len > 0; len -= sizeof(*src)) { |
711 *(dst++) = *(src++); | 797 *(dst++) = *(src++); |
712 } | 798 } |
713 #endif | 799 #endif |
714 | 800 |
715 mContextToFill->mStackBase = uintptr_t(sp); | 801 mContextToFill->mStackBase = uintptr_t(sp); |
716 mContextToFill->mStackSize = stackSize; | 802 mContextToFill->mStackSize = stackSize; |
717 mContextToFill->mValid = true; | 803 mContextToFill->mValid = true; |
718 #endif | |
719 #endif // MOZ_THREADSTACKHELPER_NATIVE | 804 #endif // MOZ_THREADSTACKHELPER_NATIVE |
720 } | 805 } |
721 | 806 |
722 } // namespace mozilla | 807 } // namespace mozilla |
723 | |
LEFT | RIGHT |