Merge "Revert "delete toolbox/r.c""
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index 5825e6c..46a6f76 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -488,6 +488,27 @@
             demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE"));
 }
 
+TEST(DemangleTest, non_virtual_thunk) {
+  Demangler demangler;
+
+  ASSERT_EQ("non-virtual thunk to one", demangler.Parse("_ZThn0_N3oneE"));
+  ASSERT_EQ("non-virtual thunk to two", demangler.Parse("_ZThn0_3two"));
+  ASSERT_EQ("non-virtual thunk to three", demangler.Parse("_ZTh0_5three"));
+  ASSERT_EQ("non-virtual thunk to four", demangler.Parse("_ZTh_4four"));
+  ASSERT_EQ("non-virtual thunk to five", demangler.Parse("_ZTh0123456789_4five"));
+  ASSERT_EQ("non-virtual thunk to six", demangler.Parse("_ZThn0123456789_3six"));
+
+  ASSERT_EQ("_ZThn0N3oneE", demangler.Parse("_ZThn0N3oneE"));
+  ASSERT_EQ("_ZThn03two", demangler.Parse("_ZThn03two"));
+  ASSERT_EQ("_ZTh05three", demangler.Parse("_ZTh05three"));
+  ASSERT_EQ("_ZTh4four", demangler.Parse("_ZTh4four"));
+  ASSERT_EQ("_ZTh01234567894five", demangler.Parse("_ZTh01234567894five"));
+  ASSERT_EQ("_ZThn01234567893six", demangler.Parse("_ZThn01234567893six"));
+  ASSERT_EQ("_ZT_N3oneE", demangler.Parse("_ZT_N3oneE"));
+  ASSERT_EQ("_ZT0_N3oneE", demangler.Parse("_ZT0_N3oneE"));
+  ASSERT_EQ("_ZTH_N3oneE", demangler.Parse("_ZTH_N3oneE"));
+}
+
 TEST(DemangleTest, demangle) {
   std::string str;
 
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index 18a90b4..af2816c 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -388,7 +388,7 @@
       saves_.pop_back();
     }
 
-    function_name_ = cur_state_.str;
+    function_name_ += cur_state_.str;
     while (!cur_state_.suffixes.empty()) {
       function_suffix_ += cur_state_.suffixes.back();
       cur_state_.suffixes.pop_back();
@@ -786,6 +786,30 @@
 }
 
 const char* Demangler::FindFunctionName(const char* name) {
+  if (*name == 'T') {
+    // non-virtual thunk, verify that it matches one of these patterns:
+    //   Thn[0-9]+_
+    //   Th[0-9]+_
+    //   Thn_
+    //   Th_
+    name++;
+    if (*name != 'h') {
+      return nullptr;
+    }
+    name++;
+    if (*name == 'n') {
+      name++;
+    }
+    while (std::isdigit(*name)) {
+      name++;
+    }
+    if (*name != '_') {
+      return nullptr;
+    }
+    function_name_ = "non-virtual thunk to ";
+    return name + 1;
+  }
+
   if (*name == 'N') {
     parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
     parse_func_ = &Demangler::ParseFunctionName;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c3b1bfb..df755aa 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1354,7 +1354,7 @@
 
 static unsigned fb_get_flash_block_size(Transport* transport, std::string name) {
     std::string sizeString;
-    if (!fb_getvar(transport, name.c_str(), &sizeString)) {
+    if (!fb_getvar(transport, name.c_str(), &sizeString) || sizeString.empty()) {
         /* This device does not report flash block sizes, so return 0 */
         return 0;
     }
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index d17c211..3a38839 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -44,13 +44,13 @@
 #include "UnwindStackMap.h"
 
 bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
-                       std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
-  std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+                       std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
+                       std::vector<std::string>* skip_names) {
   UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
   auto process_memory = stack_map->process_memory();
   unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
                                  regs, stack_map->process_memory());
-  unwinder.Unwind(&skip_names, &stack_map->GetSuffixesToIgnore());
+  unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
 
   if (num_ignore_frames >= unwinder.NumFrames()) {
     frames->resize(0);
@@ -104,7 +104,8 @@
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
-  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+  std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
+  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names);
 }
 
 UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
@@ -124,5 +125,5 @@
   }
 
   error_ = BACKTRACE_UNWIND_NO_ERROR;
-  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
+  return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
 }
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 73a58b5..e073533 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -109,7 +109,8 @@
   virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
 
   static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
-                     std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames);
+                     std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
+                     std::vector<std::string>* skip_names);
 
   // Get the function name and offset into the function given the pc.
   // If the string is empty, then no valid function name was found,