Merge "Error correction: Add a tool for en/decoding files"
diff --git a/boot_control_copy/Android.mk b/boot_control_copy/Android.mk
index 0027c10..47bd6c2 100644
--- a/boot_control_copy/Android.mk
+++ b/boot_control_copy/Android.mk
@@ -9,8 +9,7 @@
 LOCAL_SHARED_LIBRARIES := libcutils
 LOCAL_STATIC_LIBRARIES := libfs_mgr
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_MODULE:= bootctrl.default
 LOCAL_MODULE_TAGS := optional
 include $(BUILD_SHARED_LIBRARY)
-
diff --git a/boot_control_copy/boot_control_copy.c b/boot_control_copy/boot_control_copy.c
index a5deb5a..644e7de 100644
--- a/boot_control_copy/boot_control_copy.c
+++ b/boot_control_copy/boot_control_copy.c
@@ -39,21 +39,52 @@
   return 2;
 }
 
+static bool get_dev_t_for_partition(const char *name, dev_t *out_device)
+{
+  int fd;
+  struct stat statbuf;
+
+  fd = boot_info_open_partition(name, NULL, O_RDONLY);
+  if (fd == -1)
+    return false;
+  if (fstat(fd, &statbuf) != 0) {
+    fprintf(stderr, "WARNING: Error getting information about part %s: %s\n",
+            name, strerror(errno));
+    close(fd);
+    return false;
+  }
+  close(fd);
+  *out_device = statbuf.st_rdev;
+  return true;
+}
+
 unsigned module_getCurrentSlot(boot_control_module_t *module)
 {
-  BrilloBootInfo info;
+  struct stat statbuf;
+  dev_t system_a_dev, system_b_dev;
 
-  if (!boot_info_load(&info)) {
-    fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
-    boot_info_reset(&info);
-  } else {
-    if (!boot_info_validate(&info)) {
-      fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
-      boot_info_reset(&info);
-    }
+  if (stat("/system", &statbuf) != 0) {
+    fprintf(stderr, "WARNING: Error getting information about /system: %s\n",
+            strerror(errno));
+    return 0;
   }
 
-  return info.active_slot;
+  if (!get_dev_t_for_partition("system_a", &system_a_dev) ||
+      !get_dev_t_for_partition("system_b", &system_b_dev))
+    return 0;
+
+  if (statbuf.st_dev == system_a_dev) {
+    return 0;
+  } else if (statbuf.st_dev == system_b_dev) {
+    return 1;
+  } else {
+    fprintf(stderr, "WARNING: Error determining current slot "
+            "(/system dev_t of %d:%d does not match a=%d:%d or b=%d:%d)\n",
+            major(statbuf.st_dev), minor(statbuf.st_dev),
+            major(system_a_dev), minor(system_a_dev),
+            major(system_b_dev), minor(system_b_dev));
+    return 0;
+  }
 }
 
 int module_markBootSuccessful(boot_control_module_t *module)
diff --git a/libfec/Android.mk b/libfec/Android.mk
index cccf6c0..4ca563e 100644
--- a/libfec/Android.mk
+++ b/libfec/Android.mk
@@ -38,6 +38,8 @@
     $(common_static_libraries)
 include $(BUILD_STATIC_LIBRARY)
 
+ifeq ($(HOST_OS),linux)
+
 include $(CLEAR_VARS)
 LOCAL_CFLAGS := $(common_cflags) -D_GNU_SOURCE -DFEC_NO_KLOG
 LOCAL_C_INCLUDES := $(common_c_includes)
@@ -53,4 +55,6 @@
     $(common_static_libraries)
 include $(BUILD_HOST_STATIC_LIBRARY)
 
+endif # HOST_OS == linux
+
 include $(LOCAL_PATH)/test/Android.mk
diff --git a/libfec/test/Android.mk b/libfec/test/Android.mk
index 4b38310..a2bba55 100644
--- a/libfec/test/Android.mk
+++ b/libfec/test/Android.mk
@@ -1,5 +1,7 @@
 LOCAL_PATH:= $(call my-dir)
 
+ifeq ($(HOST_OS),linux)
+
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_SANITIZE := integer
@@ -26,3 +28,5 @@
 LOCAL_CFLAGS := -Wall -Werror -D_GNU_SOURCE
 LOCAL_C_INCLUDES += external/fec
 include $(BUILD_HOST_EXECUTABLE)
+
+endif # HOST_OS == linux
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 35bec54..111ad18 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -16,23 +16,40 @@
 
 LOCAL_PATH := $(call my-dir)
 
-simpleperf_common_cppflags := -std=c++11 -Wall -Wextra -Werror -Wunused
+simpleperf_common_cppflags := -std=c++11 -Wall -Wextra -Werror -Wunused \
 
-simpleperf_host_common_cppflags := $(simpleperf_common_cppflags) \
-                                   -DUSE_BIONIC_UAPI_HEADERS -I bionic/libc/kernel \
+simpleperf_cppflags_target := $(simpleperf_common_cppflags) \
 
-simpleperf_host_darwin_cppflags := $(simpleperf_host_common_cppflags) \
-                                   -I $(LOCAL_PATH)/darwin_support \
+simpleperf_cppflags_host := $(simpleperf_common_cppflags) \
+                            -DUSE_BIONIC_UAPI_HEADERS -I bionic/libc/kernel \
 
-simpleperf_common_shared_libraries := \
+simpleperf_cppflags_host_linux := $(simpleperf_cppflags_host) \
+
+simpleperf_cppflags_host_darwin := $(simpleperf_cppflags_host) \
+                                   -I $(LOCAL_PATH)/darwin_support/include \
+
+LLVM_ROOT_PATH := external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+simpleperf_shared_libraries_target := \
+  libbacktrace \
   libbase \
   libLLVM \
 
-LLVM_ROOT_PATH := external/llvm
+simpleperf_shared_libraries_host_linux := \
+  libbacktrace \
+  libbase \
+
+simpleperf_shared_libraries_host_darwin := \
+  libbase \
+  libLLVM \
+
+simpleperf_ldlibs_host_linux := -lrt \
+
 
 # libsimpleperf
 # =========================================================
-libsimpleperf_common_src_files := \
+libsimpleperf_src_files := \
   callchain.cpp \
   cmd_dumprecord.cpp \
   cmd_help.cpp \
@@ -49,113 +66,129 @@
   thread_tree.cpp \
   utils.cpp \
 
-libsimpleperf_src_files := \
-  $(libsimpleperf_common_src_files) \
+libsimpleperf_src_files_linux := \
   cmd_list.cpp \
   cmd_record.cpp \
   cmd_stat.cpp \
+  dwarf_unwind.cpp \
   environment.cpp \
   event_fd.cpp \
   event_selection_set.cpp \
   record_file_writer.cpp \
   workload.cpp \
 
-libsimpleperf_darwin_src_files := \
-  $(libsimpleperf_common_src_files) \
-  environment_fake.cpp \
+libsimpleperf_src_files_darwin := \
+  darwin_support/darwin_support.cpp \
 
+# libsimpleperf target
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_common_cppflags)
-LOCAL_SRC_FILES := $(libsimpleperf_src_files)
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
+LOCAL_SRC_FILES := \
+  $(libsimpleperf_src_files) \
+  $(libsimpleperf_src_files_linux) \
+
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_target)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := libsimpleperf
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(LLVM_ROOT_PATH)/llvm.mk
 include $(LLVM_DEVICE_BUILD_MK)
 include $(BUILD_STATIC_LIBRARY)
 
