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) {
}
}