Merge "Change all uintptr_t to uint64_t in API."
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index c1028ef..62a26b3 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -28,13 +28,15 @@
 
 #include "bootimg_utils.h"
 
+#include "fastboot.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
-{
-    strcpy((char*) h->cmdline, cmdline);
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline) {
+    if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline));
+    strcpy(reinterpret_cast<char*>(h->cmdline), cmdline);
 }
 
 boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6175f59..536d64e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -447,8 +447,11 @@
     if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
 
     // Is this actually a boot image?
+    if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr))) {
+        die("cannot load '%s': too short", kernel.c_str());
+    }
     if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
-        if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
+        if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr*>(kdata), cmdline);
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
 
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 441dc81..bbfbdda 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -70,6 +70,7 @@
     back_frame->rel_pc = frame->rel_pc;
     back_frame->pc = frame->pc;
     back_frame->sp = frame->sp;
+    back_frame->dex_pc = frame->dex_pc;
 
     back_frame->func_name = demangle(frame->function_name.c_str());
     back_frame->func_offset = frame->function_offset;
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 18e9f61..1b8ad19 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -81,6 +81,7 @@
   uint64_t rel_pc;        // The relative pc.
   uint64_t sp;            // The top of the stack.
   size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
+  uint64_t dex_pc;        // If non-zero, the Dex PC for the ART interpreter.
   backtrace_map_t map;    // The map associated with the given pc.
   std::string func_name;  // The function name associated with this pc, NULL if not found.
   uint64_t func_offset;  // pc relative to the start of the function, only valid if func_name is not
diff --git a/liblog/Android.bp b/liblog/Android.bp
index eae0b10..7d9e306 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -80,6 +80,10 @@
                 address: false,
             },
         },
+        android_arm: {
+            // TODO: This is to work around b/24465209. Remove after root cause is fixed
+            ldflags: ["-Wl,--hash-style=both"],
+        },
         windows: {
             srcs: ["uio.c"],
             enabled: true,
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 0954187..91d855b 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -34,6 +34,8 @@
 
 namespace unwindstack {
 
+constexpr uint64_t DEX_PC_REG = 0x20444558;
+
 DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
 
 const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -98,6 +100,84 @@
 }
 
 template <typename AddressType>
+struct EvalInfo {
+  const dwarf_loc_regs_t* loc_regs;
+  const DwarfCie* cie;
+  RegsImpl<AddressType>* cur_regs;
+  Memory* regular_memory;
+  AddressType cfa;
+  bool return_address_undefined = false;
+  uint64_t reg_map = 0;
+  AddressType reg_values[64];
+};
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
+                                                 AddressType* reg_ptr, void* info) {
+  EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
+  Memory* regular_memory = eval_info->regular_memory;
+  switch (loc->type) {
+    case DWARF_LOCATION_OFFSET:
+      if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
+        last_error_ = DWARF_ERROR_MEMORY_INVALID;
+        return false;
+      }
+      break;
+    case DWARF_LOCATION_VAL_OFFSET:
+      *reg_ptr = eval_info->cfa + loc->values[0];
+      break;
+    case DWARF_LOCATION_REGISTER: {
+      uint32_t cur_reg = loc->values[0];
+      if (cur_reg >= eval_info->cur_regs->total_regs()) {
+        last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+        return false;
+      }
+      AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
+      const auto& entry = eval_info->loc_regs->find(cur_reg);
+      if (entry != eval_info->loc_regs->end()) {
+        if (!(eval_info->reg_map & (1 << cur_reg))) {
+          eval_info->reg_map |= 1 << cur_reg;
+          eval_info->reg_values[cur_reg] = *cur_reg_ptr;
+          if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
+            return false;
+          }
+        }
+
+        // Use the register value from before any evaluations.
+        *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
+      } else {
+        *reg_ptr = *cur_reg_ptr + loc->values[1];
+      }
+      break;
+    }
+    case DWARF_LOCATION_EXPRESSION:
+    case DWARF_LOCATION_VAL_EXPRESSION: {
+      AddressType value;
+      if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
+        return false;
+      }
+      if (loc->type == DWARF_LOCATION_EXPRESSION) {
+        if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
+          last_error_ = DWARF_ERROR_MEMORY_INVALID;
+          return false;
+        }
+      } else {
+        *reg_ptr = value;
+      }
+      break;
+    }
+    case DWARF_LOCATION_UNDEFINED:
+      if (reg == eval_info->cie->return_address_register) {
+        eval_info->return_address_undefined = true;
+      }
+    default:
+      break;
+  }
+
+  return true;
+}
+
+template <typename AddressType>
 bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
                                          const dwarf_loc_regs_t& loc_regs, Regs* regs,
                                          bool* finished) {
@@ -114,9 +194,13 @@
     return false;
   }
 