+# libsimpleperf linux host
 ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_common_cppflags)
-LOCAL_SRC_FILES := $(libsimpleperf_src_files)
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
-LOCAL_LDLIBS := -lrt
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_linux)
+LOCAL_SRC_FILES := \
+  $(libsimpleperf_src_files) \
+  $(libsimpleperf_src_files_linux) \
+
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_host_linux)
+LOCAL_LDLIBS := $(simpleperf_ldlibs_host_linux)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := libsimpleperf
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(LLVM_ROOT_PATH)/llvm.mk
 include $(LLVM_HOST_BUILD_MK)
 include $(BUILD_HOST_STATIC_LIBRARY)
 endif
 
+# libsimpleperf darwin host
 ifeq ($(HOST_OS),darwin)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
-LOCAL_SRC_FILES := $(libsimpleperf_darwin_src_files)
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_darwin)
+LOCAL_SRC_FILES := \
+  $(libsimpleperf_src_files) \
+  $(libsimpleperf_src_files_darwin) \
+
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_host_darwin)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := libsimpleperf
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(LLVM_ROOT_PATH)/llvm.mk
 include $(LLVM_HOST_BUILD_MK)
 include $(BUILD_HOST_SHARED_LIBRARY)
 endif
 
+
 # simpleperf
 # =========================================================
