Add error propagation into Unwinder/Elf objects.

The backtrace offline code uses these error codes to diagnose errors.
In addtion, I've had cases where seeing these errors would help diagnose
failures.

This also allows us to add a few features to indicate why an unwind
terminated (such as max frames exceeded).

Bug: 65682279

Test: Updated unit tests pass.
Change-Id: If82b5092698e8a194016d670efff1320f9b44d50
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index caad131..8d0f0e5 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -257,22 +257,27 @@
 TEST_F(ArmExidxExtractTest, read_failures) {
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5004U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5000, 0x100);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5004U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5004, 0x100);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5104U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5104, 0x1);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x5108U, exidx_->status_address());
 
   elf_memory_.SetData32(0x5108, 0x01010203);
   ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
   ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
+  EXPECT_EQ(0x510cU, exidx_->status_address());
 }
 
 TEST_F(ArmExidxExtractTest, malformed) {
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 73a67ac..68dc30c 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -21,13 +21,13 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
 #include <unwindstack/Log.h>
 
 #include "DwarfCfa.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -78,7 +78,7 @@
     dwarf_loc_regs_t loc_regs;
 
     ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
     ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
 
     ASSERT_EQ("", GetFakeLogPrint());
@@ -198,7 +198,7 @@
   dwarf_loc_regs_t loc_regs;
 
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
   ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
   ASSERT_EQ(0U, loc_regs.size());
 
@@ -227,7 +227,7 @@
   dwarf_loc_regs_t loc_regs;
 
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
   ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
   ASSERT_EQ(0U, loc_regs.size());
 
@@ -594,7 +594,7 @@
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
   ASSERT_EQ(0U, loc_regs.size());
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
             GetFakeLogPrint());
@@ -637,7 +637,7 @@
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
   ASSERT_EQ(0U, loc_regs.size());
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
             GetFakeLogPrint());
@@ -679,7 +679,7 @@
 
   // This fails because the cfa is not defined as a register.
   ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
 
   ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
             GetFakeLogPrint());
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 243198e..c28a41e 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfDebugFrame.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -142,7 +143,7 @@
   this->memory_.SetData32(0x510c, 0x200);
 
   ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
@@ -267,7 +268,7 @@
   this->memory_.SetData64(0x511c, 0x200);
 
   ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
@@ -404,11 +405,11 @@
   this->debug_frame_->TestSetFdeCount(0);
   uint64_t fde_offset;
   ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
 
   this->debug_frame_->TestSetFdeCount(9);
   ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   // Odd number of elements.
   for (size_t i = 0; i < 9; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -422,7 +423,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   }
 
   // Even number of elements.
@@ -444,7 +445,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
   }
 }
 
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 3a629f8..a73db65 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfEhFrame.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -142,7 +143,7 @@
   this->memory_.SetData32(0x510c, 0x200);
 
   ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init64) {
@@ -228,7 +229,7 @@
   this->memory_.SetData64(0x511c, 0x200);
 
   ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
@@ -320,11 +321,11 @@
   this->eh_frame_->TestSetFdeCount(0);
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 
   this->eh_frame_->TestSetFdeCount(9);
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   // Odd number of elements.
   for (size_t i = 0; i < 9; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -337,7 +338,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   }
 
   // Even number of elements.
@@ -358,7 +359,7 @@
     EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
     ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
         << "Failed at index " << i;
-    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   }
 }
 
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index ef2fb32..a2ae5eb 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -19,9 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
+
 #include "DwarfEhFrameWithHdr.h"
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -97,25 +98,29 @@
   // Verify a zero fde count fails to init.
   this->memory_.SetData32(0x1006, 0);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
-  ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->LastErrorCode());
 
   // Verify an unexpected version will cause a fail.
   this->memory_.SetData32(0x1006, 126);
   this->memory_.SetData8(0x1000, 0);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
-  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
   this->memory_.SetData8(0x1000, 2);
   ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100));
-  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
   this->eh_frame_->TestSetTableEntrySize(0x10);
   this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
+  this->eh_frame_->TestSetEntriesOffset(0x1000);
+
   ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+  EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
   ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