+  // Always set the dex pc to zero when evaluating.
+  cur_regs->set_dex_pc(0);
+
   AddressType prev_cfa = regs->sp();
 
-  AddressType cfa;
+  EvalInfo<AddressType> eval_info{
+      .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
   const DwarfLocation* loc = &cfa_entry->second;
   // Only a few location types are valid for the cfa.
   switch (loc->type) {
@@ -129,11 +213,11 @@
       // pointer register does not have any associated location
       // information, use the current cfa value.
       if (regs->sp_reg() == loc->values[0] && loc_regs.count(regs->sp_reg()) == 0) {
-        cfa = prev_cfa;
+        eval_info.cfa = prev_cfa;
       } else {
-        cfa = (*cur_regs)[loc->values[0]];
+        eval_info.cfa = (*cur_regs)[loc->values[0]];
       }
-      cfa += loc->values[1];
+      eval_info.cfa += loc->values[1];
       break;
     case DWARF_LOCATION_EXPRESSION:
     case DWARF_LOCATION_VAL_EXPRESSION: {
@@ -142,12 +226,12 @@
         return false;
       }
       if (loc->type == DWARF_LOCATION_EXPRESSION) {
-        if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
+        if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
           last_error_ = DWARF_ERROR_MEMORY_INVALID;
           return false;
         }
       } else {
-        cfa = value;
+        eval_info.cfa = value;
       }
       break;
     }
@@ -156,81 +240,38 @@
       return false;
   }
 
-  // This code is not guaranteed to work in cases where a register location
-  // is a double indirection to the actual value. For example, if r3 is set
-  // to r5 + 4, and r5 is set to CFA + 4, then this won't necessarily work
-  // because it does not guarantee that r5 is evaluated before r3.
-  // Check that this case does not exist, and error if it does.
-  bool return_address_undefined = false;
   for (const auto& entry : loc_regs) {
-    uint16_t reg = entry.first;
+    uint32_t reg = entry.first;
     // Already handled the CFA register.
     if (reg == CFA_REG) continue;
 
-    if (reg >= cur_regs->total_regs()) {
-      // Skip this unknown register.
+    AddressType* reg_ptr;
+    AddressType dex_pc = 0;
+    if (reg == DEX_PC_REG) {
+      // Special register that indicates this is a dex pc.
+      dex_pc = 0;
+      reg_ptr = &dex_pc;
+    } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
+      // Skip this unknown register, or a register that has already been
+      // processed.
       continue;
+    } else {
+      reg_ptr = &(*cur_regs)[reg];
+      eval_info.reg_map |= 1 << reg;
+      eval_info.reg_values[reg] = *reg_ptr;
     }
 
-    const DwarfLocation* loc = &entry.second;
-    switch (loc->type) {
-      case DWARF_LOCATION_OFFSET:
-        if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
-                                       sizeof(AddressType))) {
-          last_error_ = DWARF_ERROR_MEMORY_INVALID;
-          return false;
-        }
-        break;
-      case DWARF_LOCATION_VAL_OFFSET:
-        (*cur_regs)[reg] = cfa + loc->values[0];
-        break;
-      case DWARF_LOCATION_REGISTER: {
-        uint16_t cur_reg = loc->values[0];
-        if (cur_reg >= cur_regs->total_regs()) {
-          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
-          return false;
-        }
-        if (loc_regs.find(cur_reg) != loc_regs.end()) {
-          // This is a double indirection, a register definition references
-          // another register which is also defined as something other
-          // than a register.
-          log(0,
-              "Invalid indirection: register %d references register %d which is "
-              "not a plain register.\n",
-              reg, cur_reg);
-          last_error_ = DWARF_ERROR_ILLEGAL_STATE;
-          return false;
-        }
-        (*cur_regs)[reg] = (*cur_regs)[cur_reg] + loc->values[1];
-        break;
-      }
-      case DWARF_LOCATION_EXPRESSION:
-      case DWARF_LOCATION_VAL_EXPRESSION: {
-        AddressType value;
-        if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
-          return false;
-        }
-        if (loc->type == DWARF_LOCATION_EXPRESSION) {
-          if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
-            last_error_ = DWARF_ERROR_MEMORY_INVALID;
-            return false;
-          }
-        } else {
-          (*cur_regs)[reg] = value;
-        }
-        break;
-      }
-      case DWARF_LOCATION_UNDEFINED:
-        if (reg == cie->return_address_register) {
-          return_address_undefined = true;
-        }
-      default:
-        break;
+    if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+      return false;
+    }
+
+    if (reg == DEX_PC_REG) {
+      cur_regs->set_dex_pc(dex_pc);
     }
   }
 
   // Find the return address location.