+
+# simpleperf target
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_common_cppflags)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
 LOCAL_SRC_FILES := main.cpp
 LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_target)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := simpleperf
 LOCAL_MODULE_TAGS := debug
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_EXECUTABLE)
 
+# simpleperf linux host
 ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_common_cppflags)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_linux)
 LOCAL_SRC_FILES := main.cpp
 LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
-LOCAL_LDLIBS := -lrt
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_host_linux)
+LOCAL_MULTILIB := first
+LOCAL_LDLIBS := $(simpleperf_ldlibs_host_linux)
 LOCAL_MODULE := simpleperf
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 endif
 
+# simpleperf darwin host
 ifeq ($(HOST_OS),darwin)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_darwin)
 LOCAL_SRC_FILES := main.cpp
-LOCAL_SHARED_LIBRARIES := libsimpleperf $(simpleperf_common_shared_libraries)
+LOCAL_SHARED_LIBRARIES := \
+  libsimpleperf \
+  $(simpleperf_shared_libraries_host_darwin) \
+
+LOCAL_MULTILIB := first
 LOCAL_MODULE := simpleperf
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 endif
 
+
 # simpleperf_unit_test
 # =========================================================
-simpleperf_unit_test_common_src_files := \
+simpleperf_unit_test_src_files := \
   command_test.cpp \
   gtest_main.cpp \
   record_test.cpp \
   sample_tree_test.cpp \
 
-simpleperf_unit_test_src_files := \
-  $(simpleperf_unit_test_common_src_files) \
+simpleperf_unit_test_src_files_linux := \
   cmd_dumprecord_test.cpp \
   cmd_list_test.cpp \
   cmd_record_test.cpp \
@@ -167,38 +200,50 @@
   record_file_test.cpp \
   workload_test.cpp \
 
+# simpleperf_unit_test target
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_common_cppflags)
-LOCAL_SRC_FILES := $(simpleperf_unit_test_src_files)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_target)
+LOCAL_SRC_FILES := \
+  $(simpleperf_unit_test_src_files) \
+  $(simpleperf_unit_test_src_files_linux) \
+
 LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_target)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := simpleperf_unit_test
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_NATIVE_TEST)
 
+# simpleperf_unit_test linux host
 ifeq ($(HOST_OS),linux)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_common_cppflags)
-LOCAL_SRC_FILES := $(simpleperf_unit_test_src_files)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_linux)
+LOCAL_SRC_FILES := \
+  $(simpleperf_unit_test_src_files) \
+  $(simpleperf_unit_test_src_files_linux) \
+
 LOCAL_WHOLE_STATIC_LIBRARIES := libsimpleperf
-LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(simpleperf_shared_libraries_host_linux)
+LOCAL_MULTILIB := first
 LOCAL_MODULE := simpleperf_unit_test
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_NATIVE_TEST)
 endif
 
