libunwindstack: add method to iterate across registers.

Add a function to iterate over Regs with a human-friendly name and the
value of the register, to make it easy to string-format registers.

Test: mma
Change-Id: I8f33830fa79b245b5030b7bc9bc3c1c7ced80c75
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index f40086e..e687a68 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -122,6 +122,7 @@
         "tests/MemoryRangeTest.cpp",
         "tests/MemoryRemoteTest.cpp",
         "tests/MemoryTest.cpp",
+        "tests/RegsIterateTest.cpp",
         "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 69e6512..bf27d21 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -80,6 +80,25 @@
   return true;
 }
 
+void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("r0", regs_[ARM_REG_R0]);
+  fn("r1", regs_[ARM_REG_R1]);
+  fn("r2", regs_[ARM_REG_R2]);
+  fn("r3", regs_[ARM_REG_R3]);
+  fn("r4", regs_[ARM_REG_R4]);
+  fn("r5", regs_[ARM_REG_R5]);
+  fn("r6", regs_[ARM_REG_R6]);
+  fn("r7", regs_[ARM_REG_R7]);
+  fn("r8", regs_[ARM_REG_R8]);
+  fn("r9", regs_[ARM_REG_R9]);
+  fn("r10", regs_[ARM_REG_R10]);
+  fn("r11", regs_[ARM_REG_R11]);
+  fn("ip", regs_[ARM_REG_R12]);
+  fn("sp", regs_[ARM_REG_SP]);
+  fn("lr", regs_[ARM_REG_LR]);
+  fn("pc", regs_[ARM_REG_PC]);
+}
+
 RegsArm64::RegsArm64()
     : RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
 
@@ -112,6 +131,42 @@
   return true;
 }
 
+void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("x0", regs_[ARM64_REG_R0]);
+  fn("x1", regs_[ARM64_REG_R1]);
+  fn("x2", regs_[ARM64_REG_R2]);
+  fn("x3", regs_[ARM64_REG_R3]);
+  fn("x4", regs_[ARM64_REG_R4]);
+  fn("x5", regs_[ARM64_REG_R5]);
+  fn("x6", regs_[ARM64_REG_R6]);
+  fn("x7", regs_[ARM64_REG_R7]);
+  fn("x8", regs_[ARM64_REG_R8]);
+  fn("x9", regs_[ARM64_REG_R9]);
+  fn("x10", regs_[ARM64_REG_R10]);
+  fn("x11", regs_[ARM64_REG_R11]);
+  fn("x12", regs_[ARM64_REG_R12]);
+  fn("x13", regs_[ARM64_REG_R13]);
+  fn("x14", regs_[ARM64_REG_R14]);
+  fn("x15", regs_[ARM64_REG_R15]);
+  fn("x16", regs_[ARM64_REG_R16]);
+  fn("x17", regs_[ARM64_REG_R17]);
+  fn("x18", regs_[ARM64_REG_R18]);
+  fn("x19", regs_[ARM64_REG_R19]);
+  fn("x20", regs_[ARM64_REG_R20]);
+  fn("x21", regs_[ARM64_REG_R21]);
+  fn("x22", regs_[ARM64_REG_R22]);
+  fn("x23", regs_[ARM64_REG_R23]);
+  fn("x24", regs_[ARM64_REG_R24]);
+  fn("x25", regs_[ARM64_REG_R25]);
+  fn("x26", regs_[ARM64_REG_R26]);
+  fn("x27", regs_[ARM64_REG_R27]);
+  fn("x28", regs_[ARM64_REG_R28]);
+  fn("x29", regs_[ARM64_REG_R29]);
+  fn("sp", regs_[ARM64_REG_SP]);
+  fn("lr", regs_[ARM64_REG_LR]);
+  fn("pc", regs_[ARM64_REG_PC]);
+}
+
 RegsX86::RegsX86()
     : RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
 
@@ -146,6 +201,18 @@
   return true;
 }
 
+void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("eax", regs_[X86_REG_EAX]);
+  fn("ebx", regs_[X86_REG_EBX]);
+  fn("ecx", regs_[X86_REG_ECX]);
+  fn("edx", regs_[X86_REG_EDX]);
+  fn("ebp", regs_[X86_REG_EBP]);
+  fn("edi", regs_[X86_REG_EDI]);
+  fn("esi", regs_[X86_REG_ESI]);
+  fn("esp", regs_[X86_REG_ESP]);
+  fn("eip", regs_[X86_REG_EIP]);
+}
+
 RegsX86_64::RegsX86_64()
     : RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
 