-  if (return_address_undefined) {
+  if (eval_info.return_address_undefined) {
     cur_regs->set_pc(0);
   } else {
     cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
@@ -239,7 +280,7 @@
   // If the pc was set to zero, consider this the final frame.
   *finished = (cur_regs->pc() == 0) ? true : false;
 
-  cur_regs->set_sp(cfa);
+  cur_regs->set_sp(eval_info.cfa);
 
   return true;
 }
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b0a1c0c..d711772 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -40,6 +40,7 @@
   frame->num = frame_num;
   frame->sp = regs_->sp();
   frame->rel_pc = adjusted_rel_pc;
+  frame->dex_pc = regs_->dex_pc();
 
   if (map_info == nullptr) {
     frame->pc = regs_->pc();
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 3467e6a..0881182 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -38,7 +38,7 @@
   uint64_t values[2];
 };
 
-typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
+typedef std::unordered_map<uint32_t, DwarfLocation> dwarf_loc_regs_t;
 
 }  // namespace unwindstack
 
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 10be6b4..e0004aa 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -132,6 +132,8 @@
 
   const DwarfFde* GetFdeFromIndex(size_t index) override;
 
+  bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
+
   bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
             Regs* regs, bool* finished) override;
 
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1904d4d..a5ba7a0 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -57,6 +57,9 @@
   virtual uint64_t pc() = 0;
   virtual uint64_t sp() = 0;
 
+  uint64_t dex_pc() { return dex_pc_; }
+  void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
+
   virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
 
   virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
@@ -79,6 +82,7 @@
   uint16_t total_regs_;
   uint16_t sp_reg_;
   Location return_loc_;
+  uint64_t dex_pc_ = 0;
 };
 
 template <typename AddressType>
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 5adec4f..32858ae 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -41,6 +41,7 @@
   uint64_t rel_pc;
   uint64_t pc;
   uint64_t sp;
+  uint64_t dex_pc;
 
   std::string function_name;
   uint64_t function_offset;
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index d54b0bf..dfd2ce0 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -266,13 +266,67 @@
 
   regs.set_pc(0x100);
   regs.set_sp(0x2000);
+  regs[1] = 0x100;
+  regs[3] = 0x300;
   regs[8] = 0x10;
   loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
-  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}};
-  loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}};
+  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 1}};
+  loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
   bool finished;
-  ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
-  EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x301U, regs[1]);
+  EXPECT_EQ(0x300U, regs[3]);
+  EXPECT_EQ(0x10U, regs[8]);
+  EXPECT_EQ(0x102U, regs[9]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10, 9);
+  dwarf_loc_regs_t loc_regs;
+
+  regs.set_pc(0x100);
+  regs.set_sp(0x2000);
+  regs[0] = 0x10;
+  regs[1] = 0x20;
+  regs[2] = 0x30;
+  regs[3] = 0x40;
+  regs[4] = 0x50;
+  regs[5] = 0x60;
+  regs[8] = 0x20;
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+  loc_regs[2] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
+  loc_regs[3] = DwarfLocation{DWARF_LOCATION_REGISTER, {2, 3}};
+  loc_regs[4] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 4}};
+  loc_regs[5] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 5}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x10U, regs[0]);
+  EXPECT_EQ(0x11U, regs[1]);
+  EXPECT_EQ(0x22U, regs[2]);
+  EXPECT_EQ(0x33U, regs[3]);
+  EXPECT_EQ(0x44U, regs[4]);
+  EXPECT_EQ(0x55U, regs[5]);
+  EXPECT_EQ(0x20U, regs[8]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10, 9);
+  dwarf_loc_regs_t loc_regs;
+
+  regs.set_pc(0x100);
+  regs.set_sp(0x2000);
+  regs[0] = 0x10;
+  regs[8] = 0x20;
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(0x10U, regs[0]);
+  EXPECT_EQ(0x20U, regs[8]);
+  EXPECT_EQ(0x11U, regs.dex_pc());
 }
 
 TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