+# simpleperf_unit_test darwin host
 ifeq ($(HOST_OS),darwin)
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
-LOCAL_SRC_FILES := $(simpleperf_unit_test_common_src_files)
-LOCAL_SHARED_LIBRARIES := libsimpleperf $(simpleperf_common_shared_libraries)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host_darwin)
+LOCAL_SRC_FILES := $(simpleperf_unit_test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+  libsimpleperf \
+  $(simpleperf_shared_libraries_host_darwin) \
+
+LOCAL_MULTILIB := first
 LOCAL_MODULE := simpleperf_unit_test
 LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_NATIVE_TEST)
 endif
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index 7fee516..6cba598 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -29,6 +29,7 @@
 #include <base/strings.h>
 
 #include "command.h"
+#include "dwarf_unwind.h"
 #include "environment.h"
 #include "event_attr.h"
 #include "event_type.h"
@@ -532,10 +533,28 @@
     if (sample == nullptr) {
       return;
     }
-    if (accumulate_callchain_ && (r.sample_type & PERF_SAMPLE_CALLCHAIN) != 0) {
+    if (accumulate_callchain_) {
+      std::vector<uint64_t> ips;
+      if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
+        ips.insert(ips.end(), r.callchain_data.ips.begin(), r.callchain_data.ips.end());
+      }
+      // Use stack_user_data.data.size() instead of stack_user_data.dyn_size, to make up for
+      // the missing kernel patch in N9. See b/22612370.
+      if ((r.sample_type & PERF_SAMPLE_REGS_USER) && (r.regs_user_data.reg_mask != 0) &&
+          (r.sample_type & PERF_SAMPLE_STACK_USER) && (!r.stack_user_data.data.empty())) {
+        RegSet regs = CreateRegSet(r.regs_user_data.reg_mask, r.regs_user_data.regs);
+        std::vector<char> stack(r.stack_user_data.data.begin(),
+                                r.stack_user_data.data.begin() + r.stack_user_data.data.size());
+        std::vector<uint64_t> unwind_ips = UnwindCallChain(*sample->thread, regs, stack);
+        if (!unwind_ips.empty()) {
+          ips.push_back(PERF_CONTEXT_USER);
+          ips.insert(ips.end(), unwind_ips.begin(), unwind_ips.end());
+        }
+      }
+
       std::vector<SampleEntry*> callchain;
       callchain.push_back(sample);
-      const std::vector<uint64_t>& ips = r.callchain_data.ips;
+
       bool first_ip = true;
       for (auto& ip : ips) {
         if (ip >= PERF_CONTEXT_MAX) {
@@ -551,11 +570,11 @@
           }
         } else {
           if (first_ip) {
+            first_ip = false;
             // Remove duplication with sampled ip.
             if (ip == r.ip_data.ip) {
               continue;
             }
-            first_ip = false;
           }
           SampleEntry* sample =
               sample_tree_->AddCallChainSample(r.tid_data.pid, r.tid_data.tid, ip, r.time_data.time,
@@ -563,6 +582,7 @@
           callchain.push_back(sample);
         }
       }
+
       if (print_callgraph_) {
         std::set<SampleEntry*> added_set;
         if (!callgraph_show_callee_) {
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index b237b77..4feac19 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include "command.h"
+#include "event_selection_set.h"
 
 static std::unique_ptr<Command> RecordCmd() {
   return CreateCommandInstance("record");
@@ -81,8 +82,6 @@
   ASSERT_TRUE(ReportCmd()->Run({"--dsos", "[kernel.kallsyms],/init"}));
 }
 
-extern bool IsBranchSamplingSupported();
-
 TEST(report_cmd, use_branch_address) {
   if (IsBranchSamplingSupported()) {
     ASSERT_TRUE(RecordCmd()->Run({"-b", "sleep", "1"}));
@@ -93,3 +92,13 @@
         << "This test does nothing as branch stack sampling is not supported on this device.";
   }
 }
+
+TEST(report_cmd, dwarf_callgraph) {
+  if (IsDwarfCallChainSamplingSupported()) {
+    ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", "perf_dwarf.data", "sleep", "1"}));
+    ASSERT_TRUE(ReportCmd()->Run({"-g", "-i", "perf_dwarf.data"}));
+  } else {
+    GTEST_LOG_(INFO)
+        << "This test does nothing as dwarf callchain sampling is not supported on this device.";
+  }
+}
diff --git a/simpleperf/darwin_support/darwin_support.cpp b/simpleperf/darwin_support/darwin_support.cpp
new file mode 100644
index 0000000..0b27a8f
--- /dev/null
+++ b/simpleperf/darwin_support/darwin_support.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+// Add fake functions to build successfully on darwin.
+#include <base/logging.h>
+
+#include "dwarf_unwind.h"
+#include "environment.h"
+
+std::vector<uint64_t> UnwindCallChain(const ThreadEntry&, const RegSet&,
+                                      const std::vector<char>&) {
+  return std::vector<uint64_t>();
+}
+
+bool ProcessKernelSymbols(const std::string&, std::function<bool(const KernelSymbol&)>) {
+  return false;
+}
+
+bool GetKernelBuildId(BuildId*) {
+  return false;
+}
diff --git a/simpleperf/darwin_support/asm/byteorder.h b/simpleperf/darwin_support/include/asm/byteorder.h
similarity index 100%
rename from simpleperf/darwin_support/asm/byteorder.h
rename to simpleperf/darwin_support/include/asm/byteorder.h
diff --git a/simpleperf/darwin_support/linux/ioctl.h b/simpleperf/darwin_support/include/linux/ioctl.h
similarity index 100%
rename from simpleperf/darwin_support/linux/ioctl.h
rename to simpleperf/darwin_support/include/linux/ioctl.h
diff --git a/simpleperf/darwin_support/linux/types.h b/simpleperf/darwin_support/include/linux/types.h
similarity index 100%
rename from simpleperf/darwin_support/linux/types.h
rename to simpleperf/darwin_support/include/linux/types.h
diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp
index ec4433e..69cbcc3 100644
--- a/simpleperf/dso.cpp
+++ b/simpleperf/dso.cpp
@@ -150,6 +150,11 @@
   }
 };
 
+
+std::string Dso::GetAccessiblePath() const {
+  return symfs_dir_ + path_;
+}
+
 const Symbol* Dso::FindSymbol(uint64_t offset_in_dso) {
   if (!is_loaded_) {
     is_loaded_ = true;
diff --git a/simpleperf/dso.h b/simpleperf/dso.h
index b9553f3..bbe0190 100644
--- a/simpleperf/dso.h
+++ b/simpleperf/dso.h
@@ -60,10 +60,16 @@
   static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path = "");
 
   ~Dso();
+
+  // Return the path recorded in perf.data.
   const std::string& Path() const {
     return path_;
   }
 
+  // Return the accessible path. It may be the same as Path(), or
+  // return the path with prefix set by SetSymFsDir().
+  std::string GetAccessiblePath() const;
+
   const Symbol* FindSymbol(uint64_t offset_in_dso);
 
  private:
diff --git a/simpleperf/dwarf_unwind.cpp b/simpleperf/dwarf_unwind.cpp
new file mode 100644
index 0000000..cd51a13
--- /dev/null
+++ b/simpleperf/dwarf_unwind.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2015 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 "dwarf_unwind.h"
+
+#include <ucontext.h>
+
+#include <backtrace/Backtrace.h>
+#include <base/logging.h>
+
+#include "thread_tree.h"
+
+#define SetUContextReg(dst, perf_regno) \
+  do { \
+    uint64_t value; \
+    if (GetRegValue(regs, perf_regno, &value)) { \
+      dst = value; \
+    } \
+  } while (0)
+
+static ucontext_t BuildUContextFromRegs(const RegSet& regs __attribute__((unused))) {
+  ucontext_t ucontext;
+  memset(&ucontext, 0, sizeof(ucontext));
+#if defined(__i386__)
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_GS], PERF_REG_X86_GS);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_FS], PERF_REG_X86_FS);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_ES], PERF_REG_X86_ES);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_DS], PERF_REG_X86_DS);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EAX], PERF_REG_X86_AX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBX], PERF_REG_X86_BX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_ECX], PERF_REG_X86_CX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDX], PERF_REG_X86_DX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESI], PERF_REG_X86_SI);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EDI], PERF_REG_X86_DI);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EBP], PERF_REG_X86_BP);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EIP], PERF_REG_X86_IP);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_ESP], PERF_REG_X86_SP);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_CS], PERF_REG_X86_CS);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_EFL], PERF_REG_X86_FLAGS);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_SS], PERF_REG_X86_SS);
+#elif defined(__x86_64__)
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R8], PERF_REG_X86_R8);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R9], PERF_REG_X86_R9);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R10], PERF_REG_X86_R10);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R11], PERF_REG_X86_R11);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R12], PERF_REG_X86_R12);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R13], PERF_REG_X86_R13);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R14], PERF_REG_X86_R14);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_R15], PERF_REG_X86_R15);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDI], PERF_REG_X86_DI);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSI], PERF_REG_X86_SI);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBP], PERF_REG_X86_BP);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RBX], PERF_REG_X86_BX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RDX], PERF_REG_X86_DX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RAX], PERF_REG_X86_AX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RCX], PERF_REG_X86_CX);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RSP], PERF_REG_X86_SP);
+  SetUContextReg(ucontext.uc_mcontext.gregs[REG_RIP], PERF_REG_X86_IP);
+#elif defined(__aarch64__)
+  for (size_t i = PERF_REG_ARM64_X0; i < PERF_REG_ARM64_MAX; ++i) {
+    SetUContextReg(ucontext.uc_mcontext.regs[i], i);
+  }
+#elif defined(__arm__)
+  SetUContextReg(ucontext.uc_mcontext.arm_r0, PERF_REG_ARM_R0);
+  SetUContextReg(ucontext.uc_mcontext.arm_r1, PERF_REG_ARM_R1);
+  SetUContextReg(ucontext.uc_mcontext.arm_r2, PERF_REG_ARM_R2);
+  SetUContextReg(ucontext.uc_mcontext.arm_r3, PERF_REG_ARM_R3);
+  SetUContextReg(ucontext.uc_mcontext.arm_r4, PERF_REG_ARM_R4);
+  SetUContextReg(ucontext.uc_mcontext.arm_r5, PERF_REG_ARM_R5);
+  SetUContextReg(ucontext.uc_mcontext.arm_r6, PERF_REG_ARM_R6);
+  SetUContextReg(ucontext.uc_mcontext.arm_r7, PERF_REG_ARM_R7);
+  SetUContextReg(ucontext.uc_mcontext.arm_r8, PERF_REG_ARM_R8);
+  SetUContextReg(ucontext.uc_mcontext.arm_r9, PERF_REG_ARM_R9);
+  SetUContextReg(ucontext.uc_mcontext.arm_r10, PERF_REG_ARM_R10);
+  SetUContextReg(ucontext.uc_mcontext.arm_fp, PERF_REG_ARM_FP);
+  SetUContextReg(ucontext.uc_mcontext.arm_ip, PERF_REG_ARM_IP);
+  SetUContextReg(ucontext.uc_mcontext.arm_sp, PERF_REG_ARM_SP);
+  SetUContextReg(ucontext.uc_mcontext.arm_lr, PERF_REG_ARM_LR);
+  SetUContextReg(ucontext.uc_mcontext.arm_pc, PERF_REG_ARM_PC);
+#endif
+  return ucontext;
+}
+
+std::vector<uint64_t> UnwindCallChain(const ThreadEntry& thread,
+                                      const RegSet& regs,
+                                      const std::vector<char>& stack) {
+  std::vector<uint64_t> result;
+  if (GetCurrentArch() != GetBuildArch()) {
+    LOG(ERROR) << "can't unwind data recorded on a different architecture";
+    return result;
+  }
+  uint64_t sp_reg_value;
+  if (!GetSpRegValue(regs, &sp_reg_value)) {
+    LOG(ERROR) << "can't get sp reg value";
+    return result;
+  }
+  uint64_t stack_addr = sp_reg_value;
+
+  std::vector<backtrace_map_t> bt_maps(thread.maps.size());
+  size_t map_index = 0;
+  for (auto& map : thread.maps) {
+    backtrace_map_t& bt_map = bt_maps[map_index++];
+    bt_map.start = map->start_addr;
+    bt_map.end = map->start_addr + map->len;
+    bt_map.offset = map->pgoff;
+    bt_map.name = map->dso->GetAccessiblePath();
+  }
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(thread.pid, bt_maps));
+
+  backtrace_stackinfo_t stack_info;
+  stack_info.start = stack_addr;
+  stack_info.end = stack_addr + stack.size();
+  stack_info.data = reinterpret_cast<const uint8_t*>(stack.data());
+
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::CreateOffline(thread.pid, thread.tid, backtrace_map.get(), stack_info, true));
+  ucontext_t ucontext = BuildUContextFromRegs(regs);
+  if (backtrace->Unwind(0, &ucontext)) {
+    for (auto it = backtrace->begin(); it != backtrace->end(); ++it) {
+      result.push_back(it->pc);
+    }
+  }
+  return result;
+}
diff --git a/simpleperf/dwarf_unwind.h b/simpleperf/dwarf_unwind.h
new file mode 100644
index 0000000..f6a58a1
--- /dev/null
+++ b/simpleperf/dwarf_unwind.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef SIMPLE_PERF_DWARF_UNWIND_H_
+#define SIMPLE_PERF_DWARF_UNWIND_H_
+
+#include <vector>
+
+#include "perf_regs.h"
+
+struct ThreadEntry;
+
+std::vector<uint64_t> UnwindCallChain(const ThreadEntry& thread, const RegSet& regs,
+                            const std::vector<char>& stack);
+
+#endif  // SIMPLE_PERF_DWARF_UNWIND_H_
diff --git a/simpleperf/event_attr.cpp b/simpleperf/event_attr.cpp
index c8acc70..b0d75ce 100644
--- a/simpleperf/event_attr.cpp
+++ b/simpleperf/event_attr.cpp
@@ -139,6 +139,8 @@
   PrintIndented(indent + 1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n",
                 attr.sample_id_all, attr.exclude_host, attr.exclude_guest);
   PrintIndented(indent + 1, "branch_sample_type 0x%" PRIx64 "\n", attr.branch_sample_type);
