Merge "init: fix variable scope issue with ExpandArgs()"
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 608917a..7fd67c2 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -37,7 +37,6 @@
"fs_mgr_avb_ops.cpp",
],
static_libs: [
- "liblogwrap",
"libfec",
"libfec_rs",
"libbase",
@@ -53,6 +52,7 @@
"libfstab",
],
whole_static_libs: [
+ "liblogwrap",
"libfstab",
],
product_variables: {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 18ccc43..007189d 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -20,6 +20,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_MODULE:= fs_mgr
LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := mke2fs mke2fs.conf e2fsdroid
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index a03d92c..75feee7 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -24,25 +24,21 @@
#include <cutils/partition_utils.h>
#include <sys/mount.h>
-#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/ext4.h>
-#include <ext4_utils/make_ext4fs.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
+#include <ext4_utils/ext4_utils.h>
+#include <logwrap/logwrap.h>
#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "fs_mgr_priv.h"
#include "cryptfs.h"
-extern "C" {
-extern struct fs_info info; /* magic global from ext4_utils */
-extern void reset_ext4fs_info();
-}
-
static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
{
uint64_t dev_sz;
int fd, rc = 0;
+ int status;
if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
PERROR << "Cannot open block device";
@@ -55,30 +51,36 @@
return -1;
}
- struct selabel_handle *sehandle = selinux_android_file_context_handle();
- if (!sehandle) {
- /* libselinux logs specific error */
- LERROR << "Cannot initialize android file_contexts";
- close(fd);
- return -1;
- }
-
- /* Format the partition using the calculated length */
- reset_ext4fs_info();
- info.len = (off64_t)dev_sz;
- if (crypt_footer) {
- info.len -= CRYPT_FOOTER_OFFSET;
- }
-
- /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
- rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL);
- if (rc) {
- LERROR << "make_ext4fs returned " << rc;
- }
close(fd);
- if (sehandle) {
- selabel_close(sehandle);
+ /* Format the partition using the calculated length */
+ if (crypt_footer) {
+ dev_sz -= CRYPT_FOOTER_OFFSET;
+ }
+
+ std::string size_str = std::to_string(dev_sz / 4096);
+ const char* const mke2fs_args[] = {
+ "/system/bin/mke2fs", "-t", "ext4", "-b", "4096", fs_blkdev, size_str.c_str(), nullptr};
+
+ rc = android_fork_execvp_ext(arraysize(mke2fs_args), const_cast<char**>(mke2fs_args), &status,
+ true, LOG_KLOG, true, nullptr, nullptr, 0);
+ if (rc) {
+ LERROR << "mke2fs returned " << rc;
+ return rc;
+ }
+
+ const char* const e2fsdroid_args[] = {
+ "/system/bin/e2fsdroid",
+ "-e",
+ "-a",
+ fs_mnt_point,
+ fs_blkdev,
+ nullptr};
+
+ rc = android_fork_execvp_ext(arraysize(e2fsdroid_args), const_cast<char**>(e2fsdroid_args),
+ &status, true, LOG_KLOG, true, nullptr, nullptr, 0);
+ if (rc) {
+ LERROR << "e2fsdroid returned " << rc;
}
return rc;
@@ -86,44 +88,11 @@
static int format_f2fs(char *fs_blkdev)
{
- char * args[5];
- int pid;
- int rc = 0;
+ int status;
+ const char* const args[] = {"/system/bin/make_f2fs", "-f", "-O encrypt", fs_blkdev, nullptr};
- args[0] = (char *)"/system/bin/make_f2fs";
- args[1] = (char *)"-f";
- args[2] = (char *)"-O encrypt";
- args[3] = fs_blkdev;
- args[4] = (char *)0;
-
- pid = fork();
- if (pid < 0) {
- return pid;
- }
- if (!pid) {
- /* This doesn't return */
- execv(args[0], args);
- exit(1);
- }
- for(;;) {
- pid_t p = waitpid(pid, &rc, 0);
- if (p != pid) {
- LERROR << "Error waiting for child process - " << p;
- rc = -1;
- break;
- }
- if (WIFEXITED(rc)) {
- rc = WEXITSTATUS(rc);
- LINFO << args[0] << " done, status " << rc;
- if (rc) {
- rc = -1;
- }
- break;
- }
- LERROR << "Still waiting for " << args[0] << "...";
- }
-
- return rc;
+ return android_fork_execvp_ext(arraysize(args), const_cast<char**>(args), &status, true,
+ LOG_KLOG, true, nullptr, nullptr, 0);
}
int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
diff --git a/init/Android.bp b/init/Android.bp
index 8737def..672942e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -119,7 +119,7 @@
"init_first_stage.cpp",
"keychords.cpp",
"reboot.cpp",
- "signal_handler.cpp",
+ "sigchld_handler.cpp",
"ueventd.cpp",
"watchdogd.cpp",
],
diff --git a/init/Android.mk b/init/Android.mk
index 23ada73..6c28517 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -48,7 +48,7 @@
init_first_stage.cpp \
keychords.cpp \
reboot.cpp \
- signal_handler.cpp \
+ sigchld_handler.cpp \
ueventd.cpp \
watchdogd.cpp \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 140ef75..886c572 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -66,7 +66,6 @@
#include "reboot.h"
#include "rlimit_parser.h"
#include "service.h"
-#include "signal_handler.h"
#include "util.h"
using namespace std::literals::string_literals;
diff --git a/init/init.cpp b/init/init.cpp
index 678f49f..c3e08fb 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -25,6 +25,7 @@
#include <string.h>
#include <sys/epoll.h>
#include <sys/mount.h>
+#include <sys/signalfd.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
@@ -51,7 +52,7 @@
#include "reboot.h"
#include "security.h"
#include "selinux.h"
-#include "signal_handler.h"
+#include "sigchld_handler.h"
#include "ueventd.h"
#include "util.h"
#include "watchdogd.h"
@@ -72,6 +73,7 @@
std::string default_console = "/dev/console";
static int epoll_fd = -1;
+static int sigterm_signal_fd = -1;
static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
@@ -392,6 +394,41 @@
sigaction(SIGTRAP, &action, nullptr);
}
+static void HandleSigtermSignal() {
+ signalfd_siginfo siginfo;
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(sigterm_signal_fd, &siginfo, sizeof(siginfo)));
+ if (bytes_read != sizeof(siginfo)) {
+ PLOG(ERROR) << "Failed to read siginfo from sigterm_signal_fd";
+ return;
+ }
+
+ if (siginfo.ssi_pid != 0) {
+ // Drop any userspace SIGTERM requests.
+ LOG(DEBUG) << "Ignoring SIGTERM from pid " << siginfo.ssi_pid;
+ return;
+ }
+
+ LOG(INFO) << "Handling SIGTERM, shutting system down";
+ HandlePowerctlMessage("shutdown");
+}
+
+static void InstallSigtermHandler() {
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_BLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to block SIGTERM";
+ }
+
+ sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+ if (sigterm_signal_fd == -1) {
+ PLOG(FATAL) << "failed to create signalfd for SIGTERM";
+ }
+
+ register_epoll_handler(sigterm_signal_fd, HandleSigtermSignal);
+}
+
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
@@ -527,7 +564,13 @@
exit(1);
}
- signal_handler_init();
+ sigchld_handler_init();
+
+ if (!IsRebootCapable()) {
+ // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
+ // In that case, receiving SIGTERM will cause the system to shut down.
+ InstallSigtermHandler();
+ }
property_load_boot_defaults();
export_oem_lock_status();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 8c592cb..5f5ed40 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -45,6 +45,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <bootimg.h>
#include <fs_mgr.h>
@@ -56,6 +57,7 @@
#include "persistent_properties.h"
#include "util.h"
+using android::base::StringPrintf;
using android::base::Timer;
#define RECOVERY_MOUNT_POINT "/recovery"
@@ -418,6 +420,20 @@
}
} else {
if (check_mac_perms(name, source_ctx, &cr)) {
+ // sys.powerctl is a special property that is used to make the device reboot. We want to log
+ // any process that sets this property to be able to accurately blame the cause of a shutdown.
+ if (name == "sys.powerctl") {
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+ std::string process_cmdline;
+ std::string process_log_string;
+ if (android::base::ReadFileToString(cmdline_path, &process_cmdline)) {
+ // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
+ process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+ }
+ LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+ << process_log_string;
+ }
+
uint32_t result = property_set(name, value);
if (!legacy_protocol) {
socket.SendUint32(result);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 891ca03..049c952 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -54,7 +54,7 @@
#include "init.h"
#include "property_service.h"
#include "service.h"
-#include "signal_handler.h"
+#include "sigchld_handler.h"
using android::base::StringPrintf;
using android::base::Timer;
@@ -169,9 +169,7 @@
<< stat;
}
-// Determines whether the system is capable of rebooting. This is conservative,
-// so if any of the attempts to determine this fail, it will still return true.
-static bool IsRebootCapable() {
+bool IsRebootCapable() {
if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) {
PLOG(WARNING) << "CAP_SYS_BOOT is not supported";
return true;
diff --git a/init/reboot.h b/init/reboot.h
index ece407f..1c58bd1 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -38,6 +38,10 @@
// Parses and handles a setprop sys.powerctl message.
bool HandlePowerctlMessage(const std::string& command);
+// Determines whether the system is capable of rebooting. This is conservative,
+// so if any of the attempts to determine this fail, it will still return true.
+bool IsRebootCapable();
+
} // namespace init
} // namespace android
diff --git a/init/signal_handler.cpp b/init/sigchld_handler.cpp
similarity index 98%
rename from init/signal_handler.cpp
rename to init/sigchld_handler.cpp
index 9e49c48..8fc9956 100644
--- a/init/signal_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "signal_handler.h"
+#include "sigchld_handler.h"
#include <signal.h>
#include <string.h>
@@ -115,7 +115,7 @@
}
}
-void signal_handler_init() {
+void sigchld_handler_init() {
// Create a signalling mechanism for SIGCHLD.
int s[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
diff --git a/init/signal_handler.h b/init/sigchld_handler.h
similarity index 88%
rename from init/signal_handler.h
rename to init/sigchld_handler.h
index 9362be5..c86dc8d 100644
--- a/init/signal_handler.h
+++ b/init/sigchld_handler.h
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#ifndef _INIT_SIGNAL_HANDLER_H_
-#define _INIT_SIGNAL_HANDLER_H_
+#ifndef _INIT_SIGCHLD_HANDLER_H_
+#define _INIT_SIGCHLD_HANDLER_H_
namespace android {
namespace init {
void ReapAnyOutstandingChildren();
-void signal_handler_init(void);
+void sigchld_handler_init(void);
} // namespace init
} // namespace android
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 3b2f38e..61812ab 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -41,8 +41,7 @@
#include "UnwindStack.h"
#include "UnwindStackMap.h"
-static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc,
- uintptr_t* offset) {
+static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) {
*offset = 0;
unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
@@ -52,7 +51,8 @@
return "";
}
- unwindstack::Elf* elf = map_info->GetElf(pid, true);
+ UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
+ unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
std::string name;
uint64_t func_offset;
@@ -68,10 +68,10 @@
return library == "libunwindstack.so" || library == "libbacktrace.so";
}
-static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
- BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
- size_t num_ignore_frames) {
- unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
+static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
+ std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
+ UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
+ unwindstack::Maps* maps = stack_map->stack_maps();
bool adjust_rel_pc = false;
size_t num_frames = 0;
frames->clear();
@@ -84,7 +84,7 @@
break;
}
- unwindstack::Elf* elf = map_info->GetElf(pid, true);
+ unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
@@ -137,7 +137,7 @@
break;
}
- if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) {
+ if (!elf->Step(rel_pc + map_info->elf_offset, regs, stack_map->process_memory().get())) {
break;
}
}
@@ -146,10 +146,10 @@
}
UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}
+ : BacktraceCurrent(pid, tid, map) {}
std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- return ::GetFunctionName(Pid(), GetMap(), pc, offset);
+ return ::GetFunctionName(GetMap(), pc, offset);
}
bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
@@ -165,14 +165,14 @@
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
- return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
+ return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
}
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}
+ : BacktracePtrace(pid, tid, map) {}
std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- return ::GetFunctionName(Pid(), GetMap(), pc, offset);
+ return ::GetFunctionName(GetMap(), pc, offset);
}
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
@@ -185,7 +185,7 @@
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
- return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
+ return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
}
Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index 32d1f51..be9ef63 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -35,9 +35,6 @@
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
-
- private:
- std::unique_ptr<unwindstack::Memory> memory_;
};
class UnwindStackPtrace : public BacktracePtrace {
@@ -48,9 +45,6 @@
bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-
- private:
- std::unique_ptr<unwindstack::Memory> memory_;
};
#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index ba9fd87..d4a2444 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -36,6 +36,9 @@
stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
}
+ // Create the process memory object.
+ process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_);
+
if (!stack_maps_->Parse()) {
return false;
}
@@ -68,7 +71,7 @@
if (map_info == nullptr) {
return;
}
- unwindstack::Elf* elf = map_info->GetElf(pid_, true);
+ unwindstack::Elf* elf = map_info->GetElf(process_memory_, true);
map->load_bias = elf->GetLoadBias();
}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 7885b74..b93b340 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -20,6 +20,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <memory>
+
#include <backtrace/BacktraceMap.h>
#include <unwindstack/Maps.h>
@@ -34,8 +36,11 @@
unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
+ const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
+
protected:
std::unique_ptr<unwindstack::Maps> stack_maps_;
+ std::shared_ptr<unwindstack::Memory> process_memory_;
};
#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index 54bfee5..cf03868 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -14,6 +14,7 @@
cc_library_static {
name: "libgrallocusage",
+ vendor_available: true,
cppflags: [
"-Weverything",
"-Werror",
@@ -26,4 +27,5 @@
srcs: ["GrallocUsageConversion.cpp"],
export_include_dirs: ["include"],
shared_libs: ["android.hardware.graphics.allocator@2.0"],
+ header_libs: ["libhardware_headers"],
}
diff --git a/liblog/Android.bp b/liblog/Android.bp
index e74aa82..b98d18f 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -42,6 +42,24 @@
"logd_writer.c",
]
+cc_library_headers {
+ name: "liblog_headers",
+ host_supported: true,
+ vendor_available: true,
+ export_include_dirs: ["include"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ vendor: {
+ export_include_dirs: ["include_vndk"],
+ },
+ },
+}
+
// Shared and static library for host and device
// ========================================================
cc_library {
@@ -81,7 +99,8 @@
},
},
- export_include_dirs: ["include"],
+ header_libs: ["liblog_headers"],
+ export_header_lib_headers: ["liblog_headers"],
cflags: [
"-Werror",
@@ -100,7 +119,7 @@
}
ndk_headers {
- name: "liblog_headers",
+ name: "liblog_ndk_headers",
from: "include/android",
to: "android",
srcs: ["include/android/log.h"],
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
index 5a3f04c..339a06d 100644
--- a/liblog/include/log/log_main.h
+++ b/liblog/include/log/log_main.h
@@ -18,10 +18,9 @@
#define _LIBS_LOG_LOG_MAIN_H
#include <android/log.h>
+#include <sys/cdefs.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
/*
* Normally we strip the effects of ALOGV (VERBOSE messages),
@@ -385,8 +384,6 @@
#pragma clang diagnostic pop
#endif
-#ifdef __cplusplus
-}
-#endif
+__END_DECLS
#endif /* _LIBS_LOG_LOG_MAIN_H */
diff --git a/liblog/local_logger.c b/liblog/local_logger.c
index 522867d..563cb3f 100644
--- a/liblog/local_logger.c
+++ b/liblog/local_logger.c
@@ -222,6 +222,7 @@
log->last[logId] = node->prev;
}
list_remove(node);
+ LOG_ALWAYS_FATAL_IF(node == log->last[logId], "corrupted list");
free(e);
}
/* add entry to list */
diff --git a/liblog/logprint.c b/liblog/logprint.c
index b62f8b4..a2839bf 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -250,6 +250,7 @@
while (!list_empty(&convertHead)) {
struct listnode* node = list_head(&convertHead);
list_remove(node);
+ LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list");
free(node);
}
}
diff --git a/libsync/sync.c b/libsync/sync.c
index baeccda..e657658 100644
--- a/libsync/sync.c
+++ b/libsync/sync.c
@@ -275,7 +275,6 @@
info = calloc(1, sizeof(struct sync_file_info) +
num_fences * sizeof(struct sync_fence_info));
if (!info) {
- free(legacy_info);
return NULL;
}
info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index b971a9e..32ba692 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -35,6 +35,10 @@
cc_library {
name: "libunwindstack",
vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
defaults: ["libunwindstack_flags"],
export_include_dirs: ["include"],
@@ -57,6 +61,13 @@
"Symbols.cpp",
],
+ target: {
+ // Always disable optimizations for host to make it easier to debug.
+ linux: {
+ cflags: ["-O0", "-g"],
+ },
+ },
+
arch: {
x86: {
srcs: ["AsmGetRegsX86.S"],
@@ -97,7 +108,6 @@
"tests/ElfTest.cpp",
"tests/ElfTestUtils.cpp",
"tests/LogFake.cpp",
- "tests/MapInfoCreateMemoryTest.cpp",
"tests/MapInfoGetElfTest.cpp",
"tests/MapsTest.cpp",
"tests/MemoryBufferTest.cpp",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 3272215..96f2cb4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
@@ -76,40 +77,39 @@
return memory.release();
}
-Memory* MapInfo::CreateMemory(pid_t pid) {
+Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
if (end <= start) {
return nullptr;
}
elf_offset = 0;
+ // Fail on device maps.
+ if (flags & MAPS_FLAGS_DEVICE_MAP) {
+ return nullptr;
+ }
+
// First try and use the file associated with the info.
if (!name.empty()) {
- // Fail on device maps.
- if (flags & MAPS_FLAGS_DEVICE_MAP) {
- return nullptr;
- }
Memory* memory = GetFileMemory();
if (memory != nullptr) {
return memory;
}
}
- Memory* memory;
- if (pid == getpid()) {
- memory = new MemoryLocal();
- } else {
- memory = new MemoryRemote(pid);
+ // If the map isn't readable, don't bother trying to read from process memory.
+ if (!(flags & PROT_READ)) {
+ return nullptr;
}
- return new MemoryRange(memory, start, end);
+ return new MemoryRange(process_memory, start, end);
}
-Elf* MapInfo::GetElf(pid_t pid, bool init_gnu_debugdata) {
+Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
if (elf) {
return elf;
}
- elf = new Elf(CreateMemory(pid));
+ elf = new Elf(CreateMemory(process_memory));
if (elf->Init() && init_gnu_debugdata) {
elf->InitGnuDebugdata();
}
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 8c36055..32753df 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -52,6 +52,13 @@
return false;
}
+std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
+ if (pid == getpid()) {
+ return std::shared_ptr<Memory>(new MemoryLocal());
+ }
+ return std::shared_ptr<Memory>(new MemoryRemote(pid));
+}
+
bool MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
uint64_t last_read_byte;
if (__builtin_add_overflow(size, addr, &last_read_byte)) {
@@ -249,7 +256,7 @@
return true;
}
-MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
+MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end)
: memory_(memory), begin_(begin), length_(end - begin) {
CHECK(end > begin);
}
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index b8ba925..f108766 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -40,10 +40,13 @@
// instead of a portion of the file.
uint64_t elf_offset;
- Memory* GetFileMemory();
- Memory* CreateMemory(pid_t pid);
// This function guarantees it will never return nullptr.
- Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
+ Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
+
+ private:
+ Memory* GetFileMemory();
+
+ Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 0c05266..183b899 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <memory>
#include <string>
#include <vector>
@@ -31,6 +32,8 @@
Memory() = default;
virtual ~Memory() = default;
+ static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+
virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
virtual bool Read(uint64_t addr, void* dst, size_t size) = 0;
@@ -125,13 +128,13 @@
class MemoryRange : public Memory {
public:
- MemoryRange(Memory* memory, uint64_t begin, uint64_t end);
- virtual ~MemoryRange() { delete memory_; }
+ MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t end);
+ virtual ~MemoryRange() = default;
bool Read(uint64_t addr, void* dst, size_t size) override;
private:
- Memory* memory_;
+ std::shared_ptr<Memory> memory_;
uint64_t begin_;
uint64_t length_;
};
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2aab9c6..d2aad49 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -34,6 +34,8 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
+#include "MemoryFake.h"
+
namespace unwindstack {
class MapInfoCreateMemoryTest : public ::testing::Test {
@@ -71,6 +73,14 @@
InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
}
+ void SetUp() override {
+ memory_ = new MemoryFake;
+ process_memory_.reset(memory_);
+ }
+
+ MemoryFake* memory_;
+ std::shared_ptr<Memory> process_memory_;
+
static TemporaryFile elf_;
static TemporaryFile elf_at_100_;
@@ -86,17 +96,16 @@
TEST_F(MapInfoCreateMemoryTest, end_le_start) {
MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
- std::unique_ptr<Memory> memory;
- memory.reset(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
info.end = 0xff;
- memory.reset(info.CreateMemory(getpid()));
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
// Make sure this test is valid.
info.end = 0x101;
- memory.reset(info.CreateMemory(getpid()));
+ memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
}
@@ -105,7 +114,7 @@
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
- std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0x100U, info.elf_offset);
@@ -126,7 +135,7 @@
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
- std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -149,7 +158,7 @@
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
MapInfo info{.start = 0x5000, .end = 0x6000, .offset = 0x1000, .name = elf32_at_map_.path};
- std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -165,7 +174,7 @@
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
MapInfo info{.start = 0x7000, .end = 0x8000, .offset = 0x2000, .name = elf64_at_map_.path};
- std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
ASSERT_EQ(0U, info.elf_offset);
@@ -187,81 +196,38 @@
info.start = reinterpret_cast<uint64_t>(buffer.data());
info.end = info.start + buffer.size();
info.offset = 0;
- std::unique_ptr<Memory> memory;
info.flags = 0x8000;
info.name = "/dev/something";
- memory.reset(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() == nullptr);
}
-TEST_F(MapInfoCreateMemoryTest, local_memory) {
- // Set up some memory for a valid local memory object.
+TEST_F(MapInfoCreateMemoryTest, process_memory) {
+ MapInfo info;
+ info.start = 0x2000;
+ info.end = 0x3000;
+ info.offset = 0;
+
+ // Verify that the the process_memory object is used, so seed it
+ // with memory.
std::vector<uint8_t> buffer(1024);
for (size_t i = 0; i < buffer.size(); i++) {
buffer[i] = i % 256;
}
+ memory_->SetMemory(info.start, buffer.data(), buffer.size());
- MapInfo info;
- info.start = reinterpret_cast<uint64_t>(buffer.data());
- info.end = info.start + buffer.size();
- info.offset = 0;
-
- std::unique_ptr<Memory> memory;
- memory.reset(info.CreateMemory(getpid()));
+ std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
- std::vector<uint8_t> read_buffer(1024);
- ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
- for (size_t i = 0; i < read_buffer.size(); i++) {
- ASSERT_EQ(i % 256, read_buffer[i]) << "Failed at byte " << i;
+ memset(buffer.data(), 0, buffer.size());
+ ASSERT_TRUE(memory->Read(0, buffer.data(), buffer.size()));
+ for (size_t i = 0; i < buffer.size(); i++) {
+ ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
}
- ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
-}
-
-TEST_F(MapInfoCreateMemoryTest, remote_memory) {
- std::vector<uint8_t> buffer(1024);
- memset(buffer.data(), 0xa, buffer.size());
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
-
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) != -1);
- uint64_t iterations = 0;
- siginfo_t si;
- while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
- usleep(30);
- iterations++;
- ASSERT_LT(iterations, 500000000ULL);
- }
-
- MapInfo info;
- info.start = reinterpret_cast<uint64_t>(buffer.data());
- info.end = info.start + buffer.size();
- info.offset = 0;
-
- std::unique_ptr<Memory> memory;
- memory.reset(info.CreateMemory(pid));
- ASSERT_TRUE(memory.get() != nullptr);
- // Set the local memory to a different value to guarantee we are reading
- // from the remote process.
- memset(buffer.data(), 0x1, buffer.size());
- std::vector<uint8_t> read_buffer(1024);
- ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
- for (size_t i = 0; i < read_buffer.size(); i++) {
- ASSERT_EQ(0xaU, read_buffer[i]) << "Failed at byte " << i;
- }
-
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
+ // Try to read outside of the map size.
+ ASSERT_FALSE(memory->Read(buffer.size(), buffer.data(), 1));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index abfa172..0b70d13 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -32,43 +32,57 @@
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include "ElfTestUtils.h"
+#include "MemoryFake.h"
namespace unwindstack {
class MapInfoGetElfTest : public ::testing::Test {
protected:
void SetUp() override {
- map_ = mmap(nullptr, kMapSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- ASSERT_NE(MAP_FAILED, map_);
-
- uint64_t start = reinterpret_cast<uint64_t>(map_);
- info_.reset(new MapInfo{.start = start, .end = start + 1024, .offset = 0, .name = ""});
+ memory_ = new MemoryFake;
+ process_memory_.reset(memory_);
}
- void TearDown() override { munmap(map_, kMapSize); }
+ template <typename Ehdr, typename Shdr>
+ static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) {
+ memset(ehdr, 0, sizeof(*ehdr));
+ memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+ ehdr->e_ident[EI_CLASS] = class_type;
+ ehdr->e_machine = machine_type;
+ ehdr->e_shoff = sh_offset;
+ ehdr->e_shentsize = sizeof(Shdr) + 100;
+ ehdr->e_shnum = 4;
+ }
const size_t kMapSize = 4096;
- void* map_ = nullptr;
- std::unique_ptr<MapInfo> info_;
+ std::shared_ptr<Memory> process_memory_;
+ MemoryFake* memory_;
+
+ TemporaryFile elf_;
};
TEST_F(MapInfoGetElfTest, invalid) {
+ MapInfo info{.start = 0x1000, .end = 0x2000, .offset = 0, .flags = PROT_READ, .name = ""};
+
// The map is empty, but this should still create an invalid elf object.
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, valid32) {
+ MapInfo info{.start = 0x3000, .end = 0x4000, .offset = 0, .flags = PROT_READ, .name = ""};
+
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memcpy(map_, &ehdr, sizeof(ehdr));
+ memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -76,11 +90,13 @@
}
TEST_F(MapInfoGetElfTest, valid64) {
+ MapInfo info{.start = 0x8000, .end = 0x9000, .offset = 0, .flags = PROT_READ, .name = ""};
+
Elf64_Ehdr ehdr;
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
- memcpy(map_, &ehdr, sizeof(ehdr));
+ memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -88,12 +104,14 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
- ELFCLASS32, EM_ARM, false, [&](uint64_t offset, const void* ptr, size_t size) {
- memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
- });
+ MapInfo info{.start = 0x4000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(0x4000 + offset, ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -102,12 +120,14 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
- ELFCLASS64, EM_AARCH64, false, [&](uint64_t offset, const void* ptr, size_t size) {
- memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
- });
+ MapInfo info{.start = 0x6000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), false));
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(0x6000 + offset, ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -116,12 +136,14 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(
- ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) {
- memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
- });
+ MapInfo info{.start = 0x2000, .end = 0x3000, .offset = 0, .flags = PROT_READ, .name = ""};
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+ TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(0x2000 + offset, ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -130,12 +152,14 @@
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(
- ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) {
- memcpy(&reinterpret_cast<uint8_t*>(map_)[offset], ptr, size);
- });
+ MapInfo info{.start = 0x5000, .end = 0x8000, .offset = 0, .flags = PROT_READ, .name = ""};
- std::unique_ptr<Elf> elf(info_->GetElf(getpid(), true));
+ TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
+ [&](uint64_t offset, const void* ptr, size_t size) {
+ memory_->SetMemory(0x5000 + offset, ptr, size);
+ });
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, true));
ASSERT_TRUE(elf.get() != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -143,4 +167,195 @@
EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
}
+TEST_F(MapInfoGetElfTest, end_le_start) {
+ MapInfo info{.start = 0x1000, .end = 0x1000, .offset = 0, .flags = PROT_READ, .name = elf_.path};
+
+ Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_FALSE(elf->valid());
+
+ info.elf = nullptr;
+ info.end = 0xfff;
+ elf.reset(info.GetElf(process_memory_, false));
+ ASSERT_FALSE(elf->valid());
+
+ // Make sure this test is valid.
+ info.elf = nullptr;
+ info.end = 0x2000;
+ elf.reset(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+}
+
+// Verify that if the offset is non-zero but there is no elf at the offset,
+// that the full file is used.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
+ MapInfo info{
+ .start = 0x1000, .end = 0x2000, .offset = 0x100, .flags = PROT_READ, .name = elf_.path};
+
+ std::vector<uint8_t> buffer(0x1000);
+ memset(buffer.data(), 0, buffer.size());
+ Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ memcpy(buffer.data(), &ehdr, sizeof(ehdr));
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+ ASSERT_TRUE(elf->memory() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+
+ // Read the entire file.
+ memset(buffer.data(), 0, buffer.size());
+ ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), buffer.size()));
+ ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+ for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
+ ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_FALSE(elf->memory()->Read(buffer.size(), buffer.data(), 1));
+}
+
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
+ MapInfo info{
+ .start = 0x1000, .end = 0x2000, .offset = 0x2000, .flags = PROT_READ, .name = elf_.path};
+
+ std::vector<uint8_t> buffer(0x4000);
+ memset(buffer.data(), 0, buffer.size());
+ Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+ ASSERT_TRUE(elf->memory() != nullptr);
+ ASSERT_EQ(0U, info.elf_offset);
+
+ // Read the valid part of the file.
+ ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+ ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+ for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
+ ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_FALSE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used. Further verify that if the
+// embedded elf is bigger than the initial map, the new object is larger
+// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
+ MapInfo info{
+ .start = 0x5000, .end = 0x6000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+
+ std::vector<uint8_t> buffer(0x4000);
+ memset(buffer.data(), 0, buffer.size());
+ Elf32_Ehdr ehdr;
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ ehdr.e_shoff = 0x2000;
+ ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
+ ehdr.e_shnum = 4;
+ memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+ ASSERT_TRUE(elf->memory() != nullptr);
+ ASSERT_EQ(0U, info.elf_offset);
+
+ // Verify the memory is a valid elf.
+ memset(buffer.data(), 0, buffer.size());
+ ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+ ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+
+ // Read past the end of what would normally be the size of the map.
+ ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
+ MapInfo info{
+ .start = 0x7000, .end = 0x8000, .offset = 0x1000, .flags = PROT_READ, .name = elf_.path};
+
+ std::vector<uint8_t> buffer(0x4000);
+ memset(buffer.data(), 0, buffer.size());
+ Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+ ehdr.e_shoff = 0x2000;
+ ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+ ehdr.e_shnum = 4;
+ memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+ ASSERT_TRUE(elf->memory() != nullptr);
+ ASSERT_EQ(0U, info.elf_offset);
+
+ // Verify the memory is a valid elf.
+ memset(buffer.data(), 0, buffer.size());
+ ASSERT_TRUE(elf->memory()->Read(0, buffer.data(), 0x1000));
+ ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
+
+ // Read past the end of what would normally be the size of the map.
+ ASSERT_TRUE(elf->memory()->Read(0x1000, buffer.data(), 1));
+}
+
+TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
+ MapInfo info{.start = 0x9000, .end = 0xa000, .offset = 0x1000, .flags = 0, .name = ""};
+
+ // Create valid elf data in process memory only.
+ Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+ ehdr.e_shoff = 0x2000;
+ ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+ ehdr.e_shnum = 4;
+ memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_FALSE(elf->valid());
+
+ info.elf = nullptr;
+ info.flags = PROT_READ;
+ elf.reset(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+}
+
+TEST_F(MapInfoGetElfTest, check_device_maps) {
+ MapInfo info{.start = 0x7000,
+ .end = 0x8000,
+ .offset = 0x1000,
+ .flags = PROT_READ | MAPS_FLAGS_DEVICE_MAP,
+ .name = "/dev/something"};
+
+ // Create valid elf data in process memory for this to verify that only
+ // the name is causing invalid elf data.
+ Elf64_Ehdr ehdr;
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
+ ehdr.e_shoff = 0x2000;
+ ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
+ ehdr.e_shnum = 4;
+ memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
+
+ std::unique_ptr<Elf> elf(info.GetElf(process_memory_, false));
+ ASSERT_FALSE(elf->valid());
+
+ // Set the name to nothing to verify that it still fails.
+ info.elf = nullptr;
+ info.name = "";
+ elf.reset(info.GetElf(process_memory_, false));
+ ASSERT_FALSE(elf->valid());
+
+ // Change the flags and verify the elf is valid now.
+ info.elf = nullptr;
+ info.flags = PROT_READ;
+ elf.reset(info.GetElf(process_memory_, false));
+ ASSERT_TRUE(elf->valid());
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 6d1366c..680fae9 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -31,10 +31,11 @@
TEST(MemoryRangeTest, read) {
std::vector<uint8_t> src(1024);
memset(src.data(), 0x4c, 1024);
- MemoryFake* memory = new MemoryFake;
- memory->SetMemory(9001, src);
+ MemoryFake* memory_fake = new MemoryFake;
+ std::shared_ptr<Memory> process_memory(memory_fake);
+ memory_fake->SetMemory(9001, src);
- MemoryRange range(memory, 9001, 9001 + src.size());
+ MemoryRange range(process_memory, 9001, 9001 + src.size());
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(0, dst.data(), src.size()));
@@ -46,10 +47,11 @@
TEST(MemoryRangeTest, read_near_limit) {
std::vector<uint8_t> src(4096);
memset(src.data(), 0x4c, 4096);
- MemoryFake* memory = new MemoryFake;
- memory->SetMemory(1000, src);
+ MemoryFake* memory_fake = new MemoryFake;
+ std::shared_ptr<Memory> process_memory(memory_fake);
+ memory_fake->SetMemory(1000, src);
- MemoryRange range(memory, 1000, 2024);
+ MemoryRange range(process_memory, 1000, 2024);
std::vector<uint8_t> dst(1024);
ASSERT_TRUE(range.Read(1020, dst.data(), 4));
@@ -69,7 +71,8 @@
TEST(MemoryRangeTest, read_overflow) {
std::vector<uint8_t> buffer(100);
- std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200));
+ std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
+ std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200));
ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
}
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index f8965b2..a66d0c5 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -22,7 +22,6 @@
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/types.h>
-#include <time.h>
#include <unistd.h>
#include <vector>
@@ -34,32 +33,18 @@
#include <unwindstack/Memory.h>
#include "MemoryFake.h"
+#include "TestUtils.h"
namespace unwindstack {
class MemoryRemoteTest : public ::testing::Test {
protected:
- static uint64_t NanoTime() {
- struct timespec t = { 0, 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
- return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
- }
-
static bool Attach(pid_t pid) {
if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
return false;
}
- uint64_t start = NanoTime();
- siginfo_t si;
- while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
- if ((NanoTime() - start) > 10 * NS_PER_SEC) {
- printf("%d: Failed to stop after 10 seconds.\n", pid);
- return false;
- }
- usleep(30);
- }
- return true;
+ return TestQuiescePid(pid);
}
static bool Detach(pid_t pid) {
@@ -79,6 +64,7 @@
exit(1);
}
ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
@@ -91,9 +77,6 @@
}
ASSERT_TRUE(Detach(pid));
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
}
TEST_F(MemoryRemoteTest, read_fail) {
@@ -111,6 +94,7 @@
exit(1);
}
ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
@@ -132,9 +116,6 @@
ASSERT_EQ(0, munmap(src, pagesize));
ASSERT_TRUE(Detach(pid));
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
}
TEST_F(MemoryRemoteTest, read_overflow) {
@@ -152,6 +133,7 @@
exit(1);
}
ASSERT_LT(0, pid);
+ TestScopedPidReaper reap(pid);
ASSERT_TRUE(Attach(pid));
@@ -162,9 +144,6 @@
ASSERT_FALSE(remote.Read(0, dst.data(), 100));
ASSERT_TRUE(Detach(pid));
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
new file mode 100644
index 0000000..8c31aa6
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
+
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+namespace unwindstack {
+
+class TestScopedPidReaper {
+ public:
+ TestScopedPidReaper(pid_t pid) : pid_(pid) {}
+ ~TestScopedPidReaper() {
+ kill(pid_, SIGKILL);
+ waitpid(pid_, nullptr, 0);
+ }
+
+ private:
+ pid_t pid_;
+};
+
+inline bool TestQuiescePid(pid_t pid) {
+ siginfo_t si;
+ bool ready = false;
+ // Wait for up to 5 seconds.
+ for (size_t i = 0; i < 5000; i++) {
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ ready = true;
+ break;
+ }
+ usleep(1000);
+ }
+ return ready;
+}
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 2fc3a38..a4f920a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -15,10 +15,9 @@
*/
#include <errno.h>
-#include <string.h>
-
#include <signal.h>
#include <stdint.h>
+#include <string.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <unistd.h>
@@ -39,14 +38,24 @@
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
+#include "TestUtils.h"
+
namespace unwindstack {
-static std::atomic_bool g_ready(false);
-static volatile bool g_ready_for_remote = false;
-static volatile bool g_signal_ready_for_remote = false;
-static std::atomic_bool g_finish(false);
+static std::atomic_bool g_ready;
+static volatile bool g_ready_for_remote;
+static volatile bool g_signal_ready_for_remote;
+static std::atomic_bool g_finish;
static std::atomic_uintptr_t g_ucontext;
+static void ResetGlobals() {
+ g_ready = false;
+ g_ready_for_remote = false;
+ g_signal_ready_for_remote = false;
+ g_finish = false;
+ g_ucontext = 0;
+}
+
static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
@@ -85,10 +94,11 @@
function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
}
-static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
+static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs,
std::vector<const char*>& function_names) {
size_t function_name_index = 0;
+ auto process_memory = Memory::CreateProcessMemory(pid);
std::stringstream unwind_stream;
unwind_stream << std::hex;
for (size_t frame_num = 0; frame_num < 64; frame_num++) {
@@ -96,7 +106,7 @@
MapInfo* map_info = maps->Find(regs->pc());
ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
- Elf* elf = map_info->GetElf(pid, true);
+ Elf* elf = map_info->GetElf(process_memory, true);
uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
uint64_t adjusted_rel_pc = rel_pc;
if (frame_num != 0) {
@@ -122,7 +132,7 @@
unwind_stream << " " << name;
}
unwind_stream << "\n";
- ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, memory))
+ ASSERT_TRUE(elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get()))
<< ErrorMsg(function_names, function_name_index, unwind_stream);
}
ASSERT_TRUE(false) << ErrorMsg(function_names, function_name_index, unwind_stream);
@@ -137,9 +147,8 @@
ASSERT_TRUE(maps.Parse());
std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
RegsGetLocal(regs.get());
- MemoryLocal memory;
- VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
+ VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
} else {
g_ready_for_remote = true;
g_ready = true;
@@ -156,48 +165,52 @@
MiddleFunction(local);
}
-TEST(UnwindTest, local) {
+class UnwindTest : public ::testing::Test {
+ public:
+ void SetUp() override { ResetGlobals(); }
+};
+
+TEST_F(UnwindTest, local) {
OuterFunction(true);
}
void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
*completed = false;
// Need to sleep before attempting first ptrace. Without this, on the
- // host it becomes impossible to attach and ptrace set errno to EPERM.
+ // host it becomes impossible to attach and ptrace sets errno to EPERM.
usleep(1000);
- for (size_t i = 0; i < 100; i++) {
- ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
- for (size_t j = 0; j < 100; j++) {
- siginfo_t si;
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- MemoryRemote memory(pid);
- // Read the remote value to see if we are ready.
- bool value;
- if (memory.Read(addr, &value, sizeof(value)) && value) {
- *completed = true;
- break;
- }
+ for (size_t i = 0; i < 1000; i++) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
+ ASSERT_TRUE(TestQuiescePid(pid))
+ << "Waiting for process to quiesce failed: " << strerror(errno);
+
+ MemoryRemote memory(pid);
+ // Read the remote value to see if we are ready.
+ bool value;
+ if (memory.Read(addr, &value, sizeof(value)) && value) {
+ *completed = true;
}
- usleep(1000);
+ if (!*completed || !leave_attached) {
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+ }
+ if (*completed) {
+ break;
+ }
+ } else {
+ ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno);
}
- if (leave_attached && *completed) {
- break;
- }
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
- if (*completed) {
- break;
- }
- usleep(1000);
+ usleep(5000);
}
}
-TEST(UnwindTest, remote) {
+TEST_F(UnwindTest, remote) {
pid_t pid;
if ((pid = fork()) == 0) {
OuterFunction(false);
exit(0);
}
ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
bool completed;
WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
@@ -205,19 +218,16 @@
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
- MemoryRemote memory(pid);
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
ASSERT_TRUE(regs.get() != nullptr);
- VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
+ VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
-TEST(UnwindTest, from_context) {
+TEST_F(UnwindTest, from_context) {
std::atomic_int tid(0);
std::thread thread([&]() {
tid = syscall(__NR_gettid);
@@ -254,9 +264,8 @@
LocalMaps maps;
ASSERT_TRUE(maps.Parse());
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
- MemoryLocal memory;
- VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
+ VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
@@ -265,10 +274,6 @@
}
static void RemoteThroughSignal(unsigned int sa_flags) {
- g_ready = false;
- g_signal_ready_for_remote = false;
- g_finish = false;
-
pid_t pid;
if ((pid = fork()) == 0) {
struct sigaction act, oldact;
@@ -281,6 +286,7 @@
exit(0);
}
ASSERT_NE(-1, pid);
+ TestScopedPidReaper reap(pid);
bool completed;
WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
@@ -291,23 +297,20 @@
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
- MemoryRemote memory(pid);
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
ASSERT_TRUE(regs.get() != nullptr);
- VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
+ VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
-
- kill(pid, SIGKILL);
- ASSERT_EQ(pid, wait(nullptr));
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+ << "ptrace detach failed with unexpected error: " << strerror(errno);
}
-TEST(UnwindTest, remote_through_signal) {
+TEST_F(UnwindTest, remote_through_signal) {
RemoteThroughSignal(0);
}
-TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+TEST_F(UnwindTest, remote_through_signal_sa_siginfo) {
RemoteThroughSignal(SA_SIGINFO);
}
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index c1077f8..3614198 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -91,7 +91,7 @@
}
printf("\n");
- unwindstack::MemoryRemote remote_memory(pid);
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
for (size_t frame_num = 0; frame_num < 64; frame_num++) {
if (regs->pc() == 0) {
break;
@@ -102,7 +102,7 @@
break;
}
- unwindstack::Elf* elf = map_info->GetElf(pid, true);
+ unwindstack::Elf* elf = map_info->GetElf(process_memory, true);
uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
uint64_t adjusted_rel_pc = rel_pc;
@@ -135,7 +135,7 @@
}
printf("\n");
- if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) {
+ if (!elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) {
break;
}
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index adcde81..038fd73 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -18,10 +18,12 @@
host_supported: true,
header_libs: [
+ "liblog_headers",
"libsystem_headers",
"libcutils_headers"
],
export_header_lib_headers: [
+ "liblog_headers",
"libsystem_headers",
"libcutils_headers"
],
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 28fc351..73ec1be 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -23,9 +23,9 @@
#include <utils/SystemClock.h>
-#include <sys/time.h>
#include <string.h>
#include <errno.h>
+#include <time.h>
#include <cutils/compiler.h>