@@ -181,6 +248,26 @@
   return true;
 }
 
+void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
+  fn("rax", regs_[X86_64_REG_RAX]);
+  fn("rbx", regs_[X86_64_REG_RBX]);
+  fn("rcx", regs_[X86_64_REG_RCX]);
+  fn("rdx", regs_[X86_64_REG_RDX]);
+  fn("r8", regs_[X86_64_REG_R8]);
+  fn("r9", regs_[X86_64_REG_R9]);
+  fn("r10", regs_[X86_64_REG_R10]);
+  fn("r11", regs_[X86_64_REG_R11]);
+  fn("r12", regs_[X86_64_REG_R12]);
+  fn("r13", regs_[X86_64_REG_R13]);
+  fn("r14", regs_[X86_64_REG_R14]);
+  fn("r15", regs_[X86_64_REG_R15]);
+  fn("rdi", regs_[X86_64_REG_RDI]);
+  fn("rsi", regs_[X86_64_REG_RSI]);
+  fn("rbp", regs_[X86_64_REG_RBP]);
+  fn("rsp", regs_[X86_64_REG_RSP]);
+  fn("rip", regs_[X86_64_REG_RIP]);
+}
+
 static Regs* ReadArm(void* remote_data) {
   arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
 
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 9d3150b..6576e4c 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -19,6 +19,8 @@
 
 #include <stdint.h>
 
+#include <functional>
+#include <string>
 #include <vector>
 
 namespace unwindstack {
@@ -63,6 +65,8 @@
 
   virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
 
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) = 0;
+
   uint16_t sp_reg() { return sp_reg_; }
   uint16_t total_regs() { return total_regs_; }
 
@@ -94,6 +98,12 @@
 
   void* RawData() override { return regs_.data(); }
 
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)> fn) override {
+    for (size_t i = 0; i < regs_.size(); ++i) {
+      fn(std::to_string(i).c_str(), regs_[i]);
+    }
+  }
+
  protected:
   AddressType pc_;
   AddressType sp_;
@@ -114,6 +124,8 @@
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
 };
 
 class RegsArm64 : public RegsImpl<uint64_t> {
@@ -130,6 +142,8 @@
   bool SetPcFromReturnAddress(Memory* process_memory) override;
 
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
 };
 
 class RegsX86 : public RegsImpl<uint32_t> {
@@ -148,6 +162,8 @@
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
   void SetFromUcontext(x86_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
 };
 
 class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -166,6 +182,8 @@
   bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
 
   void SetFromUcontext(x86_64_ucontext_t* ucontext);
+
+  virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index efcd029..fedaf87 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -42,6 +42,8 @@
     return true;
   }
 