+  PrintIndented(indent + 1, "exclude_callchain_kernel %u, exclude_callchain_user %u\n",
+                attr.exclude_callchain_kernel, attr.exclude_callchain_user);
   PrintIndented(indent + 1, "sample_regs_user 0x%" PRIx64 "\n", attr.sample_regs_user);
   PrintIndented(indent + 1, "sample_stack_user 0x%" PRIx64 "\n", attr.sample_stack_user);
 }
diff --git a/simpleperf/perf_regs.cpp b/simpleperf/perf_regs.cpp
index 6a63876..7efa01b 100644
--- a/simpleperf/perf_regs.cpp
+++ b/simpleperf/perf_regs.cpp
@@ -21,20 +21,6 @@
 #include <base/stringprintf.h>
 #include <base/strings.h>
 
-constexpr ArchType GetBuildArch() {
-#if defined(__i386__)
-  return ARCH_X86_32;
-#elif defined(__x86_64__)
-  return ARCH_X86_64;
-#elif defined(__aarch64__)
-  return ARCH_ARM64;
-#elif defined(__arm__)
-  return ARCH_ARM;
-#else
-  return ARCH_UNSUPPORTED;
-#endif
-}
-
 static ArchType current_arch = GetBuildArch();
 
 ArchType GetCurrentArch() {
@@ -120,7 +106,43 @@
       CHECK(it != arm64_reg_map.end()) << "unknown reg " << reg;
       return it->second;
     }
