| OLD | NEW |
| 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" | |
| 13 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 12 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
| 14 #include "shared-libraries.h" | 13 #include "shared-libraries.h" |
| 15 #endif | 14 #endif |
| 16 | 15 |
| 17 #include "mozilla/Assertions.h" | 16 #include "mozilla/Assertions.h" |
| 18 #include "mozilla/Attributes.h" | 17 #include "mozilla/Attributes.h" |
| 19 #include "mozilla/IntegerPrintfMacros.h" | 18 #include "mozilla/IntegerPrintfMacros.h" |
| 20 #include "mozilla/Move.h" | 19 #include "mozilla/Move.h" |
| 21 #include "mozilla/Scoped.h" | 20 #include "mozilla/Scoped.h" |
| 22 #include "mozilla/UniquePtr.h" | 21 #include "mozilla/UniquePtr.h" |
| 23 #include "mozilla/MemoryChecking.h" | 22 #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" | |
| 39 #endif | 28 #endif |
| 40 | 29 |
| 41 #if defined(MOZ_VALGRIND) | 30 #if defined(MOZ_VALGRIND) |
| 42 # include <valgrind/valgrind.h> | 31 # include <valgrind/valgrind.h> |
| 43 #endif | 32 #endif |
| 44 | 33 |
| 45 #include <string.h> | 34 #include <string.h> |
| 46 #include <vector> | 35 #include <vector> |
| 36 #include <cstdlib> |
| 47 | 37 |
| 48 #ifdef XP_LINUX | 38 #ifdef XP_LINUX |
| 49 #ifdef ANDROID | 39 #ifdef ANDROID |
| 50 // Android NDK doesn't contain ucontext.h; use Breakpad's copy. | 40 // Android NDK doesn't contain ucontext.h; use Breakpad's copy. |
| 51 # include "common/android/include/sys/ucontext.h" | 41 # include "common/android/include/sys/ucontext.h" |
| 52 #else | 42 #else |
| 53 # include <ucontext.h> | 43 # include <ucontext.h> |
| 54 #endif | 44 #endif |
| 55 #include <unistd.h> | 45 #include <unistd.h> |
| 56 #include <sys/syscall.h> | 46 #include <sys/syscall.h> |
| 57 #endif | 47 #endif |
| 58 | 48 |
| 49 #ifdef __GNUC__ |
| 50 # pragma GCC diagnostic pop // -Wshadow |
| 51 #endif |
| 52 |
| 59 #if defined(XP_LINUX) || defined(XP_MACOSX) | 53 #if defined(XP_LINUX) || defined(XP_MACOSX) |
| 60 #include <pthread.h> | 54 #include <pthread.h> |
| 61 #endif | 55 #endif |
| 62 | 56 |
| 63 #ifdef ANDROID | 57 #ifdef ANDROID |
| 64 #ifndef SYS_gettid | 58 #ifndef SYS_gettid |
| 65 #define SYS_gettid __NR_gettid | 59 #define SYS_gettid __NR_gettid |
| 66 #endif | 60 #endif |
| 67 #if defined(__arm__) && !defined(__NR_rt_tgsigqueueinfo) | 61 #if defined(__arm__) && !defined(__NR_rt_tgsigqueueinfo) |
| 68 // Some NDKs don't define this constant even though the kernel supports it. | 62 // Some NDKs don't define this constant even though the kernel supports it. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 namespace { | 203 namespace { |
| 210 template<typename T> | 204 template<typename T> |
| 211 class ScopedSetPtr | 205 class ScopedSetPtr |
| 212 { | 206 { |
| 213 private: | 207 private: |
| 214 T*& mPtr; | 208 T*& mPtr; |
| 215 public: | 209 public: |
| 216 ScopedSetPtr(T*& p, T* val) : mPtr(p) { mPtr = val; } | 210 ScopedSetPtr(T*& p, T* val) : mPtr(p) { mPtr = val; } |
| 217 ~ScopedSetPtr() { mPtr = nullptr; } | 211 ~ScopedSetPtr() { mPtr = nullptr; } |
| 218 }; | 212 }; |
| 219 } | 213 } // namespace |
| 220 | 214 |
| 221 void | 215 void |
| 222 ThreadStackHelper::GetStack(Stack& aStack) | 216 ThreadStackHelper::GetStack(Stack& aStack) |
| 223 { | 217 { |
| 224 // Always run PrepareStackBuffer first to clear aStack | 218 // Always run PrepareStackBuffer first to clear aStack |
| 225 if (!PrepareStackBuffer(aStack)) { | 219 if (!PrepareStackBuffer(aStack)) { |
| 226 // Skip and return empty aStack | 220 // Skip and return empty aStack |
| 227 return; | 221 return; |
| 228 } | 222 } |
| 229 | 223 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 | 273 |
| 280 FillStackBuffer(); | 274 FillStackBuffer(); |
| 281 FillThreadContext(); | 275 FillThreadContext(); |
| 282 | 276 |
| 283 MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS); | 277 MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS); |
| 284 | 278 |
| 285 #endif | 279 #endif |
| 286 } | 280 } |
| 287 | 281 |
| 288 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 282 #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 | |
| 339 class ThreadStackHelper::ThreadContext final | 283 class ThreadStackHelper::ThreadContext final |
| 340 : public google_breakpad::MemoryRegion | |
| 341 { | 284 { |
| 342 public: | 285 public: |
| 343 #if defined(MOZ_THREADSTACKHELPER_X86) | 286 // TODO: provide per-platform definition of Context. |
| 344 typedef MDRawContextX86 Context; | 287 typedef struct {} Context; |
| 345 #elif defined(MOZ_THREADSTACKHELPER_X64) | 288 |
| 346 typedef MDRawContextAMD64 Context; | |
| 347 #elif defined(MOZ_THREADSTACKHELPER_ARM) | |
| 348 typedef MDRawContextARM Context; | |
| 349 #endif | |
| 350 // Limit copied stack to 4kB | 289 // Limit copied stack to 4kB |
| 351 static const size_t kMaxStackSize = 0x1000; | 290 static const size_t kMaxStackSize = 0x1000; |
| 352 // Limit unwound stack to 32 frames | 291 // Limit unwound stack to 32 frames |
| 353 static const unsigned int kMaxStackFrames = 32; | 292 static const unsigned int kMaxStackFrames = 32; |
| 354 // Whether this structure contains valid data | 293 // Whether this structure contains valid data |
| 355 bool mValid; | 294 bool mValid; |
| 356 // Processor context | 295 // Processor context |
| 357 Context mContext; | 296 Context mContext; |
| 358 // Stack area | 297 // Stack area |
| 359 UniquePtr<uint8_t[]> mStack; | 298 UniquePtr<uint8_t[]> mStack; |
| 360 // Start of stack area | 299 // Start of stack area |
| 361 uintptr_t mStackBase; | 300 uintptr_t mStackBase; |
| 362 // Size of stack area | 301 // Size of stack area |
| 363 size_t mStackSize; | 302 size_t mStackSize; |
| 364 // End of stack area | 303 // End of stack area |
| 365 const void* mStackEnd; | 304 const void* mStackEnd; |
| 366 | 305 |
| 367 ThreadContext() | 306 ThreadContext() |
| 368 : mValid(false) | 307 : mValid(false) |
| 369 , mStackBase(0) | 308 , mStackBase(0) |
| 370 , mStackSize(0) | 309 , mStackSize(0) |
| 371 , mStackEnd(nullptr) {} | 310 , 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 } | |
| 404 }; | 311 }; |
| 405 #endif // MOZ_THREADSTACKHELPER_NATIVE | 312 #endif // MOZ_THREADSTACKHELPER_NATIVE |
| 406 | 313 |
| 407 void | 314 void |
| 408 ThreadStackHelper::GetNativeStack(Stack& aStack) | 315 ThreadStackHelper::GetNativeStack(Stack& aStack) |
| 409 { | 316 { |
| 410 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 317 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
| 411 ThreadContext context; | 318 ThreadContext context; |
| 412 context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize); | 319 context.mStack = MakeUnique<uint8_t[]>(ThreadContext::kMaxStackSize); |
| 413 | 320 |
| 414 ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context); | 321 ScopedSetPtr<ThreadContext> contextPtr(mContextToFill, &context); |
| 415 | 322 |
| 416 // Get pseudostack first and fill the thread context. | 323 // Get pseudostack first and fill the thread context. |
| 417 GetStack(aStack); | 324 GetStack(aStack); |
| 418 NS_ENSURE_TRUE_VOID(context.mValid); | 325 NS_ENSURE_TRUE_VOID(context.mValid); |
| 419 | 326 |
| 420 CodeModulesProvider modulesProvider; | 327 // TODO: walk the saved stack frames. |
| 421 google_breakpad::BasicCodeModules modules(&modulesProvider); | |
| 422 google_breakpad::BasicSourceLineResolver resolver; | |
| 423 google_breakpad::StackFrameSymbolizer symbolizer(nullptr, &resolver); | |
| 424 | |
| 425 #if defined(MOZ_THREADSTACKHELPER_X86) | |
| 426 google_breakpad::StackwalkerX86 stackWalker( | |
| 427 nullptr, &context.mContext, &context, &modules, &symbolizer); | |
| 428 #elif defined(MOZ_THREADSTACKHELPER_X64) | |
| 429 google_breakpad::StackwalkerAMD64 stackWalker( | |
| 430 nullptr, &context.mContext, &context, &modules, &symbolizer); | |
| 431 #elif defined(MOZ_THREADSTACKHELPER_ARM) | |
| 432 google_breakpad::StackwalkerARM stackWalker( | |
| 433 nullptr, &context.mContext, -1, &context, &modules, &symbolizer); | |
| 434 #else | |
| 435 #error "Unsupported architecture" | |
| 436 #endif | |
| 437 | |
| 438 google_breakpad::CallStack callStack; | |
| 439 std::vector<const google_breakpad::CodeModule*> modules_without_symbols; | |
| 440 | |
| 441 google_breakpad::Stackwalker::set_max_frames(ThreadContext::kMaxStackFrames); | |
| 442 google_breakpad::Stackwalker:: | |
| 443 set_max_frames_scanned(ThreadContext::kMaxStackFrames); | |
| 444 | |
| 445 NS_ENSURE_TRUE_VOID(stackWalker.Walk(&callStack, &modules_without_symbols)); | |
| 446 | |
| 447 const std::vector<google_breakpad::StackFrame*>& frames(*callStack.frames()); | |
| 448 for (intptr_t i = frames.size() - 1; i >= 0; i--) { | |
| 449 const google_breakpad::StackFrame& frame = *frames[i]; | |
| 450 if (!frame.module) { | |
| 451 continue; | |
| 452 } | |
| 453 const string& module = frame.module->code_file(); | |
| 454 #if defined(XP_LINUX) || defined(XP_MACOSX) | |
| 455 const char PATH_SEP = '/'; | |
| 456 #elif defined(XP_WIN) | |
| 457 const char PATH_SEP = '\\'; | |
| 458 #endif | |
| 459 const char* const module_basename = strrchr(module.c_str(), PATH_SEP); | |
| 460 const char* const module_name = module_basename ? | |
| 461 module_basename + 1 : module.c_str(); | |
| 462 | |
| 463 char buffer[0x100]; | |
| 464 size_t len = 0; | |
| 465 if (!frame.function_name.empty()) { | |
| 466 len = PR_snprintf(buffer, sizeof(buffer), "%s:%s", | |
| 467 module_name, frame.function_name.c_str()); | |
| 468 } else { | |
| 469 len = PR_snprintf(buffer, sizeof(buffer), "%s:0x%p", | |
| 470 module_name, (intptr_t) | |
| 471 (frame.instruction - frame.module->base_address())); | |
| 472 } | |
| 473 if (len) { | |
| 474 aStack.AppendViaBuffer(buffer, len); | |
| 475 } | |
| 476 } | |
| 477 #endif // MOZ_THREADSTACKHELPER_NATIVE | 328 #endif // MOZ_THREADSTACKHELPER_NATIVE |
| 478 } | 329 } |
| 479 | 330 |
| 480 #ifdef XP_LINUX | 331 #ifdef XP_LINUX |
| 481 | 332 |
| 482 int ThreadStackHelper::sInitialized; | 333 int ThreadStackHelper::sInitialized; |
| 483 int ThreadStackHelper::sFillStackSignum; | 334 int ThreadStackHelper::sFillStackSignum; |
| 484 | 335 |
| 485 void | 336 void |
| 486 ThreadStackHelper::FillStackHandler(int aSignal, siginfo_t* aInfo, | 337 ThreadStackHelper::FillStackHandler(int aSignal, siginfo_t* aInfo, |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 } | 455 } |
| 605 if (!basename) { | 456 if (!basename) { |
| 606 // If the (add-on) script is located under the {profile}/extensions | 457 // If the (add-on) script is located under the {profile}/extensions |
| 607 // directory, extract the path after the /extensions/ part. | 458 // directory, extract the path after the /extensions/ part. |
| 608 basename = GetPathAfterComponent(filename, "/extensions/"); | 459 basename = GetPathAfterComponent(filename, "/extensions/"); |
| 609 } | 460 } |
| 610 if (!basename) { | 461 if (!basename) { |
| 611 // Only keep the file base name for paths outside the above formats. | 462 // Only keep the file base name for paths outside the above formats. |
| 612 basename = strrchr(filename, '/'); | 463 basename = strrchr(filename, '/'); |
| 613 basename = basename ? basename + 1 : filename; | 464 basename = basename ? basename + 1 : filename; |
| 465 // Look for Windows path separator as well. |
| 466 filename = strrchr(basename, '\\'); |
| 467 if (filename) { |
| 468 basename = filename + 1; |
| 469 } |
| 614 } | 470 } |
| 615 | 471 |
| 616 size_t len = PR_snprintf(buffer, sizeof(buffer), "%s:%u", basename, lineno); | 472 size_t len = snprintf_literal(buffer, "%s:%u", basename, lineno); |
| 617 if (len < sizeof(buffer)) { | 473 if (len < sizeof(buffer)) { |
| 618 if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { | 474 if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { |
| 619 return aPrevLabel; | 475 return aPrevLabel; |
| 620 } | 476 } |
| 621 | 477 |
| 622 // Keep track of the required buffer size | 478 // Keep track of the required buffer size |
| 623 aAvailableBufferSize -= (len + 1); | 479 aAvailableBufferSize -= (len + 1); |
| 624 if (aAvailableBufferSize >= 0) { | 480 if (aAvailableBufferSize >= 0) { |
| 625 // Buffer is big enough. | 481 // Buffer is big enough. |
| 626 return mStackToFill->InfallibleAppendViaBuffer(buffer, len); | 482 return mStackToFill->InfallibleAppendViaBuffer(buffer, len); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 } | 550 } |
| 695 | 551 |
| 696 MOZ_ASAN_BLACKLIST void | 552 MOZ_ASAN_BLACKLIST void |
| 697 ThreadStackHelper::FillThreadContext(void* aContext) | 553 ThreadStackHelper::FillThreadContext(void* aContext) |
| 698 { | 554 { |
| 699 #ifdef MOZ_THREADSTACKHELPER_NATIVE | 555 #ifdef MOZ_THREADSTACKHELPER_NATIVE |
| 700 if (!mContextToFill) { | 556 if (!mContextToFill) { |
| 701 return; | 557 return; |
| 702 } | 558 } |
| 703 | 559 |
| 560 #if 0 // TODO: remove dependency on Breakpad structs. |
| 704 #if defined(XP_LINUX) | 561 #if defined(XP_LINUX) |
| 705 const ucontext_t& context = *reinterpret_cast<ucontext_t*>(aContext); | 562 const ucontext_t& context = *reinterpret_cast<ucontext_t*>(aContext); |
| 706 #if defined(MOZ_THREADSTACKHELPER_X86) | 563 #if defined(MOZ_THREADSTACKHELPER_X86) |
| 707 mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; | 564 mContextToFill->mContext.context_flags = MD_CONTEXT_X86_FULL; |
| 708 mContextToFill->mContext.edi = context.uc_mcontext.gregs[REG_EDI]; | 565 mContextToFill->mContext.edi = context.uc_mcontext.gregs[REG_EDI]; |
| 709 mContextToFill->mContext.esi = context.uc_mcontext.gregs[REG_ESI]; | 566 mContextToFill->mContext.esi = context.uc_mcontext.gregs[REG_ESI]; |
| 710 mContextToFill->mContext.ebx = context.uc_mcontext.gregs[REG_EBX]; | 567 mContextToFill->mContext.ebx = context.uc_mcontext.gregs[REG_EBX]; |
| 711 mContextToFill->mContext.edx = context.uc_mcontext.gregs[REG_EDX]; | 568 mContextToFill->mContext.edx = context.uc_mcontext.gregs[REG_EDX]; |
| 712 mContextToFill->mContext.ecx = context.uc_mcontext.gregs[REG_ECX]; | 569 mContextToFill->mContext.ecx = context.uc_mcontext.gregs[REG_ECX]; |
| 713 mContextToFill->mContext.eax = context.uc_mcontext.gregs[REG_EAX]; | 570 mContextToFill->mContext.eax = context.uc_mcontext.gregs[REG_EAX]; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 intptr_t* dst = reinterpret_cast<intptr_t*>(&mContextToFill->mStack[0]); | 708 intptr_t* dst = reinterpret_cast<intptr_t*>(&mContextToFill->mStack[0]); |
| 852 const intptr_t* src = reinterpret_cast<intptr_t*>(sp); | 709 const intptr_t* src = reinterpret_cast<intptr_t*>(sp); |
| 853 for (intptr_t len = stackSize; len > 0; len -= sizeof(*src)) { | 710 for (intptr_t len = stackSize; len > 0; len -= sizeof(*src)) { |
| 854 *(dst++) = *(src++); | 711 *(dst++) = *(src++); |
| 855 } | 712 } |
| 856 #endif | 713 #endif |
| 857 | 714 |
| 858 mContextToFill->mStackBase = uintptr_t(sp); | 715 mContextToFill->mStackBase = uintptr_t(sp); |
| 859 mContextToFill->mStackSize = stackSize; | 716 mContextToFill->mStackSize = stackSize; |
| 860 mContextToFill->mValid = true; | 717 mContextToFill->mValid = true; |
| 718 #endif |
| 861 #endif // MOZ_THREADSTACKHELPER_NATIVE | 719 #endif // MOZ_THREADSTACKHELPER_NATIVE |
| 862 } | 720 } |
| 863 | 721 |
| 864 } // namespace mozilla | 722 } // namespace mozilla |
| 723 |
| OLD | NEW |