+  EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
@@ -184,7 +189,7 @@
   uint64_t fde_offset;
   EXPECT_FALSE(this->eh_frame_->GetFdeOffsetBinary(0x100, &fde_offset, 10));
   // Not an error, just not found.
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
   // Even number of elements.
   for (size_t i = 0; i < 10; i++) {
     TypeParam pc = 0x1000 * (i + 1);
@@ -280,7 +285,7 @@
 
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetSequential(0x540, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
@@ -288,7 +293,7 @@
 
   uint64_t fde_offset;
   ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_binary_search) {
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index 234d1c9..3f09dd8 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -21,11 +21,11 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/Log.h>
 #include <unwindstack/Regs.h>
 
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 #include "MemoryFake.h"
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 2d5007b..036226d 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -21,10 +21,10 @@
 
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/Log.h>
 
-#include "DwarfError.h"
 #include "DwarfOp.h"
 
 #include "MemoryFake.h"
@@ -53,13 +53,14 @@
 TYPED_TEST_P(DwarfOpTest, decode) {
   // Memory error.
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0U, this->op_->LastErrorAddress());
 
   // No error.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x96});
   this->mem_->set_cur_offset(0);
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
   ASSERT_EQ(0x96U, this->op_->cur_op());
   ASSERT_EQ(1U, this->mem_->cur_offset());
 }
@@ -67,7 +68,8 @@
 TYPED_TEST_P(DwarfOpTest, eval) {
   // Memory error.
   ASSERT_FALSE(this->op_->Eval(0, 2, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0U, this->op_->LastErrorAddress());
 
   // Register set.
   // Do this first, to verify that subsequent calls reset the value.
@@ -84,7 +86,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_TRUE(this->op_->Eval(0, 8, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
   ASSERT_FALSE(this->op_->is_register());
   ASSERT_EQ(8U, this->mem_->cur_offset());
   ASSERT_EQ(4U, this->op_->StackSize());
@@ -96,7 +98,7 @@
   // Infinite loop.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x2f, 0xfd, 0xff});
   ASSERT_FALSE(this->op_->Eval(0, 4, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->LastErrorCode());
   ASSERT_FALSE(this->op_->is_register());
   ASSERT_EQ(0U, this->op_->StackSize());
 }
@@ -111,7 +113,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -122,7 +124,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(2));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -133,7 +135,7 @@
 
   for (size_t i = 0; i < opcode_buffer.size(); i++) {
     ASSERT_FALSE(this->op_->Decode(3));
-    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
     ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
   }
 }
@@ -178,7 +180,7 @@
 
   while (this->mem_->cur_offset() < opcode_buffer.size()) {
     ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-    ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode());
   }
 }
 
@@ -216,7 +218,7 @@
   this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -226,7 +228,8 @@
   ASSERT_EQ(value, this->op_->StackAt(0));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_deref_size) {
@@ -235,7 +238,7 @@
   this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Read all byte sizes up to the sizeof the type.
   for (size_t i = 1; i < sizeof(TypeParam); i++) {
@@ -252,17 +255,18 @@
   // Zero byte read.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, 0x00});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 
   // Read too many bytes.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, sizeof(TypeParam) + 1});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 
   // Force bad memory read.
   this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x40, 0x94, 0x01});
   ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
+  EXPECT_EQ(0x4010U, this->op_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfOpTest, const_unsigned) {
@@ -529,7 +533,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x12, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -577,7 +581,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x13, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_over) {
@@ -612,7 +616,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x14, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_pick) {
@@ -654,7 +658,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x15, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_swap) {
@@ -686,7 +690,7 @@
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(0x16, this->op_->cur_op());
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_rot) {
@@ -703,19 +707,19 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(3U, this->op_->StackSize());
@@ -753,7 +757,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -805,13 +809,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Two positive values.
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -854,7 +858,7 @@
   ASSERT_EQ(5U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_div) {
@@ -871,13 +875,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -902,13 +906,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -935,13 +939,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -957,7 +961,7 @@
   ASSERT_EQ(3U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_mul) {
@@ -974,13 +978,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1003,7 +1007,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1034,7 +1038,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1067,13 +1071,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1098,13 +1102,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1125,7 +1129,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
@@ -1150,13 +1154,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1181,13 +1185,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1216,13 +1220,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1247,13 +1251,13 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(1U, this->op_->StackSize());
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
   ASSERT_EQ(2U, this->op_->StackSize());
@@ -1280,7 +1284,7 @@
   this->op_memory_.SetMemory(0, opcode_buffer);
 
   ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
   // Push on a non-zero value with a positive branch.
   ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
@@ -1342,12 +1346,12 @@
 
     ASSERT_FALSE(this->op_->Eval(0, 1, DWARF_VERSION_MAX));
     ASSERT_EQ(opcode, this->op_->cur_op());
-    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
 
     ASSERT_FALSE(this->op_->Eval(1, 4, DWARF_VERSION_MAX));
     ASSERT_EQ(opcode, this->op_->cur_op());
     ASSERT_EQ(1U, this->op_->StackSize());
-    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->last_error());
+    ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
   }
 }
 
@@ -1532,7 +1536,7 @@
 
   // Should fail since this references a non-existent register.
   ASSERT_FALSE(this->op_->Eval(2, 4, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_bregx) {
@@ -1560,7 +1564,7 @@
   ASSERT_EQ(0x90U, this->op_->StackAt(0));
 
   ASSERT_FALSE(this->op_->Eval(7, 12, DWARF_VERSION_MAX));
-  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->last_error());
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfOpTest, op_nop) {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index dfd2ce0..7e10935 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -19,10 +19,10 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfSection.h>
 
 #include "DwarfEncoding.h"
-#include "DwarfError.h"
 
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -67,7 +67,7 @@
   }
   void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
 
-  void TestClearError() { this->last_error_ = DWARF_ERROR_NONE; }
+  void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
 };
 
 template <typename TypeParam>