-    case ARCH_UNSUPPORTED:
+    default:
       return "unknown";
   }
 }
+
+RegSet CreateRegSet(uint64_t valid_mask, const std::vector<uint64_t>& valid_regs) {
+  RegSet regs;
+  regs.valid_mask = valid_mask;
+  for (int i = 0, j = 0; i < 64; ++i) {
+    if ((valid_mask >> i) & 1) {
+      regs.data[i] = valid_regs[j++];
+    }
+  }
+  return regs;
+}
+
+bool GetRegValue(const RegSet& regs, size_t regno, uint64_t* value) {
+  CHECK_LT(regno, 64U);
+  if ((regs.valid_mask >> regno) & 1) {
+    *value = regs.data[regno];
+    return true;
+  }
+  return false;
+}
+
+bool GetSpRegValue(const RegSet& regs, uint64_t* value) {
+  size_t regno;
+#if defined(__i386__)
+  regno = PERF_REG_X86_SP;
+#elif defined(__x86_64__)
+  regno = PERF_REG_X86_SP;
+#elif defined(__aarch64__)
+  regno = PERF_REG_ARM64_SP;
+#elif defined(__arm__)
+  regno = PERF_REG_ARM_SP;
+#else
+  return false;
+#endif
+  return GetRegValue(regs, regno, value);
+}
diff --git a/simpleperf/perf_regs.h b/simpleperf/perf_regs.h
index 97e230f..3834806 100644
--- a/simpleperf/perf_regs.h
+++ b/simpleperf/perf_regs.h
@@ -31,6 +31,7 @@
 
 #include <stdint.h>
 #include <string>
