summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/breakpad-patches/16-get-last-error.patch')
-rw-r--r--toolkit/crashreporter/breakpad-patches/16-get-last-error.patch181
1 files changed, 181 insertions, 0 deletions
diff --git a/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch b/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch
new file mode 100644
index 0000000000..96bebbe503
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-patches/16-get-last-error.patch
@@ -0,0 +1,181 @@
+diff --git a/src/google_breakpad/processor/call_stack.h b/src/google_breakpad/processor/call_stack.h
+--- a/src/google_breakpad/processor/call_stack.h
++++ b/src/google_breakpad/processor/call_stack.h
+@@ -62,26 +62,30 @@ class CallStack {
+
+ // Resets the CallStack to its initial empty state
+ void Clear();
+
+ const vector<StackFrame*>* frames() const { return &frames_; }
+
+ // Set the TID associated with this call stack.
+ void set_tid(uint32_t tid) { tid_ = tid; }
++ void set_last_error(uint32_t last_error) { last_error_ = last_error; }
+
+ uint32_t tid() const { return tid_; }
++ uint32_t last_error() const { return last_error_; }
+
+ private:
+ // Stackwalker is responsible for building the frames_ vector.
+ friend class Stackwalker;
+
+ // Storage for pushed frames.
+ vector<StackFrame*> frames_;
+
+ // The TID associated with this call stack. Default to 0 if it's not
+ // available.
+ uint32_t tid_;
++ // The last error the OS set for this thread (win32's GetLastError())
++ uint32_t last_error_;
+ };
+
+ } // namespace google_breakpad
+
+ #endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__
+diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h
+--- a/src/google_breakpad/processor/minidump.h
++++ b/src/google_breakpad/processor/minidump.h
+@@ -279,16 +279,26 @@ class MinidumpMemoryRegion : public Mini
+ class MinidumpThread : public MinidumpObject {
+ public:
+ virtual ~MinidumpThread();
+
+ const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; }
+ // GetMemory may return NULL even if the MinidumpThread is valid,
+ // if the thread memory cannot be read.
+ virtual MinidumpMemoryRegion* GetMemory();
++ // Corresponds to win32's GetLastError function, which records the last
++ // error value set by the OS for this thread. A more useful error message
++ // can be produced by passing this value to FormatMessage:
++ //
++ // https://docs.microsoft.com/windows/win32/debug/retrieving-the-last-error-code
++ //
++ // The value may also be looked up in Microsoft's System Error Codes listing:
++ //
++ // https://docs.microsoft.com/windows/win32/debug/system-error-codes
++ virtual uint32_t GetLastError();
+ // GetContext may return NULL even if the MinidumpThread is valid.
+ virtual MinidumpContext* GetContext();
+
+ // The thread ID is used to determine if a thread is the exception thread,
+ // so a special getter is provided to retrieve this data from the
+ // MDRawThread structure. Returns false if the thread ID cannot be
+ // determined.
+ virtual bool GetThreadID(uint32_t *thread_id) const;
+diff --git a/src/processor/call_stack.cc b/src/processor/call_stack.cc
+--- a/src/processor/call_stack.cc
++++ b/src/processor/call_stack.cc
+@@ -44,11 +44,12 @@ CallStack::~CallStack() {
+
+ void CallStack::Clear() {
+ for (vector<StackFrame *>::const_iterator iterator = frames_.begin();
+ iterator != frames_.end();
+ ++iterator) {
+ delete *iterator;
+ }
+ tid_ = 0;
++ last_error_ = 0;
+ }
+
+ } // namespace google_breakpad
+diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
+--- a/src/processor/minidump.cc
++++ b/src/processor/minidump.cc
+@@ -1567,16 +1567,76 @@ MinidumpMemoryRegion* MinidumpThread::Ge
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
+ return NULL;
+ }
+
+ return memory_;
+ }
+
++uint32_t MinidumpThread::GetLastError() {
++ if (!valid_) {
++ BPLOG(ERROR) << "Cannot retrieve GetLastError() from an invalid thread";
++ return 0;
++ }
++
++ if (!thread_.teb) {
++ BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid TEB pointer";
++ return 0;
++ }
++
++ auto memory = minidump_->GetMemoryList();
++ if (!memory) {
++ BPLOG(ERROR) << "Cannot retrieve GetLastError() without a valid memory list";
++ return 0;
++ }
++
++ auto context = GetContext();
++ if (!context) {
++ BPLOG(ERROR) << "Cannot retrieve GetLastError()'s without a valid context";
++ return 0;
++ }
++
++ uint64_t pointer_width = 0;
++ switch (context_->GetContextCPU()) {
++ case MD_CONTEXT_X86:
++ pointer_width = 4;
++ break;
++ case MD_CONTEXT_AMD64:
++ case MD_CONTEXT_ARM64:
++ pointer_width = 8;
++ break;
++ default:
++ BPLOG(ERROR) << "GetLastError() isn't implemented for this CPU type yet";
++ return 0;
++ }
++
++ auto region = memory->GetMemoryRegionForAddress(thread_.teb);
++ if (!region) {
++ BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump";
++ return 0;
++ }
++
++ // The TEB is opaque but we know the value we want lives at this offset
++ // from reverse engineering.
++ uint64_t offset = pointer_width * 13;
++ uint32_t error = 0;
++ if (!region->GetMemoryAtAddress(thread_.teb + offset, &error)) {
++ BPLOG(ERROR) << "GetLastError()'s memory isn't mapped in this minidump";
++ return 0;
++ }
++
++ if (minidump_->swap()) {
++ Swap(&error);
++ }
++
++ return error;
++}
++
++
+
+ MinidumpContext* MinidumpThread::GetContext() {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
+ return NULL;
+ }
+
+ if (!context_) {
+diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
+--- a/src/processor/minidump_processor.cc
++++ b/src/processor/minidump_processor.cc
+@@ -301,16 +301,17 @@ ProcessResult MinidumpProcessor::Process
+ }
+ } else {
+ // Threads with missing CPU contexts will hit this, but
+ // don't abort processing the rest of the dump just for
+ // one bad thread.
+ BPLOG(ERROR) << "No stackwalker for " << thread_string;
+ }
+ stack->set_tid(thread_id);
++ stack->set_last_error(thread->GetLastError());
+ process_state->threads_.push_back(stack.release());
+ process_state->thread_memory_regions_.push_back(thread_memory);
+ }
+
+ if (interrupted) {
+ BPLOG(INFO) << "Processing interrupted for " << dump->path();
+ return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
+ }