+  void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
+
   uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
 
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
new file mode 100644
index 0000000..c8d1d98
--- /dev/null
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <utility>
+#include <type_traits>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Regs.h>
+
+#include "Machine.h"
+
+namespace unwindstack {
+
+struct Register {
+  std::string expected_name;
+  uint64_t offset;
+
+  bool operator==(const Register& rhs) const {
+    return std::tie(expected_name, offset) == std::tie(rhs.expected_name, rhs.offset);
+  }
+};
+
+template<typename T>
+class RegsIterateTest : public ::testing::Test {
+};
+
+template<typename RegsType>
+std::vector<Register> ExpectedRegisters();
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsArm>() {
+  std::vector<Register> result;
+  result.push_back({"r0", ARM_REG_R0});
+  result.push_back({"r1", ARM_REG_R1});
+  result.push_back({"r2", ARM_REG_R2});
+  result.push_back({"r3", ARM_REG_R3});
+  result.push_back({"r4", ARM_REG_R4});
+  result.push_back({"r5", ARM_REG_R5});
+  result.push_back({"r6", ARM_REG_R6});
+  result.push_back({"r7", ARM_REG_R7});
+  result.push_back({"r8", ARM_REG_R8});
+  result.push_back({"r9", ARM_REG_R9});
+  result.push_back({"r10", ARM_REG_R10});
+  result.push_back({"r11", ARM_REG_R11});
+  result.push_back({"ip", ARM_REG_R12});
+  result.push_back({"sp", ARM_REG_SP});
+  result.push_back({"lr", ARM_REG_LR});
+  result.push_back({"pc", ARM_REG_PC});
+  return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsArm64>() {
+  std::vector<Register> result;
+  result.push_back({"x0", ARM64_REG_R0});
+  result.push_back({"x1", ARM64_REG_R1});
+  result.push_back({"x2", ARM64_REG_R2});
+  result.push_back({"x3", ARM64_REG_R3});
+  result.push_back({"x4", ARM64_REG_R4});
+  result.push_back({"x5", ARM64_REG_R5});
+  result.push_back({"x6", ARM64_REG_R6});
+  result.push_back({"x7", ARM64_REG_R7});
+  result.push_back({"x8", ARM64_REG_R8});
+  result.push_back({"x9", ARM64_REG_R9});
+  result.push_back({"x10", ARM64_REG_R10});
+  result.push_back({"x11", ARM64_REG_R11});
+  result.push_back({"x12", ARM64_REG_R12});
+  result.push_back({"x13", ARM64_REG_R13});
+  result.push_back({"x14", ARM64_REG_R14});
+  result.push_back({"x15", ARM64_REG_R15});
+  result.push_back({"x16", ARM64_REG_R16});
+  result.push_back({"x17", ARM64_REG_R17});
+  result.push_back({"x18", ARM64_REG_R18});
+  result.push_back({"x19", ARM64_REG_R19});
+  result.push_back({"x20", ARM64_REG_R20});
+  result.push_back({"x21", ARM64_REG_R21});
+  result.push_back({"x22", ARM64_REG_R22});
+  result.push_back({"x23", ARM64_REG_R23});
+  result.push_back({"x24", ARM64_REG_R24});
+  result.push_back({"x25", ARM64_REG_R25});
+  result.push_back({"x26", ARM64_REG_R26});
+  result.push_back({"x27", ARM64_REG_R27});
+  result.push_back({"x28", ARM64_REG_R28});
+  result.push_back({"x29", ARM64_REG_R29});
+  result.push_back({"sp", ARM64_REG_SP});
+  result.push_back({"lr", ARM64_REG_LR});
+  result.push_back({"pc", ARM64_REG_PC});
+  return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsX86>() {
+  std::vector<Register> result;
+  result.push_back({"eax", X86_REG_EAX});
+  result.push_back({"ebx", X86_REG_EBX});
+  result.push_back({"ecx", X86_REG_ECX});
+  result.push_back({"edx", X86_REG_EDX});
+  result.push_back({"ebp", X86_REG_EBP});
+  result.push_back({"edi", X86_REG_EDI});
+  result.push_back({"esi", X86_REG_ESI});
+  result.push_back({"esp", X86_REG_ESP});
+  result.push_back({"eip", X86_REG_EIP});
+  return result;
+}
+
+template<>
+std::vector<Register> ExpectedRegisters<RegsX86_64>() {
+  std::vector<Register> result;
+  result.push_back({"rax", X86_64_REG_RAX});
+  result.push_back({"rbx", X86_64_REG_RBX});
+  result.push_back({"rcx", X86_64_REG_RCX});
+  result.push_back({"rdx", X86_64_REG_RDX});
+  result.push_back({"r8", X86_64_REG_R8});
+  result.push_back({"r9", X86_64_REG_R9});
+  result.push_back({"r10", X86_64_REG_R10});
+  result.push_back({"r11", X86_64_REG_R11});
+  result.push_back({"r12", X86_64_REG_R12});
+  result.push_back({"r13", X86_64_REG_R13});
+  result.push_back({"r14", X86_64_REG_R14});
+  result.push_back({"r15", X86_64_REG_R15});
+  result.push_back({"rdi", X86_64_REG_RDI});
+  result.push_back({"rsi", X86_64_REG_RSI});
+  result.push_back({"rbp", X86_64_REG_RBP});
+  result.push_back({"rsp", X86_64_REG_RSP});
+  result.push_back({"rip", X86_64_REG_RIP});
+  return result;
+}
+
+using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
+TYPED_TEST_CASE(RegsIterateTest, RegTypes);
+
+TYPED_TEST(RegsIterateTest, iterate) {
+  std::vector<Register> expected = ExpectedRegisters<TypeParam>();
+  TypeParam regs;
+  for (const auto& reg : expected) {
+    regs[reg.offset] = reg.offset;
+  }
+
+  std::vector<Register> actual;
+  regs.IterateRegisters([&actual](const char* name, uint64_t value) {
+    actual.push_back({name, value});
+  });
+
+  ASSERT_EQ(expected, actual);
+}
+
+}  // namespace unwindstack