@@ -102,7 +102,8 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x5000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
@@ -118,7 +119,7 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
@@ -172,7 +173,7 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) {
@@ -182,7 +183,7 @@
 
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) {
@@ -192,7 +193,7 @@
 
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) {
@@ -203,25 +204,25 @@
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 
   this->section_->TestClearError();
   loc_regs.erase(CFA_REG);
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) {
@@ -341,7 +342,7 @@
   loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}};
   bool finished;
   ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) {
@@ -489,10 +490,12 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
   ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
@@ -518,24 +521,24 @@
   EXPECT_EQ(4U, cie->code_alignment_factor);
   EXPECT_EQ(8, cie->data_alignment_factor);
   EXPECT_EQ(0x20U, cie->return_address_register);
-  EXPECT_EQ(DWARF_ERROR_NONE, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
 
   this->section_->TestClearCachedCieEntry();
   // Set version to 0, 2, 5 and verify we fail.
   this->memory_.SetData8(0x5008, 0x0);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 
   this->memory_.SetData8(0x5008, 0x2);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 
   this->memory_.SetData8(0x5008, 0x5);
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
@@ -681,10 +684,12 @@
 
 TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
   ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
   this->section_->TestClearError();
   ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
-  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->last_error());
+  EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+  EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 099026c..e232986 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -87,6 +87,10 @@
     steps_.clear();
   }
 
+  void FakeSetErrorCode(ErrorCode code) { last_error_.code = code; }
+
+  void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; }
+
  private:
   std::unordered_map<std::string, uint64_t> globals_;
 
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index e6763ab..31d6a63 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -303,6 +303,7 @@
   // FindEntry fails.
   bool finished;
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, nullptr, nullptr, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // ExtractEntry should fail.
   interface.FakeSetStartOffset(0x1000);
@@ -316,14 +317,18 @@
   regs.set_sp(regs[ARM_REG_SP]);
   regs.set_pc(0x1234);
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode());
+  EXPECT_EQ(0x1004U, interface.LastErrorAddress());
 
   // Eval should fail.
   memory_.SetData32(0x1004, 0x81000000);
   ASSERT_FALSE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // Everything should pass.
   memory_.SetData32(0x1004, 0x80b0b0b0);
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
   ASSERT_FALSE(finished);
   ASSERT_EQ(0x1000U, regs.sp());
   ASSERT_EQ(0x1000U, regs[ARM_REG_SP]);
@@ -332,9 +337,11 @@
 
   // Load bias is non-zero.
   ASSERT_TRUE(interface.StepExidx(0x8000, 0x1000, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 
   // Pc too small.
   ASSERT_FALSE(interface.StepExidx(0x8000, 0x9000, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
@@ -356,6 +363,7 @@
   // Everything should pass.
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_FALSE(finished);
   ASSERT_EQ(0x10004U, regs.sp());
   ASSERT_EQ(0x10004U, regs[ARM_REG_SP]);
@@ -379,6 +387,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0x10000U, regs.sp());
   ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -401,6 +410,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0x10000U, regs.sp());
   ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
@@ -427,6 +437,7 @@
 
   bool finished;
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0U, regs.pc());
 
@@ -439,6 +450,7 @@
   regs.set_pc(0x1234);
 
   ASSERT_TRUE(interface.StepExidx(0x7000, 0, &regs, &process_memory_, &finished));
+  EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
   ASSERT_TRUE(finished);
   ASSERT_EQ(0U, regs.pc());
 }
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 7e6a62a..eb85033 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -581,4 +581,30 @@
   EXPECT_TRUE(elf.IsValidPc(0x1500));
 }
 
+TEST_F(ElfTest, error_code_not_valid) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(false);
+
+  ErrorData error{ERROR_MEMORY_INVALID, 0x100};
+  elf.GetLastError(&error);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+  EXPECT_EQ(0x100U, error.address);
+}
+
+TEST_F(ElfTest, error_code_valid) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+  elf.FakeSetInterface(interface);
+  interface->FakeSetErrorCode(ERROR_MEMORY_INVALID);
+  interface->FakeSetErrorAddress(0x1000);
+
+  ErrorData error{ERROR_NONE, 0};
+  elf.GetLastError(&error);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
+  EXPECT_EQ(0x1000U, error.address);
+  EXPECT_EQ(ERROR_MEMORY_INVALID, elf.GetLastErrorCode());
+  EXPECT_EQ(0x1000U, elf.GetLastErrorAddress());
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index cd46807..bf2c1d8 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -129,6 +129,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -184,6 +185,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -218,6 +220,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -248,6 +251,7 @@
 
   Unwinder unwinder(20, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
 
@@ -288,6 +292,7 @@
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -346,6 +351,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -392,6 +398,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -410,6 +417,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -423,6 +431,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -457,6 +466,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -517,6 +527,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -552,6 +563,7 @@
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
@@ -607,6 +619,7 @@
 
   Unwinder unwinder(64, &maps_, &regs_, process_memory_);
   unwinder.Unwind();
+  EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
 
   ASSERT_EQ(3U, unwinder.NumFrames());