@@ -840,11 +894,11 @@
     DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
     Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
     Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
-    Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
-    Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
-    GetCie_fail_should_not_cache, GetCie_32_version_check, GetCie_negative_data_alignment_factor,
-    GetCie_64_no_augment, GetCie_augment, GetCie_version_3, GetCie_version_4,
-    GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
+    Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
+    Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
+    Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
+    GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
+    GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
     GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
     GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
     GetCfaLocationInfo_cie_cached, Log);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 07e48af..33e5527 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,8 +96,13 @@
   unwinder.Unwind();
 
   // Print the frames.
+  const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
   for (size_t i = 0; i < unwinder.NumFrames(); i++) {
     printf("%s\n", unwinder.FormatFrame(i).c_str());
+    const unwindstack::FrameData* frame = &frames[i];
+    if (frame->dex_pc != 0) {
+      printf("      dex pc %" PRIx64 "\n", frame->dex_pc);
+    }
   }
 }
 
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 6b50f0c..3bca6c8 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -43,8 +43,8 @@
     },
 }
 
-cc_library {
-    name: "libutils",
+cc_defaults {
+    name: "libutils_defaults",
     vendor_available: true,
     vndk: {
         enabled: true,
@@ -52,29 +52,6 @@
     },
     host_supported: true,
 
-    srcs: [
-        "CallStack.cpp",
-        "FileMap.cpp",
-        "JenkinsHash.cpp",
-        "NativeHandle.cpp",
-        "Printer.cpp",
-        "PropertyMap.cpp",
-        "RefBase.cpp",
-        "SharedBuffer.cpp",
-        "Static.cpp",
-        "StopWatch.cpp",
-        "String8.cpp",
-        "String16.cpp",
-        "StrongPointer.cpp",
-        "SystemClock.cpp",
-        "Threads.cpp",
-        "Timers.cpp",
-        "Tokenizer.cpp",
-        "Unicode.cpp",
-        "VectorImpl.cpp",
-        "misc.cpp",
-    ],
-
     cflags: ["-Wall", "-Werror"],
     include_dirs: ["external/safe-iop/include"],
     header_libs: [
@@ -96,14 +73,9 @@
 
     target: {
         android: {
-            srcs: [
-                "Trace.cpp",
-            ],
-
             cflags: ["-fvisibility=protected"],
 
             shared_libs: [
-                "libbacktrace",
                 "libcutils",
                 "libdl",
                 "libvndksupport",
@@ -113,12 +85,6 @@
                 misc_undefined: ["integer"],
             },
         },
-        linux: {
-            srcs: [
-                "Looper.cpp",
-                "ProcessCallStack.cpp",
-            ],
-        },
 
         host: {
             cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -148,6 +114,75 @@
     },
 }
 
+cc_library {
+    name: "libutils",
+    defaults: ["libutils_defaults"],
+
+    srcs: [
+        "FileMap.cpp",
+        "JenkinsHash.cpp",
+        "NativeHandle.cpp",
+        "Printer.cpp",
+        "PropertyMap.cpp",
+        "RefBase.cpp",
+        "SharedBuffer.cpp",
+        "Static.cpp",
+        "StopWatch.cpp",
+        "String8.cpp",
+        "String16.cpp",
+        "StrongPointer.cpp",
+        "SystemClock.cpp",
+        "Threads.cpp",
+        "Timers.cpp",
+        "Tokenizer.cpp",
+        "Unicode.cpp",
+        "VectorImpl.cpp",
+        "misc.cpp",
+    ],
+
+    target: {
+        android: {
+            srcs: [
+                "Trace.cpp",
+            ],
+        },
+        linux: {
+            srcs: [
+                "Looper.cpp",
+            ],
+        },
+    },
+}
+
+cc_library {
+    name: "libutilscallstack",
+    defaults: ["libutils_defaults"],
+
+    srcs: [
+        "CallStack.cpp",
+    ],
+
+    arch: {
+        mips: {
+            cflags: ["-DALIGN_DOUBLE"],
+        },
+    },
+
+    target: {
+        android: {
+            shared_libs: [
+                "libutils",
+                "libbacktrace",
+            ],
+        },
+        linux: {
+            srcs: [
+                "ProcessCallStack.cpp",
+            ],
+        },
+    },
+}
+
 // Include subdirectory makefiles
 // ============================================================