+#include <vector>
 
 enum ArchType {
   ARCH_X86_32,
@@ -40,6 +41,20 @@
   ARCH_UNSUPPORTED,
 };
 
+constexpr ArchType GetBuildArch() {
+#if defined(__i386__)
+  return ARCH_X86_32;
+#elif defined(__x86_64__)
+  return ARCH_X86_64;
+#elif defined(__aarch64__)
+  return ARCH_ARM64;
+#elif defined(__arm__)
+  return ARCH_ARM;
+#else
+  return ARCH_UNSUPPORTED;
+#endif
+}
+
 ArchType GetCurrentArch();
 bool SetCurrentArch(const std::string& arch);
 
@@ -47,4 +62,14 @@
 
 std::string GetRegName(size_t reg);
 
+struct RegSet {
+  uint64_t valid_mask;
+  uint64_t data[64];
+};
+
+RegSet CreateRegSet(uint64_t valid_mask, const std::vector<uint64_t>& valid_regs);
+
+bool GetRegValue(const RegSet& regs, size_t regno, uint64_t* value);
+bool GetSpRegValue(const RegSet& regs, uint64_t* value);
+
 #endif  // SIMPLE_PERF_PERF_REGS_H_
diff --git a/simpleperf/workload.cpp b/simpleperf/workload.cpp
index 42a5fdd..56870a7 100644
--- a/simpleperf/workload.cpp
+++ b/simpleperf/workload.cpp
@@ -78,6 +78,7 @@
     close(start_signal_pipe[1]);
     close(exec_child_pipe[0]);
     ChildProcessFn(args_, start_signal_pipe[0], exec_child_pipe[1]);
+    _exit(0);
   }
   // In parent process.
   close(start_signal_pipe[0]);
diff --git a/simpleperf/workload_test.cpp b/simpleperf/workload_test.cpp
index f250328..f4c1601 100644
--- a/simpleperf/workload_test.cpp
+++ b/simpleperf/workload_test.cpp
@@ -50,7 +50,7 @@
     auto workload = Workload::CreateWorkload({"sleep", "10"});
     ASSERT_TRUE(workload != nullptr);
     ASSERT_TRUE(workload->Start());
-    ASSERT_EQ(0, kill(workload->GetPid(), SIGABRT));
+    ASSERT_EQ(0, kill(workload->GetPid(), SIGKILL));
     while (!signaled) {
     }
   }