libbacktrace: export offline unwinding failures.

This is to help debugging different offline unwiding failures.

Bug: http://b/69383534
Test: run backtrace_test.
Change-Id: I5ed4837027a9f17d032925e97e9f5927161444b3
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 641f712..e290b84 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -174,11 +174,11 @@
 bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
   if (context == nullptr) {
     BACK_LOGW("The context is needed for offline backtracing.");
-    error_ = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
+    error_.error_code = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
     return false;
   }
   context_ = context;
-  error_ = BACKTRACE_UNWIND_NO_ERROR;
+  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
 
   unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
   unw_cursor_t cursor;
@@ -186,11 +186,11 @@
   if (ret != 0) {
     BACK_LOGW("unw_init_remote failed %d", ret);
     unw_destroy_addr_space(addr_space);
-    error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
+    error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
     return false;
   }
   size_t num_frames = 0;
-  do {
+  while (true) {
     unw_word_t pc;
     ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
     if (ret < 0) {
@@ -224,7 +224,17 @@
     }
     is_debug_frame_used_ = false;
     ret = unw_step(&cursor);
-  } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
+    if (ret <= 0) {
+      if (error_.error_code == BACKTRACE_UNWIND_NO_ERROR) {
+        error_.error_code = BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED;
+      }
+      break;
+    }
+    if (num_frames == MAX_BACKTRACE_FRAMES) {
+      error_.error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
+      break;
+    }
+  }
 
   unw_destroy_addr_space(addr_space);
   context_ = nullptr;
@@ -259,7 +269,12 @@
     return read_size;
   }
   read_size = stack_space_.Read(addr, buffer, bytes);
-  return read_size;
+  if (read_size != 0) {
+    return read_size;
+  }
+  error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
+  error_.error_info.addr = addr;
+  return 0;
 }
 
 bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip,
@@ -267,13 +282,17 @@
   backtrace_map_t map;
   FillInMap(ip, &map);
   if (!BacktraceMap::IsValid(map)) {
+    error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
     return false;
   }
   const std::string& filename = map.name;
   DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename);
   if (debug_frame == nullptr) {
+    error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
     return false;
   }
+  // Each FindProcInfo() is a new attempt to unwind, so reset the reason.
+  error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
 
   eh_frame_hdr_space_.Clear();
   eh_frame_space_.Clear();
@@ -367,6 +386,7 @@
       }
     }
   }
+  error_.error_code = BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED;
   return false;
 }
 
@@ -548,6 +568,10 @@
   UNUSED(value);
   result = false;
 #endif
+  if (!result) {
+    error_.error_code = BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED;
+    error_.error_info.regno = reg;
+  }
   return result;
 }