Merge "adbd: Don't close/reopen FFS ep0 on disconnect"
diff --git a/adb/adb.c b/adb/adb.c
index 41270f9..665e958 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -39,6 +39,8 @@
#include <sys/capability.h>
#include <linux/prctl.h>
#include <sys/mount.h>
+#include <getopt.h>
+#include <selinux/selinux.h>
#else
#include "usb_vendors.h"
#endif
@@ -54,6 +56,7 @@
#if !ADB_HOST
static const char *adb_device_banner = "device";
+static const char *root_seclabel = NULL;
#endif
void fatal(const char *fmt, ...)
@@ -1356,6 +1359,12 @@
D("Local port disabled\n");
} else {
char local_name[30];
+ if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
+ // b/12587913: fix setcon to allow const pointers
+ if (setcon((char *)root_seclabel) < 0) {
+ exit(1);
+ }
+ }
build_local_name(local_name, sizeof(local_name), server_port);
if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
exit(1);
@@ -1642,10 +1651,6 @@
return -1;
}
-#if !ADB_HOST
-int recovery_mode = 0;
-#endif
-
int main(int argc, char **argv)
{
#if ADB_HOST
@@ -1657,9 +1662,26 @@
/* If adbd runs inside the emulator this will enable adb tracing via
* adb-debug qemud service in the emulator. */
adb_qemu_trace_init();
- if((argc > 1) && (!strcmp(argv[1],"recovery"))) {
- adb_device_banner = "recovery";
- recovery_mode = 1;
+ while(1) {
+ int c;
+ int option_index = 0;
+ static struct option opts[] = {
+ {"root_seclabel", required_argument, 0, 's' },
+ {"device_banner", required_argument, 0, 'b' }
+ };
+ c = getopt_long(argc, argv, "", opts, &option_index);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 's':
+ root_seclabel = optarg;
+ break;
+ case 'b':
+ adb_device_banner = optarg;
+ break;
+ default:
+ break;
+ }
}
start_device_log();
diff --git a/adb/adb_client.c b/adb/adb_client.c
index f7823a8..586cd7b 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -241,7 +241,7 @@
} else {
// if server was running, check its version to make sure it is not out of date
char buf[100];
- int n;
+ size_t n;
int version = ADB_SERVER_VERSION - 1;
// if we have a file descriptor, then parse version result
@@ -250,7 +250,7 @@
buf[4] = 0;
n = strtoul(buf, 0, 16);
- if(n > (int)sizeof(buf)) goto error;
+ if(n > sizeof(buf)) goto error;
if(readx(fd, buf, n)) goto error;
adb_close(fd);
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index c30f9fb..577fb8f 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -43,11 +43,10 @@
{
int ret;
char *x = name + 1;
- unsigned int uid, gid;
+ uid_t uid = -1;
+ gid_t gid = -1;
unsigned int mode = 0775;
uint64_t cap = 0;
- uid = getuid();
- gid = getgid();
if(name[0] != '/') return -1;
@@ -172,8 +171,8 @@
return fail_message(s, strerror(errno));
}
-static int handle_send_file(int s, char *path, unsigned int uid,
- unsigned int gid, mode_t mode, char *buffer)
+static int handle_send_file(int s, char *path, uid_t uid,
+ gid_t gid, mode_t mode, char *buffer)
{
syncmsg msg;
unsigned int timestamp = 0;
@@ -201,11 +200,13 @@
fail_errno(s);
errno = 0;
}
- /* fchown clears the setuid bit - restore it if present */
- if(fchmod(fd, mode) != 0) {
- fail_errno(s);
- errno = 0;
- }
+
+ /*
+ * fchown clears the setuid bit - restore it if present.
+ * Ignore the result of calling fchmod. It's not supported
+ * by all filesystems. b/12441485
+ */
+ fchmod(fd, mode);
}
for(;;) {
@@ -350,10 +351,9 @@
#else
{
#endif
- unsigned int uid, gid;
+ uid_t uid = -1;
+ gid_t gid = -1;
uint64_t cap = 0;
- uid = getuid();
- gid = getgid();
/* copy user permission bits to "group" and "other" permissions */
mode |= ((mode >> 3) & 0070);
diff --git a/adb/services.c b/adb/services.c
index 951048e..1c9db0d 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -86,7 +86,7 @@
{
char buf[100];
char value[PROPERTY_VALUE_MAX];
- int port = (int)cookie;
+ int port = (int) (uintptr_t) cookie;
if (port <= 0) {
snprintf(buf, sizeof(buf), "invalid port\n");
@@ -269,7 +269,7 @@
#if !ADB_HOST
static void subproc_waiter_service(int fd, void *cookie)
{
- pid_t pid = (pid_t)cookie;
+ pid_t pid = (pid_t) (uintptr_t) cookie;
D("entered. fd=%d of pid=%d\n", fd, pid);
for (;;) {
@@ -314,7 +314,7 @@
sti = malloc(sizeof(stinfo));
if(sti == 0) fatal("cannot allocate stinfo");
sti->func = subproc_waiter_service;
- sti->cookie = (void*)pid;
+ sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd;
if(adb_thread_create( &t, service_bootstrap_func, sti)){
@@ -397,7 +397,7 @@
if (sscanf(name + 6, "%d", &port) == 0) {
port = 0;
}
- ret = create_service_thread(restart_tcp_service, (void *)port);
+ ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread(restart_usb_service, NULL);
#endif
diff --git a/adb/sockets.c b/adb/sockets.c
index 7f54ad9..de14a22 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -342,7 +342,7 @@
while(avail > 0) {
r = adb_read(fd, x, avail);
- D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%d\n", s->id, s->fd, r, r<0?errno:0, avail);
+ D("LS(%d): post adb_read(fd=%d,...) r=%d (errno=%d) avail=%zu\n", s->id, s->fd, r, r<0?errno:0, avail);
if(r > 0) {
avail -= r;
x += r;
diff --git a/adb/transport.c b/adb/transport.c
index 224fe55..6002530 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -1142,9 +1142,9 @@
char *p = ptr;
int r;
#if ADB_TRACE
- int len0 = len;
+ size_t len0 = len;
#endif
- D("readx: fd=%d wanted=%d\n", fd, (int)len);
+ D("readx: fd=%d wanted=%zu\n", fd, len);
while(len > 0) {
r = adb_read(fd, p, len);
if(r > 0) {
@@ -1163,7 +1163,7 @@
}
#if ADB_TRACE
- D("readx: fd=%d wanted=%d got=%d\n", fd, len0, len0 - len);
+ D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
dump_hex( ptr, len0 );
#endif
return 0;
diff --git a/adb/transport_local.c b/adb/transport_local.c
index 1cfa24d..d2dbca6 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -159,7 +159,7 @@
int serverfd, fd;
struct sockaddr addr;
socklen_t alen;
- int port = (int)arg;
+ int port = (int) (uintptr_t) arg;
D("transport: server_socket_thread() starting\n");
serverfd = -1;
@@ -241,7 +241,7 @@
/* 'ok' reply from the adb QEMUD service. */
static const char _ok_resp[] = "ok";
- const int port = (int)arg;
+ const int port = (int) (uintptr_t) arg;
int res, fd;
char tmp[256];
char con_name[32];
@@ -326,7 +326,7 @@
D("transport: local %s init\n", HOST ? "client" : "server");
- if(adb_thread_create(&thr, func, (void *)port)) {
+ if(adb_thread_create(&thr, func, (void *) (uintptr_t) port)) {
fatal_errno("cannot create local socket %s thread",
HOST ? "client" : "server");
}
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 7bf2057..8ff753e 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -179,7 +179,7 @@
// should have device and configuration descriptors, and atleast two endpoints
if (desclength < USB_DT_DEVICE_SIZE + USB_DT_CONFIG_SIZE) {
- D("desclength %d is too small\n", desclength);
+ D("desclength %zu is too small\n", desclength);
adb_close(fd);
continue;
}
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index f20772b..8426e0e 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -386,7 +386,7 @@
ret = adb_read(bulk_out, buf + count, length - count);
if (ret < 0) {
if (errno != EINTR) {
- D("[ bulk_read failed fd=%d length=%d count=%d ]\n",
+ D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n",
bulk_out, length, count);
return ret;
}
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index df1244f..cd5885e 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -58,6 +58,8 @@
#define VENDOR_ID_ECS 0x03fc
// EMERGING_TECH's USB Vendor ID
#define VENDOR_ID_EMERGING_TECH 0x297F
+// Emerson's USB Vendor ID
+#define VENDOR_ID_EMERSON 0x2207
// Foxconn's USB Vendor ID
#define VENDOR_ID_FOXCONN 0x0489
// Fujitsu's USB Vendor ID
@@ -78,6 +80,8 @@
#define VENDOR_ID_HARRIS 0x19A5
// Hisense's USB Vendor ID
#define VENDOR_ID_HISENSE 0x109b
+// HP's USB Vendor ID
+#define VENDOR_ID_HP 0x03f0
// HTC's USB Vendor ID
#define VENDOR_ID_HTC 0x0bb4
// Huawei's USB Vendor ID
@@ -190,6 +194,7 @@
VENDOR_ID_DELL,
VENDOR_ID_ECS,
VENDOR_ID_EMERGING_TECH,
+ VENDOR_ID_EMERSON,
VENDOR_ID_FOXCONN,
VENDOR_ID_FUJITSU,
VENDOR_ID_FUNAI,
@@ -200,6 +205,7 @@
VENDOR_ID_HAIER,
VENDOR_ID_HARRIS,
VENDOR_ID_HISENSE,
+ VENDOR_ID_HP,
VENDOR_ID_HTC,
VENDOR_ID_HUAWEI,
VENDOR_ID_INQ_MOBILE,
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 2fe7c7a..422a86a 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -6,14 +6,20 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- backtrace.c \
- debuggerd.c \
- getevent.c \
- tombstone.c \
- utility.c \
- $(TARGET_ARCH)/machine.c
+ backtrace.cpp \
+ debuggerd.cpp \
+ getevent.cpp \
+ tombstone.cpp \
+ utility.cpp \
+ $(TARGET_ARCH)/machine.cpp \
-LOCAL_CFLAGS := -Wall -Wno-unused-parameter -std=gnu99
+LOCAL_CONLYFLAGS := -std=gnu99
+LOCAL_CPPFLAGS := -std=gnu++11
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-array-bounds \
+ -Werror \
+
LOCAL_MODULE := debuggerd
ifeq ($(ARCH_ARM_HAVE_VFP),true)
@@ -30,6 +36,8 @@
liblog \
libselinux \
+include external/stlport/libstlport.mk
+
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
@@ -38,7 +46,7 @@
LOCAL_MODULE := crasher
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all
+LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
deleted file mode 100644
index 4ab6026..0000000
--- a/debuggerd/arm/machine.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* system/debuggerd/debuggerd.c
-**
-** Copyright 2006, 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 <errno.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-
-#include "../utility.h"
-#include "../machine.h"
-
-/* enable to dump memory pointed to by every register */
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#ifdef WITH_VFP
-#ifdef WITH_VFP_D32
-#define NUM_VFP_REGS 32
-#else
-#define NUM_VFP_REGS 16
-#endif
-#endif
-
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
- char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */
- char ascii_buffer[32]; /* actual 16 + 1 == 17 */
- uintptr_t p, end;
-
- p = addr & ~3;
- p -= 32;
- if (p > addr) {
- /* catch underflow */
- p = 0;
- }
- /* Dump more memory content for the crashing thread. */
- end = p + 256;
- /* catch overflow; 'end - p' has to be multiples of 16 */
- while (end < p)
- end -= 16;
-
- /* Dump the code around PC as:
- * addr contents ascii
- * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
- * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
- */
- while (p < end) {
- char* asc_out = ascii_buffer;
-
- sprintf(code_buffer, "%08x ", p);
-
- int i;
- for (i = 0; i < 4; i++) {
- /*
- * If we see (data == -1 && errno != 0), we know that the ptrace
- * call failed, probably because we're dumping memory in an
- * unmapped or inaccessible page. I don't know if there's
- * value in making that explicit in the output -- it likely
- * just complicates parsing and clarifies nothing for the
- * enlightened reader.
- */
- long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
- sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
- /* Enable the following code blob to dump ASCII values */
-#if 0
- int j;
- for (j = 0; j < 4; j++) {
- /*
- * Our isprint() allows high-ASCII characters that display
- * differently (often badly) in different viewers, so we
- * just use a simpler test.
- */
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
-#endif
- p += 4;
- }
- *asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
- }
-}
-
-/*
- * If configured to do so, dump memory around *all* registers
- * for the crashing thread.
- */
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
- struct pt_regs regs;
- if(ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
- return;
- }
-
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
-
- for (int reg = 0; reg < 14; reg++) {
- /* this may not be a valid way to access, but it'll do for now */
- uintptr_t addr = regs.uregs[reg];
-
- /*
- * Don't bother if it looks like a small int or ~= null, or if
- * it's in the kernel area.
- */
- if (addr < 4096 || addr >= 0xc0000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
- }
- }
-
- /* explicitly allow upload of code dump logging */
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scope_flags);
-
- if (regs.ARM_pc != regs.ARM_lr) {
- _LOG(log, scope_flags, "\ncode around lr:\n");
- dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags);
- }
-}
-
-void dump_registers(log_t* log, pid_t tid, int scope_flags)
-{
- struct pt_regs r;
- if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
- (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3);
- _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
- (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7);
- _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n",
- (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp);
- _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
- (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
- (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr);
-
-#ifdef WITH_VFP
- struct user_vfp vfp_regs;
- int i;
-
- if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- for (i = 0; i < NUM_VFP_REGS; i += 2) {
- _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n",
- i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
- }
- _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
-#endif
-}
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
new file mode 100644
index 0000000..3fba6db
--- /dev/null
+++ b/debuggerd/arm/machine.cpp
@@ -0,0 +1,172 @@
+/*
+ *
+ * Copyright 2006, 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 <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+// enable to dump memory pointed to by every register
+#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
+
+#ifdef WITH_VFP
+#ifdef WITH_VFP_D32
+#define NUM_VFP_REGS 32
+#else
+#define NUM_VFP_REGS 16
+#endif
+#endif
+
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+ char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45
+ char ascii_buffer[32]; // actual 16 + 1 == 17
+ uintptr_t p, end;
+
+ p = addr & ~3;
+ p -= 32;
+ if (p > addr) {
+ // catch underflow
+ p = 0;
+ }
+ // Dump more memory content for the crashing thread.
+ end = p + 256;
+ // catch overflow; 'end - p' has to be multiples of 16
+ while (end < p)
+ end -= 16;
+
+ // Dump the code around PC as:
+ // addr contents ascii
+ // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
+ // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
+ while (p < end) {
+ char* asc_out = ascii_buffer;
+
+ sprintf(code_buffer, "%08x ", p);
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ // If we see (data == -1 && errno != 0), we know that the ptrace
+ // call failed, probably because we're dumping memory in an
+ // unmapped or inaccessible page. I don't know if there's
+ // value in making that explicit in the output -- it likely
+ // just complicates parsing and clarifies nothing for the
+ // enlightened reader.
+ long data = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(p), NULL);
+ sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
+
+ // Enable the following code blob to dump ASCII values
+#if 0
+ int j;
+ for (j = 0; j < 4; j++) {
+ // Our isprint() allows high-ASCII characters that display
+ // differently (often badly) in different viewers, so we
+ // just use a simpler test.
+ char val = (data >> (j*8)) & 0xff;
+ if (val >= 0x20 && val < 0x7f) {
+ *asc_out++ = val;
+ } else {
+ *asc_out++ = '.';
+ }
+ }
+#endif
+ p += 4;
+ }
+ *asc_out = '\0';
+ _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
+ }
+}
+
+// If configured to do so, dump memory around *all* registers
+// for the crashing thread.
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+ struct pt_regs regs;
+ if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
+ return;
+ }
+
+ if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+ static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+
+ for (int reg = 0; reg < 14; reg++) {
+ // this may not be a valid way to access, but it'll do for now
+ uintptr_t addr = regs.uregs[reg];
+
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0xc0000000) {
+ continue;
+ }
+
+ _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ }
+ }
+
+ // explicitly allow upload of code dump logging
+ _LOG(log, scope_flags, "\ncode around pc:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags);
+
+ if (regs.ARM_pc != regs.ARM_lr) {
+ _LOG(log, scope_flags, "\ncode around lr:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags);
+ }
+}
+
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+ struct pt_regs r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
+ static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
+ _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
+ static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
+ _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n",
+ static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
+ static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
+ _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
+ static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
+ static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
+ static_cast<uint32_t>(r.ARM_cpsr));
+
+#ifdef WITH_VFP
+ struct user_vfp vfp_regs;
+ int i;
+
+ if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ for (i = 0; i < NUM_VFP_REGS; i += 2) {
+ _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n",
+ i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
+ }
+ _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
+#endif
+}
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
deleted file mode 100644
index aa7a3c2..0000000
--- a/debuggerd/backtrace.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2012 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 <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <time.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/ptrace.h>
-
-#include <backtrace/backtrace.h>
-
-#include "backtrace.h"
-#include "utility.h"
-
-static void dump_process_header(log_t* log, pid_t pid) {
- char path[PATH_MAX];
- char procnamebuf[1024];
- char* procname = NULL;
- FILE* fp;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- time_t t = time(NULL);
- struct tm tm;
- localtime_r(&t, &tm);
- char timestr[64];
- strftime(timestr, sizeof(timestr), "%F %T", &tm);
- _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
-
- if (procname) {
- _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
- }
-}
-
-static void dump_process_footer(log_t* log, pid_t pid) {
- _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
-}
-
-static void dump_thread(log_t* log, pid_t tid, bool attached,
- bool* detach_failed, int* total_sleep_time_usec) {
- char path[PATH_MAX];
- char threadnamebuf[1024];
- char* threadname = NULL;
- FILE* fp;
-
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
- }
-
- _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n",
- threadname ? threadname : "<unknown>", tid);
-
- if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
- return;
- }
-
- wait_for_stop(tid, total_sleep_time_usec);
-
- backtrace_context_t context;
- if (!backtrace_create_context(&context, tid, -1, 0)) {
- _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n");
- } else {
- dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, " ");
- backtrace_destroy_context(&context);
- }
-
- if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
- *detach_failed = true;
- }
-}
-
-void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
- int* total_sleep_time_usec) {
- log_t log;
- log.tfd = fd;
- log.amfd = amfd;
- log.quiet = true;
-
- dump_process_header(&log, pid);
- dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
-
- char task_path[64];
- snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
- DIR* d = opendir(task_path);
- if (d != NULL) {
- struct dirent* de = NULL;
- while ((de = readdir(d)) != NULL) {
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
- continue;
- }
-
- char* end;
- pid_t new_tid = strtoul(de->d_name, &end, 10);
- if (*end || new_tid == tid) {
- continue;
- }
-
- dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec);
- }
- closedir(d);
- }
-
- dump_process_footer(&log, pid);
-}
-
-void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
- int scope_flags, const char* prefix) {
- char buf[512];
- for (size_t i = 0; i < context->backtrace->num_frames; i++) {
- backtrace_format_frame_data(context, i, buf, sizeof(buf));
- _LOG(log, scope_flags, "%s%s\n", prefix, buf);
- }
-}
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
new file mode 100644
index 0000000..d388348
--- /dev/null
+++ b/debuggerd/backtrace.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include <backtrace/Backtrace.h>
+#include <UniquePtr.h>
+
+#include "backtrace.h"
+#include "utility.h"
+
+static void dump_process_header(log_t* log, pid_t pid) {
+ char path[PATH_MAX];
+ char procnamebuf[1024];
+ char* procname = NULL;
+ FILE* fp;
+
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+ if ((fp = fopen(path, "r"))) {
+ procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+ fclose(fp);
+ }
+
+ time_t t = time(NULL);
+ struct tm tm;
+ localtime_r(&t, &tm);
+ char timestr[64];
+ strftime(timestr, sizeof(timestr), "%F %T", &tm);
+ _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
+
+ if (procname) {
+ _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
+ }
+}
+
+static void dump_process_footer(log_t* log, pid_t pid) {
+ _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
+}
+
+static void dump_thread(
+ log_t* log, pid_t tid, bool attached, bool* detach_failed, int* total_sleep_time_usec) {
+ char path[PATH_MAX];
+ char threadnamebuf[1024];
+ char* threadname = NULL;
+ FILE* fp;
+
+ snprintf(path, sizeof(path), "/proc/%d/comm", tid);
+ if ((fp = fopen(path, "r"))) {
+ threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
+ fclose(fp);
+ if (threadname) {
+ size_t len = strlen(threadname);
+ if (len && threadname[len - 1] == '\n') {
+ threadname[len - 1] = '\0';
+ }
+ }
+ }
+
+ _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+
+ if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
+ _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
+ return;
+ }
+
+ wait_for_stop(tid, total_sleep_time_usec);
+
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+ if (backtrace->Unwind(0)) {
+ dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " ");
+ }
+
+ if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+ LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
+ *detach_failed = true;
+ }
+}
+
+void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
+ int* total_sleep_time_usec) {
+ log_t log;
+ log.tfd = fd;
+ log.amfd = amfd;
+ log.quiet = true;
+
+ dump_process_header(&log, pid);
+ dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
+
+ char task_path[64];
+ snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+ DIR* d = opendir(task_path);
+ if (d != NULL) {
+ struct dirent* de = NULL;
+ while ((de = readdir(d)) != NULL) {
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ char* end;
+ pid_t new_tid = strtoul(de->d_name, &end, 10);
+ if (*end || new_tid == tid) {
+ continue;
+ }
+
+ dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec);
+ }
+ closedir(d);
+ }
+
+ dump_process_footer(&log, pid);
+}
+
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
+ int scope_flags, const char* prefix) {
+ for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+ _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
+ }
+}
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 54a60b2..2ec8afb 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -17,21 +17,19 @@
#ifndef _DEBUGGERD_BACKTRACE_H
#define _DEBUGGERD_BACKTRACE_H
-#include <stddef.h>
-#include <stdbool.h>
#include <sys/types.h>
-#include <backtrace/backtrace.h>
-
#include "utility.h"
-/* Dumps a backtrace using a format similar to what Dalvik uses so that the result
- * can be intermixed in a bug report. */
+class Backtrace;
+
+// Dumps a backtrace using a format similar to what Dalvik uses so that the result
+// can be intermixed in a bug report.
void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
- int* total_sleep_time_usec);
+ int* total_sleep_time_usec);
/* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
- int scope_flags, const char* prefix);
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
+ int scope_flags, const char* prefix);
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
deleted file mode 100644
index 756f7bb..0000000
--- a/debuggerd/debuggerd.c
+++ /dev/null
@@ -1,539 +0,0 @@
-/* system/debuggerd/debuggerd.c
-**
-** Copyright 2006, 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 <stdio.h>
-#include <errno.h>
-#include <signal.h>
-#include <pthread.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <time.h>
-
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <sys/exec_elf.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-
-#include <log/logd.h>
-#include <log/logger.h>
-
-#include <cutils/sockets.h>
-#include <cutils/properties.h>
-#include <cutils/debugger.h>
-
-#include <corkscrew/backtrace.h>
-
-#include <linux/input.h>
-
-#include <private/android_filesystem_config.h>
-
-#include "backtrace.h"
-#include "getevent.h"
-#include "tombstone.h"
-#include "utility.h"
-
-typedef struct {
- debugger_action_t action;
- pid_t pid, tid;
- uid_t uid, gid;
- uintptr_t abort_msg_address;
-} debugger_request_t;
-
-static int
-write_string(const char* file, const char* string)
-{
- int len;
- int fd;
- ssize_t amt;
- fd = open(file, O_RDWR);
- len = strlen(string);
- if (fd < 0)
- return -errno;
- amt = write(fd, string, len);
- close(fd);
- return amt >= 0 ? 0 : -errno;
-}
-
-static
-void init_debug_led(void)
-{
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- write_string("/sys/class/leds/green/brightness", "0");
- write_string("/sys/class/leds/blue/brightness", "0");
- write_string("/sys/class/leds/red/device/blink", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
-
-static
-void enable_debug_led(void)
-{
- // trout leds
- write_string("/sys/class/leds/red/brightness", "255");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "1,0");
-}
-
-static
-void disable_debug_led(void)
-{
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
-
-static void wait_for_user_action(pid_t pid) {
- /* First log a helpful message */
- LOG( "********************************************************\n"
- "* Process %d has been suspended while crashing. To\n"
- "* attach gdbserver for a gdb connection on port 5039\n"
- "* and start gdbclient:\n"
- "*\n"
- "* gdbclient app_process :5039 %d\n"
- "*\n"
- "* Wait for gdb to start, then press HOME or VOLUME DOWN key\n"
- "* to let the process continue crashing.\n"
- "********************************************************\n",
- pid, pid);
-
- /* wait for HOME or VOLUME DOWN key */
- if (init_getevent() == 0) {
- int ms = 1200 / 10;
- int dit = 1;
- int dah = 3*dit;
- int _ = -dit;
- int ___ = 3*_;
- int _______ = 7*_;
- const signed char codes[] = {
- dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
- };
- size_t s = 0;
- struct input_event e;
- bool done = false;
- init_debug_led();
- enable_debug_led();
- do {
- int timeout = abs((int)(codes[s])) * ms;
- int res = get_event(&e, timeout);
- if (res == 0) {
- if (e.type == EV_KEY
- && (e.code == KEY_HOME || e.code == KEY_VOLUMEDOWN)
- && e.value == 0) {
- done = true;
- }
- } else if (res == 1) {
- if (++s >= sizeof(codes)/sizeof(*codes))
- s = 0;
- if (codes[s] > 0) {
- enable_debug_led();
- } else {
- disable_debug_led();
- }
- }
- } while (!done);
- uninit_getevent();
- }
-
- /* don't forget to turn debug led off */
- disable_debug_led();
- LOG("debuggerd resuming process %d", pid);
-}
-
-static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
- char path[64];
- snprintf(path, sizeof(path), "/proc/%d/status", tid);
-
- FILE* fp = fopen(path, "r");
- if (!fp) {
- return -1;
- }
-
- int fields = 0;
- char line[1024];
- while (fgets(line, sizeof(line), fp)) {
- size_t len = strlen(line);
- if (len > 6 && !memcmp(line, "Tgid:\t", 6)) {
- *out_pid = atoi(line + 6);
- fields |= 1;
- } else if (len > 5 && !memcmp(line, "Uid:\t", 5)) {
- *out_uid = atoi(line + 5);
- fields |= 2;
- } else if (len > 5 && !memcmp(line, "Gid:\t", 5)) {
- *out_gid = atoi(line + 5);
- fields |= 4;
- }
- }
- fclose(fp);
- return fields == 7 ? 0 : -1;
-}
-
-static int read_request(int fd, debugger_request_t* out_request) {
- struct ucred cr;
- int len = sizeof(cr);
- int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
- if (status != 0) {
- LOG("cannot get credentials\n");
- return -1;
- }
-
- XLOG("reading tid\n");
- fcntl(fd, F_SETFL, O_NONBLOCK);
-
- struct pollfd pollfds[1];
- pollfds[0].fd = fd;
- pollfds[0].events = POLLIN;
- pollfds[0].revents = 0;
- status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
- if (status != 1) {
- LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
- return -1;
- }
-
- debugger_msg_t msg;
- memset(&msg, 0, sizeof(msg));
- status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
- if (status < 0) {
- LOG("read failure? %s (pid=%d uid=%d)\n",
- strerror(errno), cr.pid, cr.uid);
- return -1;
- }
- if (status == sizeof(debugger_msg_t)) {
- XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address);
- } else {
- LOG("invalid crash request of size %d (from pid=%d uid=%d)\n",
- status, cr.pid, cr.uid);
- return -1;
- }
-
- out_request->action = msg.action;
- out_request->tid = msg.tid;
- out_request->pid = cr.pid;
- out_request->uid = cr.uid;
- out_request->gid = cr.gid;
- out_request->abort_msg_address = msg.abort_msg_address;
-
- if (msg.action == DEBUGGER_ACTION_CRASH) {
- /* Ensure that the tid reported by the crashing process is valid. */
- char buf[64];
- struct stat s;
- snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
- if(stat(buf, &s)) {
- LOG("tid %d does not exist in pid %d. ignoring debug request\n",
- out_request->tid, out_request->pid);
- return -1;
- }
- } else if (cr.uid == 0
- || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
- /* Only root or system can ask us to attach to any process and dump it explicitly.
- * However, system is only allowed to collect backtraces but cannot dump tombstones. */
- status = get_process_info(out_request->tid, &out_request->pid,
- &out_request->uid, &out_request->gid);
- if (status < 0) {
- LOG("tid %d does not exist. ignoring explicit dump request\n",
- out_request->tid);
- return -1;
- }
- } else {
- /* No one else is allowed to dump arbitrary processes. */
- return -1;
- }
- return 0;
-}
-
-static bool should_attach_gdb(debugger_request_t* request) {
- if (request->action == DEBUGGER_ACTION_CRASH) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.db.uid", value, "-1");
- int debug_uid = atoi(value);
- return debug_uid >= 0 && request->uid <= (uid_t)debug_uid;
- }
- return false;
-}
-
-static void handle_request(int fd) {
- XLOG("handle_request(%d)\n", fd);
-
- debugger_request_t request;
- memset(&request, 0, sizeof(request));
- int status = read_request(fd, &request);
- if (!status) {
- XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
- request.pid, request.uid, request.gid, request.tid);
-
- /* At this point, the thread that made the request is blocked in
- * a read() call. If the thread has crashed, then this gives us
- * time to PTRACE_ATTACH to it before it has a chance to really fault.
- *
- * The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
- * won't necessarily have stopped by the time ptrace() returns. (We
- * currently assume it does.) We write to the file descriptor to
- * ensure that it can run as soon as we call PTRACE_CONT below.
- * See details in bionic/libc/linker/debugger.c, in function
- * debugger_signal_handler().
- */
- if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
- LOG("ptrace attach failed: %s\n", strerror(errno));
- } else {
- bool detach_failed = false;
- bool attach_gdb = should_attach_gdb(&request);
- if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
- LOG("failed responding to client: %s\n", strerror(errno));
- } else {
- char* tombstone_path = NULL;
-
- if (request.action == DEBUGGER_ACTION_CRASH) {
- close(fd);
- fd = -1;
- }
-
- int total_sleep_time_usec = 0;
- for (;;) {
- int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
- if (signal < 0) {
- break;
- }
-
- switch (signal) {
- case SIGSTOP:
- if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
- XLOG("stopped -- dumping to tombstone\n");
- tombstone_path = engrave_tombstone(request.pid, request.tid,
- signal, request.abort_msg_address, true, true, &detach_failed,
- &total_sleep_time_usec);
- } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
- XLOG("stopped -- dumping to fd\n");
- dump_backtrace(fd, -1,
- request.pid, request.tid, &detach_failed,
- &total_sleep_time_usec);
- } else {
- XLOG("stopped -- continuing\n");
- status = ptrace(PTRACE_CONT, request.tid, 0, 0);
- if (status) {
- LOG("ptrace continue failed: %s\n", strerror(errno));
- }
- continue; /* loop again */
- }
- break;
-
- case SIGILL:
- case SIGABRT:
- case SIGBUS:
- case SIGFPE:
- case SIGSEGV:
- case SIGPIPE:
-#ifdef SIGSTKFLT
- case SIGSTKFLT:
-#endif
- {
- XLOG("stopped -- fatal signal\n");
- /*
- * Send a SIGSTOP to the process to make all of
- * the non-signaled threads stop moving. Without
- * this we get a lot of "ptrace detach failed:
- * No such process".
- */
- kill(request.pid, SIGSTOP);
- /* don't dump sibling threads when attaching to GDB because it
- * makes the process less reliable, apparently... */
- tombstone_path = engrave_tombstone(request.pid, request.tid,
- signal, request.abort_msg_address, !attach_gdb, false,
- &detach_failed, &total_sleep_time_usec);
- break;
- }
-
- default:
- XLOG("stopped -- unexpected signal\n");
- LOG("process stopped due to unexpected signal %d\n", signal);
- break;
- }
- break;
- }
-
- if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
- if (tombstone_path) {
- write(fd, tombstone_path, strlen(tombstone_path));
- }
- close(fd);
- fd = -1;
- }
- free(tombstone_path);
- }
-
- XLOG("detaching\n");
- if (attach_gdb) {
- /* stop the process so we can debug */
- kill(request.pid, SIGSTOP);
-
- /* detach so we can attach gdbserver */
- if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
- detach_failed = true;
- }
-
- /*
- * if debug.db.uid is set, its value indicates if we should wait
- * for user action for the crashing process.
- * in this case, we log a message and turn the debug LED on
- * waiting for a gdb connection (for instance)
- */
- wait_for_user_action(request.pid);
- } else {
- /* just detach */
- if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
- detach_failed = true;
- }
- }
-
- /* resume stopped process (so it can crash in peace). */
- kill(request.pid, SIGCONT);
-
- /* If we didn't successfully detach, we're still the parent, and the
- * actual parent won't receive a death notification via wait(2). At this point
- * there's not much we can do about that. */
- if (detach_failed) {
- LOG("debuggerd committing suicide to free the zombie!\n");
- kill(getpid(), SIGKILL);
- }
- }
-
- }
- if (fd >= 0) {
- close(fd);
- }
-}
-
-static int do_server() {
- int s;
- struct sigaction act;
- int logsocket = -1;
-
- /*
- * debuggerd crashes can't be reported to debuggerd. Reset all of the
- * crash handlers.
- */
- signal(SIGILL, SIG_DFL);
- signal(SIGABRT, SIG_DFL);
- signal(SIGBUS, SIG_DFL);
- signal(SIGFPE, SIG_DFL);
- signal(SIGSEGV, SIG_DFL);
-#ifdef SIGSTKFLT
- signal(SIGSTKFLT, SIG_DFL);
-#endif
-
- // Ignore failed writes to closed sockets
- signal(SIGPIPE, SIG_IGN);
-
- logsocket = socket_local_client("logd",
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
- if(logsocket < 0) {
- logsocket = -1;
- } else {
- fcntl(logsocket, F_SETFD, FD_CLOEXEC);
- }
-
- act.sa_handler = SIG_DFL;
- sigemptyset(&act.sa_mask);
- sigaddset(&act.sa_mask,SIGCHLD);
- act.sa_flags = SA_NOCLDWAIT;
- sigaction(SIGCHLD, &act, 0);
-
- s = socket_local_server(DEBUGGER_SOCKET_NAME,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- if(s < 0) return 1;
- fcntl(s, F_SETFD, FD_CLOEXEC);
-
- LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
-
- for(;;) {
- struct sockaddr addr;
- socklen_t alen;
- int fd;
-
- alen = sizeof(addr);
- XLOG("waiting for connection\n");
- fd = accept(s, &addr, &alen);
- if(fd < 0) {
- XLOG("accept failed: %s\n", strerror(errno));
- continue;
- }
-
- fcntl(fd, F_SETFD, FD_CLOEXEC);
-
- handle_request(fd);
- }
- return 0;
-}
-
-static int do_explicit_dump(pid_t tid, bool dump_backtrace) {
- fprintf(stdout, "Sending request to dump task %d.\n", tid);
-
- if (dump_backtrace) {
- fflush(stdout);
- if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) {
- fputs("Error dumping backtrace.\n", stderr);
- return 1;
- }
- } else {
- char tombstone_path[PATH_MAX];
- if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) {
- fputs("Error dumping tombstone.\n", stderr);
- return 1;
- }
- fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
- }
- return 0;
-}
-
-static void usage() {
- fputs("Usage: -b [<tid>]\n"
- " -b dump backtrace to console, otherwise dump full tombstone file\n"
- "\n"
- "If tid specified, sends a request to debuggerd to dump that task.\n"
- "Otherwise, starts the debuggerd server.\n", stderr);
-}
-
-int main(int argc, char** argv) {
- if (argc == 1) {
- return do_server();
- }
-
- bool dump_backtrace = false;
- bool have_tid = false;
- pid_t tid = 0;
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-b")) {
- dump_backtrace = true;
- } else if (!have_tid) {
- tid = atoi(argv[i]);
- have_tid = true;
- } else {
- usage();
- return 1;
- }
- }
- if (!have_tid) {
- usage();
- return 1;
- }
- return do_explicit_dump(tid, dump_backtrace);
-}
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
new file mode 100644
index 0000000..de8ba9d
--- /dev/null
+++ b/debuggerd/debuggerd.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2006, 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 <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <elf.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+
+#include <log/logd.h>
+#include <log/logger.h>
+
+#include <cutils/sockets.h>
+#include <cutils/properties.h>
+#include <cutils/debugger.h>
+
+#include <linux/input.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "backtrace.h"
+#include "getevent.h"
+#include "tombstone.h"
+#include "utility.h"
+
+typedef struct {
+ debugger_action_t action;
+ pid_t pid, tid;
+ uid_t uid, gid;
+ uintptr_t abort_msg_address;
+} debugger_request_t;
+
+static int write_string(const char* file, const char* string) {
+ int len;
+ int fd;
+ ssize_t amt;
+ fd = open(file, O_RDWR);
+ len = strlen(string);
+ if (fd < 0)
+ return -errno;
+ amt = write(fd, string, len);
+ close(fd);
+ return amt >= 0 ? 0 : -errno;
+}
+
+static void init_debug_led() {
+ // trout leds
+ write_string("/sys/class/leds/red/brightness", "0");
+ write_string("/sys/class/leds/green/brightness", "0");
+ write_string("/sys/class/leds/blue/brightness", "0");
+ write_string("/sys/class/leds/red/device/blink", "0");
+ // sardine leds
+ write_string("/sys/class/leds/left/cadence", "0,0");
+}
+
+static void enable_debug_led() {
+ // trout leds
+ write_string("/sys/class/leds/red/brightness", "255");
+ // sardine leds
+ write_string("/sys/class/leds/left/cadence", "1,0");
+}
+
+static void disable_debug_led() {
+ // trout leds
+ write_string("/sys/class/leds/red/brightness", "0");
+ // sardine leds
+ write_string("/sys/class/leds/left/cadence", "0,0");
+}
+
+static void wait_for_user_action(pid_t pid) {
+ // First log a helpful message
+ LOG( "********************************************************\n"
+ "* Process %d has been suspended while crashing. To\n"
+ "* attach gdbserver for a gdb connection on port 5039\n"
+ "* and start gdbclient:\n"
+ "*\n"
+ "* gdbclient app_process :5039 %d\n"
+ "*\n"
+ "* Wait for gdb to start, then press HOME or VOLUME DOWN key\n"
+ "* to let the process continue crashing.\n"
+ "********************************************************\n",
+ pid, pid);
+
+ // wait for HOME or VOLUME DOWN key
+ if (init_getevent() == 0) {
+ int ms = 1200 / 10;
+ int dit = 1;
+ int dah = 3*dit;
+ int _ = -dit;
+ int ___ = 3*_;
+ int _______ = 7*_;
+ const int codes[] = {
+ dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
+ };
+ size_t s = 0;
+ struct input_event e;
+ bool done = false;
+ init_debug_led();
+ enable_debug_led();
+ do {
+ int timeout = abs(codes[s]) * ms;
+ int res = get_event(&e, timeout);
+ if (res == 0) {
+ if (e.type == EV_KEY
+ && (e.code == KEY_HOME || e.code == KEY_VOLUMEDOWN)
+ && e.value == 0) {
+ done = true;
+ }
+ } else if (res == 1) {
+ if (++s >= sizeof(codes)/sizeof(*codes))
+ s = 0;
+ if (codes[s] > 0) {
+ enable_debug_led();
+ } else {
+ disable_debug_led();
+ }
+ }
+ } while (!done);
+ uninit_getevent();
+ }
+
+ // don't forget to turn debug led off
+ disable_debug_led();
+ LOG("debuggerd resuming process %d", pid);
+}
+
+static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/%d/status", tid);
+
+ FILE* fp = fopen(path, "r");
+ if (!fp) {
+ return -1;
+ }
+
+ int fields = 0;
+ char line[1024];
+ while (fgets(line, sizeof(line), fp)) {
+ size_t len = strlen(line);
+ if (len > 6 && !memcmp(line, "Tgid:\t", 6)) {
+ *out_pid = atoi(line + 6);
+ fields |= 1;
+ } else if (len > 5 && !memcmp(line, "Uid:\t", 5)) {
+ *out_uid = atoi(line + 5);
+ fields |= 2;
+ } else if (len > 5 && !memcmp(line, "Gid:\t", 5)) {
+ *out_gid = atoi(line + 5);
+ fields |= 4;
+ }
+ }
+ fclose(fp);
+ return fields == 7 ? 0 : -1;
+}
+
+static int read_request(int fd, debugger_request_t* out_request) {
+ struct ucred cr;
+ int len = sizeof(cr);
+ int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
+ if (status != 0) {
+ LOG("cannot get credentials\n");
+ return -1;
+ }
+
+ XLOG("reading tid\n");
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ struct pollfd pollfds[1];
+ pollfds[0].fd = fd;
+ pollfds[0].events = POLLIN;
+ pollfds[0].revents = 0;
+ status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
+ if (status != 1) {
+ LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
+ return -1;
+ }
+
+ debugger_msg_t msg;
+ memset(&msg, 0, sizeof(msg));
+ status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
+ if (status < 0) {
+ LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
+ return -1;
+ }
+ if (status == sizeof(debugger_msg_t)) {
+ XLOG("crash request of size %d abort_msg_address=%#08x\n", status, msg.abort_msg_address);
+ } else {
+ LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
+ return -1;
+ }
+
+ out_request->action = msg.action;
+ out_request->tid = msg.tid;
+ out_request->pid = cr.pid;
+ out_request->uid = cr.uid;
+ out_request->gid = cr.gid;
+ out_request->abort_msg_address = msg.abort_msg_address;
+
+ if (msg.action == DEBUGGER_ACTION_CRASH) {
+ // Ensure that the tid reported by the crashing process is valid.
+ char buf[64];
+ struct stat s;
+ snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
+ if (stat(buf, &s)) {
+ LOG("tid %d does not exist in pid %d. ignoring debug request\n",
+ out_request->tid, out_request->pid);
+ return -1;
+ }
+ } else if (cr.uid == 0
+ || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
+ // Only root or system can ask us to attach to any process and dump it explicitly.
+ // However, system is only allowed to collect backtraces but cannot dump tombstones.
+ status = get_process_info(out_request->tid, &out_request->pid,
+ &out_request->uid, &out_request->gid);
+ if (status < 0) {
+ LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
+ return -1;
+ }
+ } else {
+ // No one else is allowed to dump arbitrary processes.
+ return -1;
+ }
+ return 0;
+}
+
+static bool should_attach_gdb(debugger_request_t* request) {
+ if (request->action == DEBUGGER_ACTION_CRASH) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.db.uid", value, "-1");
+ int debug_uid = atoi(value);
+ return debug_uid >= 0 && request->uid <= (uid_t)debug_uid;
+ }
+ return false;
+}
+
+static void handle_request(int fd) {
+ XLOG("handle_request(%d)\n", fd);
+
+ debugger_request_t request;
+ memset(&request, 0, sizeof(request));
+ int status = read_request(fd, &request);
+ if (!status) {
+ XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
+ request.pid, request.uid, request.gid, request.tid);
+
+ // At this point, the thread that made the request is blocked in
+ // a read() call. If the thread has crashed, then this gives us
+ // time to PTRACE_ATTACH to it before it has a chance to really fault.
+ //
+ // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
+ // won't necessarily have stopped by the time ptrace() returns. (We
+ // currently assume it does.) We write to the file descriptor to
+ // ensure that it can run as soon as we call PTRACE_CONT below.
+ // See details in bionic/libc/linker/debugger.c, in function
+ // debugger_signal_handler().
+ if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
+ LOG("ptrace attach failed: %s\n", strerror(errno));
+ } else {
+ bool detach_failed = false;
+ bool attach_gdb = should_attach_gdb(&request);
+ if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
+ LOG("failed responding to client: %s\n", strerror(errno));
+ } else {
+ char* tombstone_path = NULL;
+
+ if (request.action == DEBUGGER_ACTION_CRASH) {
+ close(fd);
+ fd = -1;
+ }
+
+ int total_sleep_time_usec = 0;
+ for (;;) {
+ int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
+ if (signal < 0) {
+ break;
+ }
+
+ switch (signal) {
+ case SIGSTOP:
+ if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+ XLOG("stopped -- dumping to tombstone\n");
+ tombstone_path = engrave_tombstone(
+ request.pid, request.tid, signal, request.abort_msg_address, true, true,
+ &detach_failed, &total_sleep_time_usec);
+ } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
+ XLOG("stopped -- dumping to fd\n");
+ dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
+ &total_sleep_time_usec);
+ } else {
+ XLOG("stopped -- continuing\n");
+ status = ptrace(PTRACE_CONT, request.tid, 0, 0);
+ if (status) {
+ LOG("ptrace continue failed: %s\n", strerror(errno));
+ }
+ continue; // loop again
+ }
+ break;
+
+ case SIGILL:
+ case SIGABRT:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGPIPE:
+#ifdef SIGSTKFLT
+ case SIGSTKFLT:
+#endif
+ XLOG("stopped -- fatal signal\n");
+ // Send a SIGSTOP to the process to make all of
+ // the non-signaled threads stop moving. Without
+ // this we get a lot of "ptrace detach failed:
+ // No such process".
+ kill(request.pid, SIGSTOP);
+ // don't dump sibling threads when attaching to GDB because it
+ // makes the process less reliable, apparently...
+ tombstone_path = engrave_tombstone(
+ request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb,
+ false, &detach_failed, &total_sleep_time_usec);
+ break;
+
+ default:
+ XLOG("stopped -- unexpected signal\n");
+ LOG("process stopped due to unexpected signal %d\n", signal);
+ break;
+ }
+ break;
+ }
+
+ if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
+ if (tombstone_path) {
+ write(fd, tombstone_path, strlen(tombstone_path));
+ }
+ close(fd);
+ fd = -1;
+ }
+ free(tombstone_path);
+ }
+
+ XLOG("detaching\n");
+ if (attach_gdb) {
+ // stop the process so we can debug
+ kill(request.pid, SIGSTOP);
+
+ // detach so we can attach gdbserver
+ if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
+ LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ detach_failed = true;
+ }
+
+ // if debug.db.uid is set, its value indicates if we should wait
+ // for user action for the crashing process.
+ // in this case, we log a message and turn the debug LED on
+ // waiting for a gdb connection (for instance)
+ wait_for_user_action(request.pid);
+ } else {
+ // just detach
+ if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
+ LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ detach_failed = true;
+ }
+ }
+
+ // resume stopped process (so it can crash in peace).
+ kill(request.pid, SIGCONT);
+
+ // If we didn't successfully detach, we're still the parent, and the
+ // actual parent won't receive a death notification via wait(2). At this point
+ // there's not much we can do about that.
+ if (detach_failed) {
+ LOG("debuggerd committing suicide to free the zombie!\n");
+ kill(getpid(), SIGKILL);
+ }
+ }
+
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
+static int do_server() {
+ int s;
+ struct sigaction act;
+ int logsocket = -1;
+
+ // debuggerd crashes can't be reported to debuggerd. Reset all of the
+ // crash handlers.
+ signal(SIGILL, SIG_DFL);
+ signal(SIGABRT, SIG_DFL);
+ signal(SIGBUS, SIG_DFL);
+ signal(SIGFPE, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+#ifdef SIGSTKFLT
+ signal(SIGSTKFLT, SIG_DFL);
+#endif
+
+ // Ignore failed writes to closed sockets
+ signal(SIGPIPE, SIG_IGN);
+
+ logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
+ if (logsocket < 0) {
+ logsocket = -1;
+ } else {
+ fcntl(logsocket, F_SETFD, FD_CLOEXEC);
+ }
+
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ sigaddset(&act.sa_mask,SIGCHLD);
+ act.sa_flags = SA_NOCLDWAIT;
+ sigaction(SIGCHLD, &act, 0);
+
+ s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ if (s < 0)
+ return 1;
+ fcntl(s, F_SETFD, FD_CLOEXEC);
+
+ LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
+
+ for (;;) {
+ struct sockaddr addr;
+ socklen_t alen;
+ int fd;
+
+ alen = sizeof(addr);
+ XLOG("waiting for connection\n");
+ fd = accept(s, &addr, &alen);
+ if (fd < 0) {
+ XLOG("accept failed: %s\n", strerror(errno));
+ continue;
+ }
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+ handle_request(fd);
+ }
+ return 0;
+}
+
+static int do_explicit_dump(pid_t tid, bool dump_backtrace) {
+ fprintf(stdout, "Sending request to dump task %d.\n", tid);
+
+ if (dump_backtrace) {
+ fflush(stdout);
+ if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) {
+ fputs("Error dumping backtrace.\n", stderr);
+ return 1;
+ }
+ } else {
+ char tombstone_path[PATH_MAX];
+ if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) {
+ fputs("Error dumping tombstone.\n", stderr);
+ return 1;
+ }
+ fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
+ }
+ return 0;
+}
+
+static void usage() {
+ fputs("Usage: -b [<tid>]\n"
+ " -b dump backtrace to console, otherwise dump full tombstone file\n"
+ "\n"
+ "If tid specified, sends a request to debuggerd to dump that task.\n"
+ "Otherwise, starts the debuggerd server.\n", stderr);
+}
+
+int main(int argc, char** argv) {
+ if (argc == 1) {
+ return do_server();
+ }
+
+ bool dump_backtrace = false;
+ bool have_tid = false;
+ pid_t tid = 0;
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-b")) {
+ dump_backtrace = true;
+ } else if (!have_tid) {
+ tid = atoi(argv[i]);
+ have_tid = true;
+ } else {
+ usage();
+ return 1;
+ }
+ }
+ if (!have_tid) {
+ usage();
+ return 1;
+ }
+ return do_explicit_dump(tid, dump_backtrace);
+}
diff --git a/debuggerd/getevent.c b/debuggerd/getevent.c
deleted file mode 100644
index ebd070c..0000000
--- a/debuggerd/getevent.c
+++ /dev/null
@@ -1,219 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
-#include <sys/limits.h>
-#include <sys/poll.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <cutils/log.h>
-
-static struct pollfd *ufds;
-static char **device_names;
-static int nfds;
-
-static int open_device(const char *device)
-{
- int version;
- int fd;
- struct pollfd *new_ufds;
- char **new_device_names;
- char name[80];
- char location[80];
- char idstr[80];
- struct input_id id;
-
- fd = open(device, O_RDWR);
- if(fd < 0) {
- return -1;
- }
-
- if(ioctl(fd, EVIOCGVERSION, &version)) {
- return -1;
- }
- if(ioctl(fd, EVIOCGID, &id)) {
- return -1;
- }
- name[sizeof(name) - 1] = '\0';
- location[sizeof(location) - 1] = '\0';
- idstr[sizeof(idstr) - 1] = '\0';
- if(ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
- //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno));
- name[0] = '\0';
- }
- if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
- //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno));
- location[0] = '\0';
- }
- if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
- //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno));
- idstr[0] = '\0';
- }
-
- new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
- if(new_ufds == NULL) {
- fprintf(stderr, "out of memory\n");
- return -1;
- }
- ufds = new_ufds;
- new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1));
- if(new_device_names == NULL) {
- fprintf(stderr, "out of memory\n");
- return -1;
- }
- device_names = new_device_names;
- ufds[nfds].fd = fd;
- ufds[nfds].events = POLLIN;
- device_names[nfds] = strdup(device);
- nfds++;
-
- return 0;
-}
-
-int close_device(const char *device)
-{
- int i;
- for(i = 1; i < nfds; i++) {
- if(strcmp(device_names[i], device) == 0) {
- int count = nfds - i - 1;
- free(device_names[i]);
- memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
- memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
- nfds--;
- return 0;
- }
- }
- return -1;
-}
-
-static int read_notify(const char *dirname, int nfd)
-{
- int res;
- char devname[PATH_MAX];
- char *filename;
- char event_buf[512];
- int event_size;
- int event_pos = 0;
- struct inotify_event *event;
-
- res = read(nfd, event_buf, sizeof(event_buf));
- if(res < (int)sizeof(*event)) {
- if(errno == EINTR)
- return 0;
- fprintf(stderr, "could not get event, %s\n", strerror(errno));
- return 1;
- }
- //printf("got %d bytes of event information\n", res);
-
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = '/';
-
- while(res >= (int)sizeof(*event)) {
- event = (struct inotify_event *)(event_buf + event_pos);
- //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
- if(event->len) {
- strcpy(filename, event->name);
- if(event->mask & IN_CREATE) {
- open_device(devname);
- }
- else {
- close_device(devname);
- }
- }
- event_size = sizeof(*event) + event->len;
- res -= event_size;
- event_pos += event_size;
- }
- return 0;
-}
-
-static int scan_dir(const char *dirname)
-{
- char devname[PATH_MAX];
- char *filename;
- DIR *dir;
- struct dirent *de;
- dir = opendir(dirname);
- if(dir == NULL)
- return -1;
- strcpy(devname, dirname);
- filename = devname + strlen(devname);
- *filename++ = '/';
- while((de = readdir(dir))) {
- if(de->d_name[0] == '.' &&
- (de->d_name[1] == '\0' ||
- (de->d_name[1] == '.' && de->d_name[2] == '\0')))
- continue;
- strcpy(filename, de->d_name);
- open_device(devname);
- }
- closedir(dir);
- return 0;
-}
-
-int init_getevent()
-{
- int res;
- const char *device_path = "/dev/input";
-
- nfds = 1;
- ufds = calloc(1, sizeof(ufds[0]));
- ufds[0].fd = inotify_init();
- ufds[0].events = POLLIN;
-
- res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
- if(res < 0) {
- return 1;
- }
- res = scan_dir(device_path);
- if(res < 0) {
- return 1;
- }
- return 0;
-}
-
-void uninit_getevent()
-{
- int i;
- for(i = 0; i < nfds; i++) {
- close(ufds[i].fd);
- }
- free(ufds);
- ufds = 0;
- nfds = 0;
-}
-
-int get_event(struct input_event* event, int timeout)
-{
- int res;
- int i;
- int pollres;
- const char *device_path = "/dev/input";
- while(1) {
- pollres = poll(ufds, nfds, timeout);
- if (pollres == 0) {
- return 1;
- }
- if(ufds[0].revents & POLLIN) {
- read_notify(device_path, ufds[0].fd);
- }
- for(i = 1; i < nfds; i++) {
- if(ufds[i].revents) {
- if(ufds[i].revents & POLLIN) {
- res = read(ufds[i].fd, event, sizeof(*event));
- if(res < (int)sizeof(event)) {
- fprintf(stderr, "could not get event\n");
- return -1;
- }
- return 0;
- }
- }
- }
- }
- return 0;
-}
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
new file mode 100644
index 0000000..751c4fb
--- /dev/null
+++ b/debuggerd/getevent.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/inotify.h>
+#include <sys/limits.h>
+#include <sys/poll.h>
+#include <linux/input.h>
+#include <errno.h>
+#include <cutils/log.h>
+
+static struct pollfd* ufds;
+static char** device_names;
+static int nfds;
+
+static int open_device(const char* device) {
+ int version;
+ int fd;
+ struct pollfd* new_ufds;
+ char** new_device_names;
+ char name[80];
+ char location[80];
+ char idstr[80];
+ struct input_id id;
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ return -1;
+ }
+
+ if (ioctl(fd, EVIOCGVERSION, &version)) {
+ return -1;
+ }
+ if (ioctl(fd, EVIOCGID, &id)) {
+ return -1;
+ }
+ name[sizeof(name) - 1] = '\0';
+ location[sizeof(location) - 1] = '\0';
+ idstr[sizeof(idstr) - 1] = '\0';
+ if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
+ name[0] = '\0';
+ }
+ if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
+ location[0] = '\0';
+ }
+ if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
+ idstr[0] = '\0';
+ }
+
+ new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
+ if (new_ufds == NULL) {
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+ ufds = new_ufds;
+ new_device_names = reinterpret_cast<char**>(realloc(
+ device_names, sizeof(device_names[0]) * (nfds + 1)));
+ if (new_device_names == NULL) {
+ fprintf(stderr, "out of memory\n");
+ return -1;
+ }
+ device_names = new_device_names;
+ ufds[nfds].fd = fd;
+ ufds[nfds].events = POLLIN;
+ device_names[nfds] = strdup(device);
+ nfds++;
+
+ return 0;
+}
+
+int close_device(const char* device) {
+ int i;
+ for (i = 1; i < nfds; i++) {
+ if (strcmp(device_names[i], device) == 0) {
+ int count = nfds - i - 1;
+ free(device_names[i]);
+ memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
+ memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
+ nfds--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int read_notify(const char* dirname, int nfd) {
+ int res;
+ char devname[PATH_MAX];
+ char* filename;
+ char event_buf[512];
+ int event_size;
+ int event_pos = 0;
+ struct inotify_event *event;
+
+ res = read(nfd, event_buf, sizeof(event_buf));
+ if (res < (int)sizeof(*event)) {
+ if (errno == EINTR)
+ return 0;
+ fprintf(stderr, "could not get event, %s\n", strerror(errno));
+ return 1;
+ }
+
+ strcpy(devname, dirname);
+ filename = devname + strlen(devname);
+ *filename++ = '/';
+
+ while (res >= (int)sizeof(*event)) {
+ event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
+ if (event->len) {
+ strcpy(filename, event->name);
+ if (event->mask & IN_CREATE) {
+ open_device(devname);
+ } else {
+ close_device(devname);
+ }
+ }
+ event_size = sizeof(*event) + event->len;
+ res -= event_size;
+ event_pos += event_size;
+ }
+ return 0;
+}
+
+static int scan_dir(const char* dirname) {
+ char devname[PATH_MAX];
+ char* filename;
+ DIR* dir;
+ struct dirent* de;
+ dir = opendir(dirname);
+ if (dir == NULL)
+ return -1;
+ strcpy(devname, dirname);
+ filename = devname + strlen(devname);
+ *filename++ = '/';
+ while ((de = readdir(dir))) {
+ if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+ (de->d_name[1] == '.' && de->d_name[2] == '\0'))
+ continue;
+ strcpy(filename, de->d_name);
+ open_device(devname);
+ }
+ closedir(dir);
+ return 0;
+}
+
+int init_getevent() {
+ int res;
+ const char* device_path = "/dev/input";
+
+ nfds = 1;
+ ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
+ ufds[0].fd = inotify_init();
+ ufds[0].events = POLLIN;
+
+ res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
+ if (res < 0) {
+ return 1;
+ }
+ res = scan_dir(device_path);
+ if (res < 0) {
+ return 1;
+ }
+ return 0;
+}
+
+void uninit_getevent() {
+ int i;
+ for (i = 0; i < nfds; i++) {
+ close(ufds[i].fd);
+ }
+ free(ufds);
+ ufds = 0;
+ nfds = 0;
+}
+
+int get_event(struct input_event* event, int timeout) {
+ int res;
+ int i;
+ int pollres;
+ const char* device_path = "/dev/input";
+ while (1) {
+ pollres = poll(ufds, nfds, timeout);
+ if (pollres == 0) {
+ return 1;
+ }
+ if (ufds[0].revents & POLLIN) {
+ read_notify(device_path, ufds[0].fd);
+ }
+ for (i = 1; i < nfds; i++) {
+ if (ufds[i].revents) {
+ if (ufds[i].revents & POLLIN) {
+ res = read(ufds[i].fd, event, sizeof(*event));
+ if (res < static_cast<int>(sizeof(event))) {
+ fprintf(stderr, "could not get event\n");
+ return -1;
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c
deleted file mode 100644
index 489f3c5..0000000
--- a/debuggerd/mips/machine.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/* system/debuggerd/debuggerd.c
-**
-** Copyright 2012, 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 <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/ptrace.h>
-
-#include <corkscrew/ptrace.h>
-
-#include <sys/user.h>
-
-#include "../utility.h"
-#include "../machine.h"
-
-/* enable to dump memory pointed to by every register */
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#define R(x) ((unsigned int)(x))
-
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
- char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */
- char ascii_buffer[32]; /* actual 16 + 1 == 17 */
- uintptr_t p, end;
-
- p = addr & ~3;
- p -= 32;
- if (p > addr) {
- /* catch underflow */
- p = 0;
- }
- end = p + 80;
- /* catch overflow; 'end - p' has to be multiples of 16 */
- while (end < p)
- end -= 16;
-
- /* Dump the code around PC as:
- * addr contents ascii
- * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
- * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
- */
- while (p < end) {
- char* asc_out = ascii_buffer;
-
- sprintf(code_buffer, "%08x ", p);
-
- int i;
- for (i = 0; i < 4; i++) {
- /*
- * If we see (data == -1 && errno != 0), we know that the ptrace
- * call failed, probably because we're dumping memory in an
- * unmapped or inaccessible page. I don't know if there's
- * value in making that explicit in the output -- it likely
- * just complicates parsing and clarifies nothing for the
- * enlightened reader.
- */
- long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
- sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
-
- int j;
- for (j = 0; j < 4; j++) {
- /*
- * Our isprint() allows high-ASCII characters that display
- * differently (often badly) in different viewers, so we
- * just use a simpler test.
- */
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
- p += 4;
- }
- *asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
- }
-}
-
-/*
- * If configured to do so, dump memory around *all* registers
- * for the crashing thread.
- */
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
- pt_regs_mips_t r;
- if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- return;
- }
-
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
-
- for (int reg = 0; reg < 32; reg++) {
- /* skip uninteresting registers */
- if (reg == 0 /* $0 */
- || reg == 26 /* $k0 */
- || reg == 27 /* $k1 */
- || reg == 31 /* $ra (done below) */
- )
- continue;
-
- uintptr_t addr = R(r.regs[reg]);
-
- /*
- * Don't bother if it looks like a small int or ~= null, or if
- * it's in the kernel area.
- */
- if (addr < 4096 || addr >= 0x80000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
- }
- }
-
- unsigned int pc = R(r.cp0_epc);
- unsigned int ra = R(r.regs[31]);
-
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc, scope_flags);
-
- if (pc != ra) {
- _LOG(log, scope_flags, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra, scope_flags);
- }
-}
-
-void dump_registers(log_t* log, pid_t tid, int scope_flags)
-{
- pt_regs_mips_t r;
- if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
- return;
- }
-
- _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n",
- R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
- R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
- R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
- R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
- R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
- R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
- R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n",
- R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n",
- R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
-}
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
new file mode 100644
index 0000000..d1a7f2d
--- /dev/null
+++ b/debuggerd/mips/machine.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2012, 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include <corkscrew/ptrace.h>
+
+#include <sys/user.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+// enable to dump memory pointed to by every register
+#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
+
+#define R(x) (static_cast<unsigned int>(x))
+
+static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+ char code_buffer[64]; // actual 8+1+((8+1)*4) + 1 == 45
+ char ascii_buffer[32]; // actual 16 + 1 == 17
+ uintptr_t p, end;
+
+ p = addr & ~3;
+ p -= 32;
+ if (p > addr) {
+ // catch underflow
+ p = 0;
+ }
+ end = p + 80;
+ // catch overflow; 'end - p' has to be multiples of 16
+ while (end < p)
+ end -= 16;
+
+ // Dump the code around PC as:
+ // addr contents ascii
+ // 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
+ // 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
+ while (p < end) {
+ char* asc_out = ascii_buffer;
+
+ sprintf(code_buffer, "%08x ", p);
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ // If we see (data == -1 && errno != 0), we know that the ptrace
+ // call failed, probably because we're dumping memory in an
+ // unmapped or inaccessible page. I don't know if there's
+ // value in making that explicit in the output -- it likely
+ // just complicates parsing and clarifies nothing for the
+ // enlightened reader.
+ long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
+ sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
+
+ int j;
+ for (j = 0; j < 4; j++) {
+ // Our isprint() allows high-ASCII characters that display
+ // differently (often badly) in different viewers, so we
+ // just use a simpler test.
+ char val = (data >> (j*8)) & 0xff;
+ if (val >= 0x20 && val < 0x7f) {
+ *asc_out++ = val;
+ } else {
+ *asc_out++ = '.';
+ }
+ }
+ p += 4;
+ }
+ *asc_out = '\0';
+ _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
+ }
+}
+
+// If configured to do so, dump memory around *all* registers
+// for the crashing thread.
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+ pt_regs_mips_t r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+ return;
+ }
+
+ if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+ static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+
+ for (int reg = 0; reg < 32; reg++) {
+ // skip uninteresting registers
+ if (reg == 0 // $0
+ || reg == 26 // $k0
+ || reg == 27 // $k1
+ || reg == 31 // $ra (done below)
+ )
+ continue;
+
+ uintptr_t addr = R(r.regs[reg]);
+
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0x80000000) {
+ continue;
+ }
+
+ _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ }
+ }
+
+ unsigned int pc = R(r.cp0_epc);
+ unsigned int ra = R(r.regs[31]);
+
+ _LOG(log, scope_flags, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)pc, scope_flags);
+
+ if (pc != ra) {
+ _LOG(log, scope_flags, "\ncode around ra:\n");
+ dump_memory(log, tid, (uintptr_t)ra, scope_flags);
+ }
+}
+
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+ pt_regs_mips_t r;
+ if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n",
+ R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
+ _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
+ R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
+ _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
+ R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
+ _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
+ R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
+ _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
+ R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
+ _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
+ R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
+ _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
+ R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
+ _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n",
+ R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
+ _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n",
+ R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
+}
diff --git a/debuggerd/tombstone.c b/debuggerd/tombstone.c
deleted file mode 100644
index aa63547..0000000
--- a/debuggerd/tombstone.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * Copyright (C) 2012 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 <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dirent.h>
-#include <time.h>
-#include <sys/ptrace.h>
-#include <sys/stat.h>
-
-#include <private/android_filesystem_config.h>
-
-#include <log/logger.h>
-#include <cutils/properties.h>
-
-#include <backtrace/backtrace.h>
-
-#include <sys/socket.h>
-#include <linux/un.h>
-
-#include <selinux/android.h>
-
-#include "machine.h"
-#include "tombstone.h"
-#include "backtrace.h"
-
-#define STACK_WORDS 16
-
-#define MAX_TOMBSTONES 10
-#define TOMBSTONE_DIR "/data/tombstones"
-
-/* Must match the path defined in NativeCrashListener.java */
-#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-
-#define typecheck(x,y) { \
- typeof(x) __dummy1; \
- typeof(y) __dummy2; \
- (void)(&__dummy1 == &__dummy2); }
-
-
-static bool signal_has_address(int sig) {
- switch (sig) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
- case SIGBUS:
- return true;
- default:
- return false;
- }
-}
-
-static const char *get_signame(int sig)
-{
- switch(sig) {
- case SIGILL: return "SIGILL";
- case SIGABRT: return "SIGABRT";
- case SIGBUS: return "SIGBUS";
- case SIGFPE: return "SIGFPE";
- case SIGSEGV: return "SIGSEGV";
- case SIGPIPE: return "SIGPIPE";
-#ifdef SIGSTKFLT
- case SIGSTKFLT: return "SIGSTKFLT";
-#endif
- case SIGSTOP: return "SIGSTOP";
- default: return "?";
- }
-}
-
-static const char *get_sigcode(int signo, int code)
-{
- // Try the signal-specific codes...
- switch (signo) {
- case SIGILL:
- switch (code) {
- case ILL_ILLOPC: return "ILL_ILLOPC";
- case ILL_ILLOPN: return "ILL_ILLOPN";
- case ILL_ILLADR: return "ILL_ILLADR";
- case ILL_ILLTRP: return "ILL_ILLTRP";
- case ILL_PRVOPC: return "ILL_PRVOPC";
- case ILL_PRVREG: return "ILL_PRVREG";
- case ILL_COPROC: return "ILL_COPROC";
- case ILL_BADSTK: return "ILL_BADSTK";
- }
- break;
- case SIGBUS:
- switch (code) {
- case BUS_ADRALN: return "BUS_ADRALN";
- case BUS_ADRERR: return "BUS_ADRERR";
- case BUS_OBJERR: return "BUS_OBJERR";
- }
- break;
- case SIGFPE:
- switch (code) {
- case FPE_INTDIV: return "FPE_INTDIV";
- case FPE_INTOVF: return "FPE_INTOVF";
- case FPE_FLTDIV: return "FPE_FLTDIV";
- case FPE_FLTOVF: return "FPE_FLTOVF";
- case FPE_FLTUND: return "FPE_FLTUND";
- case FPE_FLTRES: return "FPE_FLTRES";
- case FPE_FLTINV: return "FPE_FLTINV";
- case FPE_FLTSUB: return "FPE_FLTSUB";
- }
- break;
- case SIGSEGV:
- switch (code) {
- case SEGV_MAPERR: return "SEGV_MAPERR";
- case SEGV_ACCERR: return "SEGV_ACCERR";
- }
- break;
- case SIGTRAP:
- switch (code) {
- case TRAP_BRKPT: return "TRAP_BRKPT";
- case TRAP_TRACE: return "TRAP_TRACE";
- }
- break;
- }
- // Then the other codes...
- switch (code) {
- case SI_USER: return "SI_USER";
-#if defined(SI_KERNEL)
- case SI_KERNEL: return "SI_KERNEL";
-#endif
- case SI_QUEUE: return "SI_QUEUE";
- case SI_TIMER: return "SI_TIMER";
- case SI_MESGQ: return "SI_MESGQ";
- case SI_ASYNCIO: return "SI_ASYNCIO";
-#if defined(SI_SIGIO)
- case SI_SIGIO: return "SI_SIGIO";
-#endif
-#if defined(SI_TKILL)
- case SI_TKILL: return "SI_TKILL";
-#endif
- }
- // Then give up...
- return "?";
-}
-
-static void dump_revision_info(log_t* log)
-{
- char revision[PROPERTY_VALUE_MAX];
-
- property_get("ro.revision", revision, "unknown");
-
- _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
-}
-
-static void dump_build_info(log_t* log)
-{
- char fingerprint[PROPERTY_VALUE_MAX];
-
- property_get("ro.build.fingerprint", fingerprint, "unknown");
-
- _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
-}
-
-static void dump_fault_addr(log_t* log, pid_t tid, int sig)
-{
- siginfo_t si;
-
- memset(&si, 0, sizeof(si));
- if(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
- _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
- } else if (signal_has_address(sig)) {
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %08x\n",
- sig, get_signame(sig),
- si.si_code, get_sigcode(sig, si.si_code),
- (uintptr_t) si.si_addr);
- } else {
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
- sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
- }
-}
-
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
- char path[64];
- char threadnamebuf[1024];
- char* threadname = NULL;
- FILE *fp;
-
- snprintf(path, sizeof(path), "/proc/%d/comm", tid);
- if ((fp = fopen(path, "r"))) {
- threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
- fclose(fp);
- if (threadname) {
- size_t len = strlen(threadname);
- if (len && threadname[len - 1] == '\n') {
- threadname[len - 1] = '\0';
- }
- }
- }
-
- if (IS_AT_FAULT(scope_flags)) {
- char procnamebuf[1024];
- char* procname = NULL;
-
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
- threadname ? threadname : "UNKNOWN",
- procname ? procname : "UNKNOWN");
- } else {
- _LOG(log, 0, "pid: %d, tid: %d, name: %s\n",
- pid, tid, threadname ? threadname : "UNKNOWN");
- }
-}
-
-static void dump_stack_segment(const backtrace_context_t* context, log_t* log,
- int scope_flags, uintptr_t *sp, size_t words, int label) {
- for (size_t i = 0; i < words; i++) {
- uint32_t stack_content;
- if (!backtrace_read_word(context, *sp, &stack_content)) {
- break;
- }
-
- const char* map_name = backtrace_get_map_name(context, stack_content, NULL);
- if (!map_name) {
- map_name = "";
- }
- uintptr_t offset = 0;
- char* func_name = backtrace_get_func_name(context, stack_content, &offset);
- if (func_name) {
- if (!i && label >= 0) {
- if (offset) {
- _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n",
- label, *sp, stack_content, map_name, func_name, offset);
- } else {
- _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n",
- label, *sp, stack_content, map_name, func_name);
- }
- } else {
- if (offset) {
- _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n",
- *sp, stack_content, map_name, func_name, offset);
- } else {
- _LOG(log, scope_flags, " %08x %08x %s (%s)\n",
- *sp, stack_content, map_name, func_name);
- }
- }
- free(func_name);
- } else {
- if (!i && label >= 0) {
- _LOG(log, scope_flags, " #%02d %08x %08x %s\n",
- label, *sp, stack_content, map_name);
- } else {
- _LOG(log, scope_flags, " %08x %08x %s\n",
- *sp, stack_content, map_name);
- }
- }
-
- *sp += sizeof(uint32_t);
- }
-}
-
-static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) {
- const backtrace_t* backtrace = context->backtrace;
- size_t first = 0, last;
- for (size_t i = 0; i < backtrace->num_frames; i++) {
- if (backtrace->frames[i].sp) {
- if (!first) {
- first = i+1;
- }
- last = i;
- }
- }
- if (!first) {
- return;
- }
- first--;
-
- scope_flags |= SCOPE_SENSITIVE;
-
- // Dump a few words before the first frame.
- uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t);
- dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1);
-
- // Dump a few words from all successive frames.
- // Only log the first 3 frames, put the rest in the tombstone.
- for (size_t i = first; i <= last; i++) {
- const backtrace_frame_data_t* frame = &backtrace->frames[i];
- if (sp != frame->sp) {
- _LOG(log, scope_flags, " ........ ........\n");
- sp = frame->sp;
- }
- if (i - first == 3) {
- scope_flags &= (~SCOPE_AT_FAULT);
- }
- if (i == last) {
- dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i);
- if (sp < frame->sp + frame->stack_size) {
- _LOG(log, scope_flags, " ........ ........\n");
- }
- } else {
- size_t words = frame->stack_size / sizeof(uint32_t);
- if (words == 0) {
- words = 1;
- } else if (words > STACK_WORDS) {
- words = STACK_WORDS;
- }
- dump_stack_segment(context, log, scope_flags, &sp, words, i);
- }
- }
-}
-
-static void dump_backtrace_and_stack(const backtrace_context_t* context,
- log_t* log, int scope_flags) {
- if (context->backtrace->num_frames) {
- _LOG(log, scope_flags, "\nbacktrace:\n");
- dump_backtrace_to_log(context, log, scope_flags, " ");
-
- _LOG(log, scope_flags, "\nstack:\n");
- dump_stack(context, log, scope_flags);
- }
-}
-
-static void dump_map(log_t* log, const backtrace_map_info_t* m, const char* what, int scope_flags) {
- if (m != NULL) {
- _LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", m->start, m->end,
- m->is_readable ? 'r' : '-',
- m->is_writable ? 'w' : '-',
- m->is_executable ? 'x' : '-',
- m->name);
- } else {
- _LOG(log, scope_flags, " (no %s)\n", what);
- }
-}
-
-static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* log, pid_t tid, int scope_flags) {
- scope_flags |= SCOPE_SENSITIVE;
- siginfo_t si;
- memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
- _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n",
- tid, strerror(errno));
- return;
- }
- if (!signal_has_address(si.si_signo)) {
- return;
- }
-
- uintptr_t addr = (uintptr_t) si.si_addr;
- addr &= ~0xfff; /* round to 4K page boundary */
- if (addr == 0) { /* null-pointer deref */
- return;
- }
-
- _LOG(log, scope_flags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
-
- /*
- * Search for a match, or for a hole where the match would be. The list
- * is backward from the file content, so it starts at high addresses.
- */
- const backtrace_map_info_t* map = map_info_list;
- const backtrace_map_info_t* next = NULL;
- const backtrace_map_info_t* prev = NULL;
- while (map != NULL) {
- if (addr >= map->start && addr < map->end) {
- next = map->next;
- break;
- } else if (addr >= map->end) {
- /* map would be between "prev" and this entry */
- next = map;
- map = NULL;
- break;
- }
-
- prev = map;
- map = map->next;
- }
-
- /*
- * Show "next" then "match" then "prev" so that the addresses appear in
- * ascending order (like /proc/pid/maps).
- */
- dump_map(log, next, "map below", scope_flags);
- dump_map(log, map, "map for address", scope_flags);
- dump_map(log, prev, "map above", scope_flags);
-}
-
-static void dump_thread(const backtrace_context_t* context, log_t* log,
- int scope_flags, int* total_sleep_time_usec) {
- const backtrace_t* backtrace = context->backtrace;
- wait_for_stop(backtrace->tid, total_sleep_time_usec);
-
- dump_registers(log, backtrace->tid, scope_flags);
- dump_backtrace_and_stack(context, log, scope_flags);
- if (IS_AT_FAULT(scope_flags)) {
- dump_memory_and_code(log, backtrace->tid, scope_flags);
- dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags);
- }
-}
-
-/* Return true if some thread is not detached cleanly */
-static bool dump_sibling_thread_report(
- log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec) {
- char task_path[64];
- snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
-
- DIR* d = opendir(task_path);
- /* Bail early if the task directory cannot be opened */
- if (d == NULL) {
- XLOG("Cannot open /proc/%d/task\n", pid);
- return false;
- }
-
- bool detach_failed = false;
- struct dirent* de;
- while ((de = readdir(d)) != NULL) {
- /* Ignore "." and ".." */
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
- continue;
- }
-
- /* The main thread at fault has been handled individually */
- char* end;
- pid_t new_tid = strtoul(de->d_name, &end, 10);
- if (*end || new_tid == tid) {
- continue;
- }
-
- /* Skip this thread if cannot ptrace it */
- if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
- continue;
- }
-
- _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
- dump_thread_info(log, pid, new_tid, 0);
- backtrace_context_t new_context;
- if (backtrace_create_context(&new_context, pid, new_tid, 0)) {
- dump_thread(&new_context, log, 0, total_sleep_time_usec);
- backtrace_destroy_context(&new_context);
- }
-
- if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
- detach_failed = true;
- }
- }
-
- closedir(d);
- return detach_failed;
-}
-
-/*
- * Reads the contents of the specified log device, filters out the entries
- * that don't match the specified pid, and writes them to the tombstone file.
- *
- * If "tailOnly" is set, we only print the last few lines.
- */
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
- bool tailOnly)
-{
- bool first = true;
-
- /* circular buffer, for "tailOnly" mode */
- const int kShortLogMaxLines = 5;
- const int kShortLogLineLen = 256;
- char shortLog[kShortLogMaxLines][kShortLogLineLen];
- int shortLogCount = 0;
- int shortLogNext = 0;
-
- int logfd = open(filename, O_RDONLY | O_NONBLOCK);
- if (logfd < 0) {
- XLOG("Unable to open %s: %s\n", filename, strerror(errno));
- return;
- }
-
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry entry;
- } log_entry;
-
- while (true) {
- ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
- if (actual < 0) {
- if (errno == EINTR) {
- /* interrupted by signal, retry */
- continue;
- } else if (errno == EAGAIN) {
- /* non-blocking EOF; we're done */
- break;
- } else {
- _LOG(log, 0, "Error while reading log: %s\n",
- strerror(errno));
- break;
- }
- } else if (actual == 0) {
- _LOG(log, 0, "Got zero bytes while reading log: %s\n",
- strerror(errno));
- break;
- }
-
- /*
- * NOTE: if you XLOG something here, this will spin forever,
- * because you will be writing as fast as you're reading. Any
- * high-frequency debug diagnostics should just be written to
- * the tombstone file.
- */
-
- struct logger_entry* entry = &log_entry.entry;
-
- if (entry->pid != (int32_t) pid) {
- /* wrong pid, ignore */
- continue;
- }
-
- if (first) {
- _LOG(log, 0, "--------- %slog %s\n",
- tailOnly ? "tail end of " : "", filename);
- first = false;
- }
-
- /*
- * Msg format is: <priority:1><tag:N>\0<message:N>\0
- *
- * We want to display it in the same format as "logcat -v threadtime"
- * (although in this case the pid is redundant).
- *
- * TODO: scan for line breaks ('\n') and display each text line
- * on a separate line, prefixed with the header, like logcat does.
- */
- static const char* kPrioChars = "!.VDIWEFS";
- unsigned char prio = entry->msg[0];
- char* tag = entry->msg + 1;
- char* msg = tag + strlen(tag) + 1;
-
- /* consume any trailing newlines */
- char* eatnl = msg + strlen(msg) - 1;
- while (eatnl >= msg && *eatnl == '\n') {
- *eatnl-- = '\0';
- }
-
- char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
-
- char timeBuf[32];
- time_t sec = (time_t) entry->sec;
- struct tm tmBuf;
- struct tm* ptm;
- ptm = localtime_r(&sec, &tmBuf);
- strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
-
- if (tailOnly) {
- snprintf(shortLog[shortLogNext], kShortLogLineLen,
- "%s.%03d %5d %5d %c %-8s: %s",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- prioChar, tag, msg);
- shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
- shortLogCount++;
- } else {
- _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- prioChar, tag, msg);
- }
- }
-
- if (tailOnly) {
- int i;
-
- /*
- * If we filled the buffer, we want to start at "next", which has
- * the oldest entry. If we didn't, we want to start at zero.
- */
- if (shortLogCount < kShortLogMaxLines) {
- shortLogNext = 0;
- } else {
- shortLogCount = kShortLogMaxLines; /* cap at window size */
- }
-
- for (i = 0; i < shortLogCount; i++) {
- _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
- shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
- }
- }
-
- close(logfd);
-}
-
-/*
- * Dumps the logs generated by the specified pid to the tombstone, from both
- * "system" and "main" log devices. Ideally we'd interleave the output.
- */
-static void dump_logs(log_t* log, pid_t pid, bool tailOnly)
-{
- dump_log_file(log, pid, "/dev/log/system", tailOnly);
- dump_log_file(log, pid, "/dev/log/main", tailOnly);
-}
-
-static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) {
- if (address == 0) {
- return;
- }
-
- address += sizeof(size_t); // Skip the buffer length.
-
- char msg[512];
- memset(msg, 0, sizeof(msg));
- char* p = &msg[0];
- while (p < &msg[sizeof(msg)]) {
- uint32_t data;
- if (!backtrace_read_word(context, address, &data)) {
- break;
- }
- address += sizeof(uint32_t);
-
- if ((*p++ = (data >> 0) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 8) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 16) & 0xff) == 0) {
- break;
- }
- if ((*p++ = (data >> 24) & 0xff) == 0) {
- break;
- }
- }
- msg[sizeof(msg) - 1] = '\0';
-
- _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
-}
-
-/*
- * Dumps all information about the specified pid to the tombstone.
- */
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
- bool dump_sibling_threads, int* total_sleep_time_usec)
-{
- /* don't copy log messages to tombstone unless this is a dev device */
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.debuggable", value, "0");
- bool want_logs = (value[0] == '1');
-
- if (log->amfd >= 0) {
- /*
- * Activity Manager protocol: binary 32-bit network-byte-order ints for the
- * pid and signal number, followed by the raw text of the dump, culminating
- * in a zero byte that marks end-of-data.
- */
- uint32_t datum = htonl(pid);
- TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
- datum = htonl(signal);
- TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
- }
-
- _LOG(log, SCOPE_AT_FAULT,
- "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- dump_build_info(log);
- dump_revision_info(log);
- dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
- if (signal) {
- dump_fault_addr(log, tid, signal);
- }
-
- backtrace_context_t context;
- if (backtrace_create_context(&context, pid, tid, 0)) {
- dump_abort_message(&context, log, abort_msg_address);
- dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec);
- backtrace_destroy_context(&context);
- }
-
- if (want_logs) {
- dump_logs(log, pid, true);
- }
-
- bool detach_failed = false;
- if (dump_sibling_threads) {
- detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec);
- }
-
- if (want_logs) {
- dump_logs(log, pid, false);
- }
-
- /* send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
- * and killing the target out from under it */
- if (log->amfd >= 0) {
- uint8_t eodMarker = 0;
- TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
- /* 3 sec timeout reading the ack; we're fine if that happens */
- TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
- }
-
- return detach_failed;
-}
-
-/*
- * find_and_open_tombstone - find an available tombstone slot, if any, of the
- * form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
- * file is available, we reuse the least-recently-modified file.
- *
- * Returns the path of the tombstone file, allocated using malloc(). Caller must free() it.
- */
-static char* find_and_open_tombstone(int* fd)
-{
- unsigned long mtime = ULONG_MAX;
- struct stat sb;
-
- /*
- * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
- * to, our logic breaks. This check will generate a warning if that happens.
- */
- typecheck(mtime, sb.st_mtime);
-
- /*
- * In a single wolf-like pass, find an available slot and, in case none
- * exist, find and record the least-recently-modified file.
- */
- char path[128];
- int oldest = 0;
- for (int i = 0; i < MAX_TOMBSTONES; i++) {
- snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
-
- if (!stat(path, &sb)) {
- if (sb.st_mtime < mtime) {
- oldest = i;
- mtime = sb.st_mtime;
- }
- continue;
- }
- if (errno != ENOENT)
- continue;
-
- *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
- if (*fd < 0)
- continue; /* raced ? */
-
- fchown(*fd, AID_SYSTEM, AID_SYSTEM);
- return strdup(path);
- }
-
- /* we didn't find an available file, so we clobber the oldest one */
- snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
- *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
- if (*fd < 0) {
- LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
- return NULL;
- }
- fchown(*fd, AID_SYSTEM, AID_SYSTEM);
- return strdup(path);
-}
-
-static int activity_manager_connect() {
- int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (amfd >= 0) {
- struct sockaddr_un address;
- int err;
-
- memset(&address, 0, sizeof(address));
- address.sun_family = AF_UNIX;
- strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
- err = TEMP_FAILURE_RETRY( connect(amfd, (struct sockaddr*) &address, sizeof(address)) );
- if (!err) {
- struct timeval tv;
- memset(&tv, 0, sizeof(tv));
- tv.tv_sec = 1; // tight leash
- err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- if (!err) {
- tv.tv_sec = 3; // 3 seconds on handshake read
- err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- }
- }
- if (err) {
- close(amfd);
- amfd = -1;
- }
- }
-
- return amfd;
-}
-
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
- bool dump_sibling_threads, bool quiet, bool* detach_failed,
- int* total_sleep_time_usec) {
- mkdir(TOMBSTONE_DIR, 0755);
- chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
-
- if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
- *detach_failed = false;
- return NULL;
- }
-
- int fd;
- char* path = find_and_open_tombstone(&fd);
- if (!path) {
- *detach_failed = false;
- return NULL;
- }
-
- log_t log;
- log.tfd = fd;
- log.amfd = activity_manager_connect();
- log.quiet = quiet;
- *detach_failed = dump_crash(&log, pid, tid, signal, abort_msg_address, dump_sibling_threads,
- total_sleep_time_usec);
-
- close(log.amfd);
- close(fd);
- return path;
-}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
new file mode 100644
index 0000000..acb6ed6
--- /dev/null
+++ b/debuggerd/tombstone.cpp
@@ -0,0 +1,786 @@
+/*
+ * Copyright (C) 2012 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 <stddef.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <time.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+#include <private/android_filesystem_config.h>
+
+#include <log/logger.h>
+#include <cutils/properties.h>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <sys/socket.h>
+#include <linux/un.h>
+
+#include <selinux/android.h>
+
+#include <UniquePtr.h>
+
+#include "machine.h"
+#include "tombstone.h"
+#include "backtrace.h"
+
+#define STACK_WORDS 16
+
+#define MAX_TOMBSTONES 10
+#define TOMBSTONE_DIR "/data/tombstones"
+
+// Must match the path defined in NativeCrashListener.java
+#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
+
+#define typecheck(x,y) { \
+ typeof(x) __dummy1; \
+ typeof(y) __dummy2; \
+ (void)(&__dummy1 == &__dummy2); }
+
+
+static bool signal_has_address(int sig) {
+ switch (sig) {
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGBUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const char* get_signame(int sig) {
+ switch(sig) {
+ case SIGILL: return "SIGILL";
+ case SIGABRT: return "SIGABRT";
+ case SIGBUS: return "SIGBUS";
+ case SIGFPE: return "SIGFPE";
+ case SIGSEGV: return "SIGSEGV";
+ case SIGPIPE: return "SIGPIPE";
+#ifdef SIGSTKFLT
+ case SIGSTKFLT: return "SIGSTKFLT";
+#endif
+ case SIGSTOP: return "SIGSTOP";
+ default: return "?";
+ }
+}
+
+static const char* get_sigcode(int signo, int code) {
+ // Try the signal-specific codes...
+ switch (signo) {
+ case SIGILL:
+ switch (code) {
+ case ILL_ILLOPC: return "ILL_ILLOPC";
+ case ILL_ILLOPN: return "ILL_ILLOPN";
+ case ILL_ILLADR: return "ILL_ILLADR";
+ case ILL_ILLTRP: return "ILL_ILLTRP";
+ case ILL_PRVOPC: return "ILL_PRVOPC";
+ case ILL_PRVREG: return "ILL_PRVREG";
+ case ILL_COPROC: return "ILL_COPROC";
+ case ILL_BADSTK: return "ILL_BADSTK";
+ }
+ break;
+ case SIGBUS:
+ switch (code) {
+ case BUS_ADRALN: return "BUS_ADRALN";
+ case BUS_ADRERR: return "BUS_ADRERR";
+ case BUS_OBJERR: return "BUS_OBJERR";
+ }
+ break;
+ case SIGFPE:
+ switch (code) {
+ case FPE_INTDIV: return "FPE_INTDIV";
+ case FPE_INTOVF: return "FPE_INTOVF";
+ case FPE_FLTDIV: return "FPE_FLTDIV";
+ case FPE_FLTOVF: return "FPE_FLTOVF";
+ case FPE_FLTUND: return "FPE_FLTUND";
+ case FPE_FLTRES: return "FPE_FLTRES";
+ case FPE_FLTINV: return "FPE_FLTINV";
+ case FPE_FLTSUB: return "FPE_FLTSUB";
+ }
+ break;
+ case SIGSEGV:
+ switch (code) {
+ case SEGV_MAPERR: return "SEGV_MAPERR";
+ case SEGV_ACCERR: return "SEGV_ACCERR";
+ }
+ break;
+ case SIGTRAP:
+ switch (code) {
+ case TRAP_BRKPT: return "TRAP_BRKPT";
+ case TRAP_TRACE: return "TRAP_TRACE";
+ }
+ break;
+ }
+ // Then the other codes...
+ switch (code) {
+ case SI_USER: return "SI_USER";
+#if defined(SI_KERNEL)
+ case SI_KERNEL: return "SI_KERNEL";
+#endif
+ case SI_QUEUE: return "SI_QUEUE";
+ case SI_TIMER: return "SI_TIMER";
+ case SI_MESGQ: return "SI_MESGQ";
+ case SI_ASYNCIO: return "SI_ASYNCIO";
+#if defined(SI_SIGIO)
+ case SI_SIGIO: return "SI_SIGIO";
+#endif
+#if defined(SI_TKILL)
+ case SI_TKILL: return "SI_TKILL";
+#endif
+ }
+ // Then give up...
+ return "?";
+}
+
+static void dump_revision_info(log_t* log) {
+ char revision[PROPERTY_VALUE_MAX];
+
+ property_get("ro.revision", revision, "unknown");
+
+ _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
+}
+
+static void dump_build_info(log_t* log) {
+ char fingerprint[PROPERTY_VALUE_MAX];
+
+ property_get("ro.build.fingerprint", fingerprint, "unknown");
+
+ _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
+}
+
+static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
+ siginfo_t si;
+
+ memset(&si, 0, sizeof(si));
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
+ _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
+ } else if (signal_has_address(sig)) {
+ _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %0*" PRIxPTR "\n",
+ sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
+ sizeof(uintptr_t)*2, reinterpret_cast<uintptr_t>(si.si_addr));
+ } else {
+ _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
+ sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
+ }
+}
+
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
+ char path[64];
+ char threadnamebuf[1024];
+ char* threadname = NULL;
+ FILE *fp;
+
+ snprintf(path, sizeof(path), "/proc/%d/comm", tid);
+ if ((fp = fopen(path, "r"))) {
+ threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
+ fclose(fp);
+ if (threadname) {
+ size_t len = strlen(threadname);
+ if (len && threadname[len - 1] == '\n') {
+ threadname[len - 1] = '\0';
+ }
+ }
+ }
+
+ if (IS_AT_FAULT(scope_flags)) {
+ char procnamebuf[1024];
+ char* procname = NULL;
+
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+ if ((fp = fopen(path, "r"))) {
+ procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+ fclose(fp);
+ }
+
+ _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
+ threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
+ } else {
+ _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
+ }
+}
+
+static void dump_stack_segment(
+ Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
+ for (size_t i = 0; i < words; i++) {
+ uint32_t stack_content;
+ if (!backtrace->ReadWord(*sp, &stack_content)) {
+ break;
+ }
+
+ const backtrace_map_t* map = backtrace->FindMap(stack_content);
+ const char* map_name;
+ if (!map) {
+ map_name = "";
+ } else {
+ map_name = map->name.c_str();
+ }
+ uintptr_t offset = 0;
+ std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
+ if (!func_name.empty()) {
+ if (!i && label >= 0) {
+ if (offset) {
+ _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n",
+ label, *sp, stack_content, map_name, func_name.c_str(), offset);
+ } else {
+ _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n",
+ label, *sp, stack_content, map_name, func_name.c_str());
+ }
+ } else {
+ if (offset) {
+ _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n",
+ *sp, stack_content, map_name, func_name.c_str(), offset);
+ } else {
+ _LOG(log, scope_flags, " %08x %08x %s (%s)\n",
+ *sp, stack_content, map_name, func_name.c_str());
+ }
+ }
+ } else {
+ if (!i && label >= 0) {
+ _LOG(log, scope_flags, " #%02d %08x %08x %s\n",
+ label, *sp, stack_content, map_name);
+ } else {
+ _LOG(log, scope_flags, " %08x %08x %s\n",
+ *sp, stack_content, map_name);
+ }
+ }
+
+ *sp += sizeof(uint32_t);
+ }
+}
+
+static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+ size_t first = 0, last;
+ for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+ const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
+ if (frame->sp) {
+ if (!first) {
+ first = i+1;
+ }
+ last = i;
+ }
+ }
+ if (!first) {
+ return;
+ }
+ first--;
+
+ scope_flags |= SCOPE_SENSITIVE;
+
+ // Dump a few words before the first frame.
+ uintptr_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(uint32_t);
+ dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+
+ // Dump a few words from all successive frames.
+ // Only log the first 3 frames, put the rest in the tombstone.
+ for (size_t i = first; i <= last; i++) {
+ const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
+ if (sp != frame->sp) {
+ _LOG(log, scope_flags, " ........ ........\n");
+ sp = frame->sp;
+ }
+ if (i - first == 3) {
+ scope_flags &= (~SCOPE_AT_FAULT);
+ }
+ if (i == last) {
+ dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+ if (sp < frame->sp + frame->stack_size) {
+ _LOG(log, scope_flags, " ........ ........\n");
+ }
+ } else {
+ size_t words = frame->stack_size / sizeof(uint32_t);
+ if (words == 0) {
+ words = 1;
+ } else if (words > STACK_WORDS) {
+ words = STACK_WORDS;
+ }
+ dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+ }
+ }
+}
+
+static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+ if (backtrace->NumFrames()) {
+ _LOG(log, scope_flags, "\nbacktrace:\n");
+ dump_backtrace_to_log(backtrace, log, scope_flags, " ");
+
+ _LOG(log, scope_flags, "\nstack:\n");
+ dump_stack(backtrace, log, scope_flags);
+ }
+}
+
+static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
+ if (map != NULL) {
+ _LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", map->start, map->end,
+ (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
+ (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
+ } else {
+ _LOG(log, scope_flags, " (no %s)\n", what);
+ }
+}
+
+static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
+ scope_flags |= SCOPE_SENSITIVE;
+ siginfo_t si;
+ memset(&si, 0, sizeof(si));
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
+ _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
+ return;
+ }
+ if (!signal_has_address(si.si_signo)) {
+ return;
+ }
+
+ uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
+ addr &= ~0xfff; // round to 4K page boundary
+ if (addr == 0) { // null-pointer deref
+ return;
+ }
+
+ _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIxPTR ":\n",
+ reinterpret_cast<uintptr_t>(si.si_addr));
+
+ // Search for a match, or for a hole where the match would be. The list
+ // is backward from the file content, so it starts at high addresses.
+ const backtrace_map_t* cur_map = NULL;
+ const backtrace_map_t* next_map = NULL;
+ const backtrace_map_t* prev_map = NULL;
+ for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+ if (addr >= it->start && addr < it->end) {
+ cur_map = &*it;
+ if (it != map->begin()) {
+ prev_map = &*(it-1);
+ }
+ if (++it != map->end()) {
+ next_map = &*it;
+ }
+ break;
+ }
+ }
+
+ // Show the map address in ascending order (like /proc/pid/maps).
+ dump_map(log, prev_map, "map below", scope_flags);
+ dump_map(log, cur_map, "map for address", scope_flags);
+ dump_map(log, next_map, "map above", scope_flags);
+}
+
+static void dump_thread(
+ Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) {
+ wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
+
+ dump_registers(log, backtrace->Tid(), scope_flags);
+ dump_backtrace_and_stack(backtrace, log, scope_flags);
+ if (IS_AT_FAULT(scope_flags)) {
+ dump_memory_and_code(log, backtrace->Tid(), scope_flags);
+ dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
+ }
+}
+
+// Return true if some thread is not detached cleanly
+static bool dump_sibling_thread_report(
+ log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
+ char task_path[64];
+ snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+
+ DIR* d = opendir(task_path);
+ // Bail early if the task directory cannot be opened
+ if (d == NULL) {
+ XLOG("Cannot open /proc/%d/task\n", pid);
+ return false;
+ }
+
+ bool detach_failed = false;
+ struct dirent* de;
+ while ((de = readdir(d)) != NULL) {
+ // Ignore "." and ".."
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+
+ // The main thread at fault has been handled individually
+ char* end;
+ pid_t new_tid = strtoul(de->d_name, &end, 10);
+ if (*end || new_tid == tid) {
+ continue;
+ }
+
+ // Skip this thread if cannot ptrace it
+ if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
+ continue;
+ }
+
+ _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+ dump_thread_info(log, pid, new_tid, 0);
+
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
+ if (backtrace->Unwind(0)) {
+ dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
+ }
+
+ if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
+ LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+ detach_failed = true;
+ }
+ }
+
+ closedir(d);
+ return detach_failed;
+}
+
+// Reads the contents of the specified log device, filters out the entries
+// that don't match the specified pid, and writes them to the tombstone file.
+//
+// If "tailOnly" is set, we only print the last few lines.
+static void dump_log_file(log_t* log, pid_t pid, const char* filename, bool tailOnly) {
+ bool first = true;
+
+ // circular buffer, for "tailOnly" mode
+ const int kShortLogMaxLines = 5;
+ const int kShortLogLineLen = 256;
+ char shortLog[kShortLogMaxLines][kShortLogLineLen];
+ int shortLogCount = 0;
+ int shortLogNext = 0;
+
+ int logfd = open(filename, O_RDONLY | O_NONBLOCK);
+ if (logfd < 0) {
+ XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+ return;
+ }
+
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+ struct logger_entry entry;
+ } log_entry;
+
+ while (true) {
+ ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
+ if (actual < 0) {
+ if (errno == EINTR) {
+ // interrupted by signal, retry
+ continue;
+ } else if (errno == EAGAIN) {
+ // non-blocking EOF; we're done
+ break;
+ } else {
+ _LOG(log, 0, "Error while reading log: %s\n", strerror(errno));
+ break;
+ }
+ } else if (actual == 0) {
+ _LOG(log, 0, "Got zero bytes while reading log: %s\n", strerror(errno));
+ break;
+ }
+
+ // NOTE: if you XLOG something here, this will spin forever,
+ // because you will be writing as fast as you're reading. Any
+ // high-frequency debug diagnostics should just be written to
+ // the tombstone file.
+ struct logger_entry* entry = &log_entry.entry;
+
+ if (entry->pid != static_cast<int32_t>(pid)) {
+ // wrong pid, ignore
+ continue;
+ }
+
+ if (first) {
+ _LOG(log, 0, "--------- %slog %s\n", tailOnly ? "tail end of " : "", filename);
+ first = false;
+ }
+
+ // Msg format is: <priority:1><tag:N>\0<message:N>\0
+ //
+ // We want to display it in the same format as "logcat -v threadtime"
+ // (although in this case the pid is redundant).
+ //
+ // TODO: scan for line breaks ('\n') and display each text line
+ // on a separate line, prefixed with the header, like logcat does.
+ static const char* kPrioChars = "!.VDIWEFS";
+ unsigned char prio = entry->msg[0];
+ char* tag = entry->msg + 1;
+ char* msg = tag + strlen(tag) + 1;
+
+ // consume any trailing newlines
+ char* eatnl = msg + strlen(msg) - 1;
+ while (eatnl >= msg && *eatnl == '\n') {
+ *eatnl-- = '\0';
+ }
+
+ char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
+ char timeBuf[32];
+ time_t sec = static_cast<time_t>(entry->sec);
+ struct tm tmBuf;
+ struct tm* ptm;
+ ptm = localtime_r(&sec, &tmBuf);
+ strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+
+ if (tailOnly) {
+ snprintf(shortLog[shortLogNext], kShortLogLineLen,
+ "%s.%03d %5d %5d %c %-8s: %s",
+ timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+ prioChar, tag, msg);
+ shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
+ shortLogCount++;
+ } else {
+ _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+ timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, prioChar, tag, msg);
+ }
+ }
+
+ if (tailOnly) {
+ int i;
+
+ // If we filled the buffer, we want to start at "next", which has
+ // the oldest entry. If we didn't, we want to start at zero.
+ if (shortLogCount < kShortLogMaxLines) {
+ shortLogNext = 0;
+ } else {
+ shortLogCount = kShortLogMaxLines; // cap at window size
+ }
+
+ for (i = 0; i < shortLogCount; i++) {
+ _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
+ shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
+ }
+ }
+
+ close(logfd);
+}
+
+// Dumps the logs generated by the specified pid to the tombstone, from both
+// "system" and "main" log devices. Ideally we'd interleave the output.
+static void dump_logs(log_t* log, pid_t pid, bool tailOnly) {
+ dump_log_file(log, pid, "/dev/log/system", tailOnly);
+ dump_log_file(log, pid, "/dev/log/main", tailOnly);
+}
+
+static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t address) {
+ if (address == 0) {
+ return;
+ }
+
+ address += sizeof(size_t); // Skip the buffer length.
+
+ char msg[512];
+ memset(msg, 0, sizeof(msg));
+ char* p = &msg[0];
+ while (p < &msg[sizeof(msg)]) {
+ uint32_t data;
+ if (!backtrace->ReadWord(address, &data)) {
+ break;
+ }
+ address += sizeof(uint32_t);
+
+ if ((*p++ = (data >> 0) & 0xff) == 0) {
+ break;
+ }
+ if ((*p++ = (data >> 8) & 0xff) == 0) {
+ break;
+ }
+ if ((*p++ = (data >> 16) & 0xff) == 0) {
+ break;
+ }
+ if ((*p++ = (data >> 24) & 0xff) == 0) {
+ break;
+ }
+ }
+ msg[sizeof(msg) - 1] = '\0';
+
+ _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+}
+
+// Dumps all information about the specified pid to the tombstone.
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
+ bool dump_sibling_threads, int* total_sleep_time_usec) {
+ // don't copy log messages to tombstone unless this is a dev device
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.debuggable", value, "0");
+ bool want_logs = (value[0] == '1');
+
+ if (log->amfd >= 0) {
+ // Activity Manager protocol: binary 32-bit network-byte-order ints for the
+ // pid and signal number, followed by the raw text of the dump, culminating
+ // in a zero byte that marks end-of-data.
+ uint32_t datum = htonl(pid);
+ TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+ datum = htonl(signal);
+ TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
+ }
+
+ _LOG(log, SCOPE_AT_FAULT,
+ "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
+ dump_build_info(log);
+ dump_revision_info(log);
+ dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
+ if (signal) {
+ dump_fault_addr(log, tid, signal);
+ }
+
+ BacktraceMap* map = NULL;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid));
+ if (backtrace->Unwind(0)) {
+ // Grab the map that was created and share it with the siblings.
+ map = backtrace->TakeMapOwnership();
+
+ dump_abort_message(backtrace.get(), log, abort_msg_address);
+ dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
+ }
+
+ if (want_logs) {
+ dump_logs(log, pid, true);
+ }
+
+ bool detach_failed = false;
+ if (dump_sibling_threads) {
+ detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map);
+ }
+
+ // Destroy the BacktraceMap object.
+ delete map;
+
+ if (want_logs) {
+ dump_logs(log, pid, false);
+ }
+
+ // send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
+ // and killing the target out from under it
+ if (log->amfd >= 0) {
+ uint8_t eodMarker = 0;
+ TEMP_FAILURE_RETRY( write(log->amfd, &eodMarker, 1) );
+ // 3 sec timeout reading the ack; we're fine if that happens
+ TEMP_FAILURE_RETRY( read(log->amfd, &eodMarker, 1) );
+ }
+
+ return detach_failed;
+}
+
+// find_and_open_tombstone - find an available tombstone slot, if any, of the
+// form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
+// file is available, we reuse the least-recently-modified file.
+//
+// Returns the path of the tombstone file, allocated using malloc(). Caller must free() it.
+static char* find_and_open_tombstone(int* fd) {
+ unsigned long mtime = ULONG_MAX;
+ struct stat sb;
+
+ // XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought
+ // to, our logic breaks. This check will generate a warning if that happens.
+ typecheck(mtime, sb.st_mtime);
+
+ // In a single wolf-like pass, find an available slot and, in case none
+ // exist, find and record the least-recently-modified file.
+ char path[128];
+ int oldest = 0;
+ for (int i = 0; i < MAX_TOMBSTONES; i++) {
+ snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i);
+
+ if (!stat(path, &sb)) {
+ if (sb.st_mtime < mtime) {
+ oldest = i;
+ mtime = sb.st_mtime;
+ }
+ continue;
+ }
+ if (errno != ENOENT)
+ continue;
+
+ *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ if (*fd < 0)
+ continue; // raced ?
+
+ fchown(*fd, AID_SYSTEM, AID_SYSTEM);
+ return strdup(path);
+ }
+
+ // we didn't find an available file, so we clobber the oldest one
+ snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest);
+ *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+ if (*fd < 0) {
+ LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
+ return NULL;
+ }
+ fchown(*fd, AID_SYSTEM, AID_SYSTEM);
+ return strdup(path);
+}
+
+static int activity_manager_connect() {
+ int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (amfd >= 0) {
+ struct sockaddr_un address;
+ int err;
+
+ memset(&address, 0, sizeof(address));
+ address.sun_family = AF_UNIX;
+ strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
+ err = TEMP_FAILURE_RETRY(connect(
+ amfd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)));
+ if (!err) {
+ struct timeval tv;
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = 1; // tight leash
+ err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+ if (!err) {
+ tv.tv_sec = 3; // 3 seconds on handshake read
+ err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+ }
+ }
+ if (err) {
+ close(amfd);
+ amfd = -1;
+ }
+ }
+
+ return amfd;
+}
+
+char* engrave_tombstone(
+ pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
+ bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
+ mkdir(TOMBSTONE_DIR, 0755);
+ chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM);
+
+ if (selinux_android_restorecon(TOMBSTONE_DIR) == -1) {
+ *detach_failed = false;
+ return NULL;
+ }
+
+ int fd;
+ char* path = find_and_open_tombstone(&fd);
+ if (!path) {
+ *detach_failed = false;
+ return NULL;
+ }
+
+ log_t log;
+ log.tfd = fd;
+ log.amfd = activity_manager_connect();
+ log.quiet = quiet;
+ *detach_failed = dump_crash(
+ &log, pid, tid, signal, abort_msg_address, dump_sibling_threads, total_sleep_time_usec);
+
+ close(log.amfd);
+ close(fd);
+ return path;
+}
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index d4a1a96..e9878bf 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -21,8 +21,6 @@
#include <stdbool.h>
#include <sys/types.h>
-#include <corkscrew/ptrace.h>
-
/* Creates a tombstone file and writes the crash dump to it.
* Returns the path of the tombstone, which must be freed using free(). */
char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
diff --git a/debuggerd/utility.c b/debuggerd/utility.c
deleted file mode 100644
index 41be982..0000000
--- a/debuggerd/utility.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/* system/debuggerd/utility.c
-**
-** Copyright 2008, 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 <stddef.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <log/logd.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <assert.h>
-
-#include "utility.h"
-
-const int sleep_time_usec = 50000; /* 0.05 seconds */
-const int max_total_sleep_usec = 10000000; /* 10 seconds */
-
-static int write_to_am(int fd, const char* buf, int len) {
- int to_write = len;
- while (to_write > 0) {
- int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
- if (written < 0) {
- /* hard failure */
- LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
- return -1;
- }
- to_write -= written;
- }
- return len;
-}
-
-void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) {
- char buf[512];
- bool want_tfd_write;
- bool want_log_write;
- bool want_amfd_write;
- int len = 0;
-
- va_list ap;
- va_start(ap, fmt);
-
- // where is the information going to go?
- want_tfd_write = log && log->tfd >= 0;
- want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
- want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
-
- // if we're going to need the literal string, generate it once here
- if (want_tfd_write || want_amfd_write) {
- vsnprintf(buf, sizeof(buf), fmt, ap);
- len = strlen(buf);
- }
-
- if (want_tfd_write) {
- write(log->tfd, buf, len);
- }
-
- if (want_log_write) {
- // whatever goes to logcat also goes to the Activity Manager
- __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
- if (want_amfd_write && len > 0) {
- int written = write_to_am(log->amfd, buf, len);
- if (written <= 0) {
- // timeout or other failure on write; stop informing the activity manager
- log->amfd = -1;
- }
- }
- }
- va_end(ap);
-}
-
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
- for (;;) {
- int status;
- pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
- if (n < 0) {
- if(errno == EAGAIN) continue;
- LOG("waitpid failed: %s\n", strerror(errno));
- return -1;
- } else if (n > 0) {
- XLOG("waitpid: n=%d status=%08x\n", n, status);
- if (WIFSTOPPED(status)) {
- return WSTOPSIG(status);
- } else {
- LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
- return -1;
- }
- }
-
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to die\n", tid);
- return -1;
- }
-
- /* not ready yet */
- XLOG("not ready yet\n");
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
- }
-}
-
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
- siginfo_t si;
- while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to stop\n", tid);
- break;
- }
-
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
- }
-}
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
new file mode 100644
index 0000000..35f061e
--- /dev/null
+++ b/debuggerd/utility.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2008, 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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <log/logd.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <assert.h>
+
+#include "utility.h"
+
+const int sleep_time_usec = 50000; // 0.05 seconds
+const int max_total_sleep_usec = 10000000; // 10 seconds
+
+static int write_to_am(int fd, const char* buf, int len) {
+ int to_write = len;
+ while (to_write > 0) {
+ int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
+ if (written < 0) {
+ // hard failure
+ LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
+ return -1;
+ }
+ to_write -= written;
+ }
+ return len;
+}
+
+void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
+ char buf[512];
+ bool want_tfd_write;
+ bool want_log_write;
+ bool want_amfd_write;
+ int len = 0;
+
+ va_list ap;
+ va_start(ap, fmt);
+
+ // where is the information going to go?
+ want_tfd_write = log && log->tfd >= 0;
+ want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
+ want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+
+ // if we're going to need the literal string, generate it once here
+ if (want_tfd_write || want_amfd_write) {
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ len = strlen(buf);
+ }
+
+ if (want_tfd_write) {
+ write(log->tfd, buf, len);
+ }
+
+ if (want_log_write) {
+ // whatever goes to logcat also goes to the Activity Manager
+ __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
+ if (want_amfd_write && len > 0) {
+ int written = write_to_am(log->amfd, buf, len);
+ if (written <= 0) {
+ // timeout or other failure on write; stop informing the activity manager
+ log->amfd = -1;
+ }
+ }
+ }
+ va_end(ap);
+}
+
+int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+ for (;;) {
+ int status;
+ pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
+ if (n < 0) {
+ if (errno == EAGAIN)
+ continue;
+ LOG("waitpid failed: %s\n", strerror(errno));
+ return -1;
+ } else if (n > 0) {
+ XLOG("waitpid: n=%d status=%08x\n", n, status);
+ if (WIFSTOPPED(status)) {
+ return WSTOPSIG(status);
+ } else {
+ LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
+ return -1;
+ }
+ }
+
+ if (*total_sleep_time_usec > max_total_sleep_usec) {
+ LOG("timed out waiting for tid=%d to die\n", tid);
+ return -1;
+ }
+
+ // not ready yet
+ XLOG("not ready yet\n");
+ usleep(sleep_time_usec);
+ *total_sleep_time_usec += sleep_time_usec;
+ }
+}
+
+void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
+ siginfo_t si;
+ while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
+ if (*total_sleep_time_usec > max_total_sleep_usec) {
+ LOG("timed out waiting for tid=%d to stop\n", tid);
+ break;
+ }
+
+ usleep(sleep_time_usec);
+ *total_sleep_time_usec += sleep_time_usec;
+ }
+}
diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c
deleted file mode 100644
index db44b11..0000000
--- a/debuggerd/x86/machine.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-** Copyright 2006, 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 <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/ptrace.h>
-
-#include "../utility.h"
-#include "../machine.h"
-
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
-}
-
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
- struct pt_regs r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
- return;
- }
- _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
- r.eax, r.ebx, r.ecx, r.edx);
- _LOG(log, scope_flags, " esi %08lx edi %08lx\n",
- r.esi, r.edi);
- _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
- r.xcs, r.xds, r.xes, r.xfs, r.xss);
- _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
- r.eip, r.ebp, r.esp, r.eflags);
-}
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
new file mode 100644
index 0000000..141f19a
--- /dev/null
+++ b/debuggerd/x86/machine.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006, 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 <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include "../utility.h"
+#include "../machine.h"
+
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+}
+
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+ struct pt_regs r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+ _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
+ r.eax, r.ebx, r.ecx, r.edx);
+ _LOG(log, scope_flags, " esi %08lx edi %08lx\n",
+ r.esi, r.edi);
+ _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
+ r.xcs, r.xds, r.xes, r.xfs, r.xss);
+ _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
+ r.eip, r.ebp, r.esp, r.eflags);
+}
diff --git a/fastbootd/commands.c b/fastbootd/commands.c
index d8a601f..063e1a6 100644
--- a/fastbootd/commands.c
+++ b/fastbootd/commands.c
@@ -29,6 +29,7 @@
* SUCH DAMAGE.
*/
+#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
@@ -319,7 +320,7 @@
return;
}
- D(INFO, "writing %lld bytes to '%s'\n", sz, arg);
+ D(INFO, "writing %"PRId64" bytes to '%s'\n", sz, arg);
if (flash_write(partition, phandle->download_fd, sz, header_sz)) {
fastboot_fail(phandle, "flash write failure");
diff --git a/fastbootd/commands/flash.c b/fastbootd/commands/flash.c
index 0954217..1eb4d1b 100644
--- a/fastbootd/commands/flash.c
+++ b/fastbootd/commands/flash.c
@@ -31,6 +31,7 @@
#include <sys/stat.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <sys/mman.h>
#include "flash.h"
@@ -82,7 +83,7 @@
{
int64_t size;
size = get_block_device_size(fd);
- D(DEBUG, "erase %llu data from %d\n", size, fd);
+ D(DEBUG, "erase %"PRId64" data from %d\n", size, fd);
return wipe_block_device(fd, size);
}
@@ -97,7 +98,7 @@
int current_size = MIN(size - written, BUFFER_SIZE);
if (gpt_mmap(&input, written + skip, current_size, data_fd)) {
- D(ERR, "Error in writing data, unable to map data file %d at %d size %d", size, skip, current_size);
+ D(ERR, "Error in writing data, unable to map data file %zd at %zd size %d", size, skip, current_size);
return -1;
}
if (gpt_mmap(&output, written, current_size, partition_fd)) {
diff --git a/fastbootd/commands/partitions.c b/fastbootd/commands/partitions.c
index de80ea3..74232e6 100644
--- a/fastbootd/commands/partitions.c
+++ b/fastbootd/commands/partitions.c
@@ -42,6 +42,7 @@
#include <sys/ioctl.h>
#include <stdlib.h>
#include <cutils/config_utils.h>
+#include <inttypes.h>
#include "partitions.h"
#include "debug.h"
@@ -80,7 +81,7 @@
uint64_t sz = get_file_size64(fd);
if (sz < size + location) {
- D(ERR, "the location of mapping area is outside of the device size %lld", sz);
+ D(ERR, "the location of mapping area is outside of the device size %" PRId64, sz);
return 1;
}
location = ALIGN_DOWN(location, PAGE_SIZE);
@@ -89,7 +90,7 @@
if (mapping->map_ptr == MAP_FAILED) {
mapping->ptr = MAP_FAILED;
- D(ERR, "map failed %d", (int) mapping->map_ptr);
+ D(ERR, "map failed: %s", strerror(errno));
return 1;
}
diff --git a/fastbootd/other/gptedit.c b/fastbootd/other/gptedit.c
index 16d34a5..d423529 100644
--- a/fastbootd/other/gptedit.c
+++ b/fastbootd/other/gptedit.c
@@ -29,9 +29,10 @@
* SUCH DAMAGE.
*/
+#include <getopt.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
#include <unistd.h>
#include <cutils/klog.h>
@@ -185,7 +186,7 @@
name[m] = entry->name[m] & 127;
}
name[m] = 0;
- printf("#%03d %13lld %13lld %s\n",
+ printf("#%03d %13"PRId64" %13"PRId64" %s\n",
n + 1, entry->first_lba, entry->last_lba, name);
}
}
@@ -197,11 +198,11 @@
char temp_guid[17];
temp_guid[16] = 0;
- printf("header_lba %lld\n", table->header->current_lba);
- printf("backup_lba %lld\n", table->header->backup_lba);
- printf("first_lba %lld\n", table->header->first_usable_lba);
- printf("last_lba %lld\n", table->header->last_usable_lba);
- printf("entries_lba %lld\n", table->header->entries_lba);
+ printf("header_lba %"PRId64"\n", table->header->current_lba);
+ printf("backup_lba %"PRId64"\n", table->header->backup_lba);
+ printf("first_lba %"PRId64"\n", table->header->first_usable_lba);
+ printf("last_lba %"PRId64"\n", table->header->last_usable_lba);
+ printf("entries_lba %"PRId64"\n", table->header->entries_lba);
snprintf(temp_guid, 17, "%s", table->header->disk_guid);
printf("guid \"%s\"", temp_guid);
@@ -220,8 +221,8 @@
printf(" %s {\n", name);
snprintf(temp_guid, 17, "%s", entry->partition_guid);
printf(" guid \"%s\"\n", temp_guid);
- printf(" first_lba %lld\n", entry->first_lba);
- printf(" partition_size %lld\n", size);
+ printf(" first_lba %"PRId64"\n", entry->first_lba);
+ printf(" partition_size %"PRId64"\n", size);
if (entry->flags & GPT_FLAG_SYSTEM)
printf(" system\n");
if (entry->flags & GPT_FLAG_BOOTABLE)
diff --git a/fastbootd/secure.c b/fastbootd/secure.c
index a657ad4..186e026 100644
--- a/fastbootd/secure.c
+++ b/fastbootd/secure.c
@@ -151,7 +151,7 @@
char buf[256];
unsigned long err = ERR_peek_last_error();
D(ERR, "Verification failed with reason: %s, %s", ERR_lib_error_string(err), ERR_error_string(err, buf));
- D(ERR, "Data used: content %d", (int) content);
+ D(ERR, "Data used: content %p", content);
}
ERR_clear_error();
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
index 19a705c..ce8f9d0 100644
--- a/fastbootd/transport.c
+++ b/fastbootd/transport.c
@@ -56,14 +56,14 @@
buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (buffer == NULL) {
- D(ERR, "mmap(%u) failed: %d %s", len, errno, strerror(errno));
+ D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno));
goto err;
}
while (n < len) {
ret = thandle->transport->read(thandle, buffer + n, len - n);
if (ret <= 0) {
- D(WARN, "transport read failed, ret=%d %s", ret, strerror(-ret));
+ D(WARN, "transport read failed, ret=%zd %s", ret, strerror(-ret));
break;
}
n += ret;
diff --git a/fastbootd/transport_socket.c b/fastbootd/transport_socket.c
index ff0f3bd..664d473 100644
--- a/fastbootd/transport_socket.c
+++ b/fastbootd/transport_socket.c
@@ -88,7 +88,7 @@
ssize_t ret;
struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
- D(DEBUG, "about to write (fd=%d, len=%d)", handle->fd, len);
+ D(DEBUG, "about to write (fd=%d, len=%zu)", handle->fd, len);
ret = bulk_write(handle->fd, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
@@ -103,7 +103,7 @@
ssize_t ret;
struct socket_handle *handle = container_of(thandle, struct socket_handle, handle);
- D(DEBUG, "about to read (fd=%d, len=%d)", handle->fd, len);
+ D(DEBUG, "about to read (fd=%d, len=%zu)", handle->fd, len);
ret = bulk_read(handle->fd, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", handle->fd, ret);
diff --git a/fastbootd/usb_linux_client.c b/fastbootd/usb_linux_client.c
index 7a8e46f..64420e9 100644
--- a/fastbootd/usb_linux_client.c
+++ b/fastbootd/usb_linux_client.c
@@ -217,7 +217,7 @@
struct transport *t = thandle->transport;
struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
- D(DEBUG, "about to write (fd=%d, len=%d)", usb_transport->bulk_in, len);
+ D(DEBUG, "about to write (fd=%d, len=%zu)", usb_transport->bulk_in, len);
ret = bulk_write(usb_transport->bulk_in, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_in, ret);
@@ -233,7 +233,7 @@
struct transport *t = thandle->transport;
struct usb_transport *usb_transport = container_of(t, struct usb_transport, transport);
- D(DEBUG, "about to read (fd=%d, len=%d)", usb_transport->bulk_out, len);
+ D(DEBUG, "about to read (fd=%d, len=%zu)", usb_transport->bulk_out, len);
ret = bulk_read(usb_transport->bulk_out, data, len);
if (ret < 0) {
D(ERR, "ERROR: fd = %d, ret = %zd", usb_transport->bulk_out, ret);
diff --git a/fastbootd/utils.c b/fastbootd/utils.c
index fe3f0f8..bef2463 100644
--- a/fastbootd/utils.c
+++ b/fastbootd/utils.c
@@ -169,7 +169,7 @@
do {
ret = TEMP_FAILURE_RETRY(write(bulk_in, buf + count, length - count));
if (ret < 0) {
- D(WARN, "[ bulk_write failed fd=%d length=%d errno=%d %s ]",
+ D(WARN, "[ bulk_write failed fd=%d length=%zu errno=%d %s ]",
bulk_in, length, errno, strerror(errno));
return -1;
} else {
@@ -190,13 +190,13 @@
size_t to_read = (length - n > READ_BUF_SIZE) ? READ_BUF_SIZE : length - n;
ret = TEMP_FAILURE_RETRY(read(bulk_out, buf + n, to_read));
if (ret < 0) {
- D(WARN, "[ bulk_read failed fd=%d length=%d errno=%d %s ]",
+ D(WARN, "[ bulk_read failed fd=%d length=%zu errno=%d %s ]",
bulk_out, length, errno, strerror(errno));
return ret;
}
n += ret;
if (ret < (ssize_t)to_read) {
- D(VERBOSE, "bulk_read short read, ret=%zd to_read=%u n=%u length=%u",
+ D(VERBOSE, "bulk_read short read, ret=%zd to_read=%zu n=%zu length=%zu",
ret, to_read, n, length);
break;
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 13b71ee..24ce806 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -28,11 +28,6 @@
#include <libgen.h>
#include <time.h>
#include <sys/swap.h>
-/* XXX These need to be obtained from kernel headers. See b/9336527 */
-#define SWAP_FLAG_PREFER 0x8000
-#define SWAP_FLAG_PRIO_MASK 0x7fff
-#define SWAP_FLAG_PRIO_SHIFT 0
-#define SWAP_FLAG_DISCARD 0x10000
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
@@ -522,6 +517,7 @@
int encrypted = 0;
int ret = -1;
int mret;
+ int mount_errno;
if (!fstab) {
return ret;
@@ -565,6 +561,9 @@
continue;
}
+ /* back up errno as partition_wipe clobbers the value */
+ mount_errno = errno;
+
/* mount(2) returned an error, check if it's encrypted and deal with it */
if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
!partition_wiped(fstab->recs[i].blk_device)) {
@@ -573,14 +572,16 @@
*/
if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
- ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
- fstab->recs[i].mount_point);
+ ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
+ fstab->recs[i].mount_point, strerror(errno));
goto out;
}
encrypted = 1;
} else {
- ERROR("Cannot mount filesystem on %s at %s\n",
- fstab->recs[i].blk_device, fstab->recs[i].mount_point);
+ ERROR("Failed to mount an un-encryptable or wiped partition on"
+ "%s at %s options: %s error: %s\n",
+ fstab->recs[i].blk_device, fstab->recs[i].mount_point,
+ fstab->recs[i].fs_options, strerror(mount_errno));
goto out;
}
}
@@ -649,8 +650,8 @@
}
if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
- ERROR("Cannot mount filesystem on %s at %s\n",
- n_blk_device, m);
+ ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
+ n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
goto out;
} else {
ret = 0;
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 969eab2..1549316 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -178,7 +179,7 @@
goto out;
}
if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
- ERROR("Couldn't find verity metadata at offset %llu!\n", device_length);
+ ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_length);
goto out;
}
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index b15678c..f0fb0cd 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -17,10 +17,25 @@
#ifndef _BACKTRACE_BACKTRACE_H
#define _BACKTRACE_BACKTRACE_H
-#include <backtrace/backtrace.h>
+#include <stdint.h>
#include <string>
+#include <vector>
+#include <backtrace/backtrace_constants.h>
+#include <backtrace/BacktraceMap.h>
+
+struct backtrace_frame_data_t {
+ size_t num; // The current fame number.
+ uintptr_t pc; // The absolute pc.
+ uintptr_t sp; // The top of the stack.
+ size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
+ const backtrace_map_t* map; // The map associated with the given pc.
+ std::string func_name; // The function name associated with this pc, NULL if not found.
+ uintptr_t func_offset; // pc relative to the start of the function, only valid if func_name is not NULL.
+};
+
+// Forward declarations.
class BacktraceImpl;
class Backtrace {
@@ -33,7 +48,9 @@
// If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
// different process.
// Tracing a thread in a different process is not supported.
- static Backtrace* Create(pid_t pid, pid_t tid);
+ // If map is NULL, then create the map and manage it internally.
+ // If map is not NULL, the map is still owned by the caller.
+ static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);
virtual ~Backtrace();
@@ -44,13 +61,12 @@
// If the string is empty, then no valid function name was found.
virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
- // Get the name of the map associated with the given pc. If NULL is returned,
- // then map_start is not set. Otherwise, map_start is the beginning of this
- // map.
- virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start);
+ // Find the map associated with the given pc.
+ virtual const backtrace_map_t* FindMap(uintptr_t pc);
- // Finds the memory map associated with the given ptr.
- virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);
+ // Take ownership of the BacktraceMap object associated with the backtrace.
+ // If this is called, the caller must handle deleting the object themselves.
+ virtual BacktraceMap* TakeMapOwnership();
// Read the data at a specific address.
virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
@@ -58,28 +74,46 @@
// Create a string representing the formatted line of backtrace information
// for a single frame.
virtual std::string FormatFrameData(size_t frame_num);
+ virtual std::string FormatFrameData(const backtrace_frame_data_t* frame);
- pid_t Pid() { return backtrace_.pid; }
- pid_t Tid() { return backtrace_.tid; }
- size_t NumFrames() { return backtrace_.num_frames; }
-
- const backtrace_t* GetBacktrace() { return &backtrace_; }
+ pid_t Pid() { return pid_; }
+ pid_t Tid() { return tid_; }
+ size_t NumFrames() { return frames_.size(); }
const backtrace_frame_data_t* GetFrame(size_t frame_num) {
- return &backtrace_.frames[frame_num];
+ if (frame_num >= frames_.size()) {
+ return NULL;
+ }
+ return &frames_[frame_num];
}
+ typedef std::vector<backtrace_frame_data_t>::iterator iterator;
+ iterator begin() { return frames_.begin(); }
+ iterator end() { return frames_.end(); }
+
+ typedef std::vector<backtrace_frame_data_t>::const_iterator const_iterator;
+ const_iterator begin() const { return frames_.begin(); }
+ const_iterator end() const { return frames_.end(); }
+
+ BacktraceMap* GetMap() { return map_; }
+
protected:
- Backtrace(BacktraceImpl* impl);
+ Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+ bool BuildMap();
+
+ pid_t pid_;
+ pid_t tid_;
+
+ BacktraceMap* map_;
+ bool map_shared_;
+
+ std::vector<backtrace_frame_data_t> frames_;
+
BacktraceImpl* impl_;
- backtrace_map_info_t* map_info_;
-
- backtrace_t backtrace_;
-
friend class BacktraceImpl;
};
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
new file mode 100644
index 0000000..a53293a
--- /dev/null
+++ b/include/backtrace/BacktraceMap.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2014 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 _BACKTRACE_BACKTRACE_MAP_H
+#define _BACKTRACE_BACKTRACE_MAP_H
+
+#include <stdint.h>
+#ifdef USE_MINGW
+// MINGW does not define these constants.
+#define PROT_NONE 0
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+#else
+#include <sys/mman.h>
+#endif
+
+#include <string>
+#include <vector>
+
+struct backtrace_map_t {
+ uintptr_t start;
+ uintptr_t end;
+ int flags;
+ std::string name;
+};
+
+class BacktraceMap {
+public:
+ BacktraceMap(pid_t pid);
+ virtual ~BacktraceMap();
+
+ // Get the map data structure for the given address.
+ const backtrace_map_t* Find(uintptr_t addr);
+
+ // The flags returned are the same flags as used by the mmap call.
+ // The values are PROT_*.
+ int GetFlags(uintptr_t pc) {
+ const backtrace_map_t* map = Find(pc);
+ if (map) {
+ return map->flags;
+ }
+ return PROT_NONE;
+ }
+
+ bool IsReadable(uintptr_t pc) { return GetFlags(pc) & PROT_READ; }
+ bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
+ bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
+
+ typedef std::vector<backtrace_map_t>::iterator iterator;
+ iterator begin() { return maps_.begin(); }
+ iterator end() { return maps_.end(); }
+
+ typedef std::vector<backtrace_map_t>::const_iterator const_iterator;
+ const_iterator begin() const { return maps_.begin(); }
+ const_iterator end() const { return maps_.end(); }
+
+ virtual bool Build();
+
+protected:
+ virtual bool ParseLine(const char* line, backtrace_map_t* map);
+
+ std::vector<backtrace_map_t> maps_;
+ pid_t pid_;
+};
+
+#endif // _BACKTRACE_BACKTRACE_MAP_H
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
deleted file mode 100644
index 8a45690..0000000
--- a/include/backtrace/backtrace.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2013 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 _BACKTRACE_H
-#define _BACKTRACE_H
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <sys/types.h>
-
-__BEGIN_DECLS
-
-// When the pid to be traced is set to this value, then trace the current
-// process. If the tid value is not BACKTRACE_NO_TID, then the specified
-// thread from the current process will be traced.
-#define BACKTRACE_CURRENT_PROCESS -1
-// When the tid to be traced is set to this value, then trace the specified
-// pid.
-#define BACKTRACE_NO_TID -1
-
-#define MAX_BACKTRACE_FRAMES 64
-
-typedef struct backtrace_map_info {
- struct backtrace_map_info* next;
- uintptr_t start;
- uintptr_t end;
- bool is_readable;
- bool is_writable;
- bool is_executable;
- char name[];
-} backtrace_map_info_t;
-
-typedef struct {
- uintptr_t pc; /* The absolute pc. */
- uintptr_t sp; /* The top of the stack. */
- size_t stack_size; /* The size of the stack, zero indicate an unknown stack size. */
- const char* map_name; /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */
- uintptr_t map_offset; /* pc relative to the start of the map, only valid if map_name is not NULL. */
- char* func_name; /* The function name associated with this pc, NULL if not found. */
- uintptr_t func_offset; /* pc relative to the start of the function, only valid if func_name is not NULL. */
-} backtrace_frame_data_t;
-
-typedef struct {
- backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
- size_t num_frames;
-
- pid_t pid;
- pid_t tid;
- backtrace_map_info_t* map_info_list;
-} backtrace_t;
-
-typedef struct {
- void* data;
- const backtrace_t* backtrace;
-} backtrace_context_t;
-
-/* Create a context for the backtrace data and gather the backtrace.
- * If pid < 0, then gather the backtrace for the current process.
- */
-bool backtrace_create_context(
- backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);
-
-/* Gather the backtrace data for a pthread instead of a process. */
-bool backtrace_create_thread_context(
- backtrace_context_t* context, pid_t tid, size_t num_ignore_frames);
-
-/* Free any memory allocated during the context create. */
-void backtrace_destroy_context(backtrace_context_t* context);
-
-/* Read data at a specific address for a process. */
-bool backtrace_read_word(
- const backtrace_context_t* context, uintptr_t ptr, uint32_t* value);
-
-/* Get information about the map name associated with a pc. If NULL is
- * returned, then map_start is not set.
- */
-const char* backtrace_get_map_name(
- const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);
-
-/* Get the function name and offset given the pc. If NULL is returned,
- * then func_offset is not set. The returned string is allocated using
- * malloc and must be freed by the caller.
- */
-char* backtrace_get_func_name(
- const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);
-
-/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory
- * map for the current process.
- */
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid);
-
-/* Frees memory associated with the map list. */
-void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
-
-/* Finds the memory map that contains the specified pc. */
-const backtrace_map_info_t* backtrace_find_map_info(
- const backtrace_map_info_t* map_info_list, uintptr_t pc);
-
-/* Create a formatted line of backtrace information for a single frame. */
-void backtrace_format_frame_data(
- const backtrace_context_t* context, size_t frame_num, char* buf,
- size_t buf_size);
-
-/* Get the backtrace data structure associated with the context. */
-const backtrace_t* backtrace_get_data(backtrace_context_t* context);
-
-__END_DECLS
-
-#endif /* _BACKTRACE_H */
diff --git a/include/backtrace/backtrace_constants.h b/include/backtrace/backtrace_constants.h
new file mode 100644
index 0000000..f8c1575
--- /dev/null
+++ b/include/backtrace/backtrace_constants.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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 _BACKTRACE_BACKTRACE_CONSTANTS_H
+#define _BACKTRACE_BACKTRACE_CONSTANTS_H
+
+// When the pid to be traced is set to this value, then trace the current
+// process. If the tid value is not BACKTRACE_NO_TID, then the specified
+// thread from the current process will be traced.
+#define BACKTRACE_CURRENT_PROCESS -1
+// When the tid to be traced is set to this value, then trace the specified
+// current thread of the specified pid.
+#define BACKTRACE_CURRENT_THREAD -1
+
+#define MAX_BACKTRACE_FRAMES 64
+
+#endif // _BACKTRACE_BACKTRACE_CONSTANTS_H
diff --git a/include/cutils/atomic-arm64.h b/include/cutils/atomic-arm64.h
new file mode 100644
index 0000000..4562ad0
--- /dev/null
+++ b/include/cutils/atomic-arm64.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_CUTILS_ATOMIC_AARCH64_H
+#define ANDROID_CUTILS_ATOMIC_AARCH64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+/*
+ TODOAArch64: Revisit the below functions and check for potential
+ optimizations using assembly code or otherwise.
+*/
+
+extern ANDROID_ATOMIC_INLINE
+void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern ANDROID_ATOMIC_INLINE
+void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("dmb ish" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE
+void android_memory_store_barrier(void)
+{
+ __asm__ __volatile__ ("dmb ishst" : : : "memory");
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+ int64_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int status = android_atomic_cas(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ int status = android_atomic_cas64(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value, int32_t new_value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev + increment, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev & value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ prev = *ptr;
+ status = android_atomic_cas(prev, prev | value, ptr);
+ } while (__builtin_expect(status != 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_AARCH64_H */
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 0b13138..ae79e00 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -43,7 +43,9 @@
# error "Must define ANDROID_SMP before including atomic-inline.h"
#endif
-#if defined(__arm__)
+#if defined(__aarch64__)
+#include <cutils/atomic-arm64.h>
+#elif defined(__arm__)
#include <cutils/atomic-arm.h>
#elif defined(__i386__) || defined(__x86_64__)
#include <cutils/atomic-x86.h>
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index ae42eb8..1787e34 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -80,6 +80,11 @@
int32_t android_atomic_acquire_load(volatile const int32_t* addr);
int32_t android_atomic_release_load(volatile const int32_t* addr);
+#if defined (__LP64__)
+int64_t android_atomic_acquire_load64(volatile const int64_t* addr);
+int64_t android_atomic_release_load64(volatile const int64_t* addr);
+#endif
+
/*
* Perform an atomic store with "acquire" or "release" ordering.
*
@@ -89,6 +94,11 @@
void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
void android_atomic_release_store(int32_t value, volatile int32_t* addr);
+#if defined (__LP64__)
+void android_atomic_acquire_store64(int64_t value, volatile int64_t* addr);
+void android_atomic_release_store64(int64_t value, volatile int64_t* addr);
+#endif
+
/*
* Compare-and-set operation with "acquire" or "release" ordering.
*
@@ -106,6 +116,13 @@
int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
volatile int32_t* addr);
+#if defined (__LP64__)
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr);
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr);
+#endif
+
/*
* Aliases for code using an older version of this header. These are now
* deprecated and should not be used. The definitions will be removed
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
index 2056751..27e89f4 100644
--- a/include/utils/CallStack.h
+++ b/include/utils/CallStack.h
@@ -18,8 +18,9 @@
#define ANDROID_CALLSTACK_H
#include <android/log.h>
+#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
-#include <corkscrew/backtrace.h>
+#include <utils/Vector.h>
#include <stdint.h>
#include <sys/types.h>
@@ -31,42 +32,19 @@
// Collect/print the call stack (function, file, line) traces for a single thread.
class CallStack {
public:
- enum {
- // Prune the lowest-most stack frames until we have at most MAX_DEPTH.
- MAX_DEPTH = 31,
- // Placeholder for specifying the current thread when updating the stack.
- CURRENT_THREAD = -1,
- };
-
// Create an empty call stack. No-op.
CallStack();
// Create a callstack with the current thread's stack trace.
// Immediately dump it to logcat using the given logtag.
- CallStack(const char* logtag, int32_t ignoreDepth=1,
- int32_t maxDepth=MAX_DEPTH);
- // Copy the existing callstack (no other side effects).
- CallStack(const CallStack& rhs);
+ CallStack(const char* logtag, int32_t ignoreDepth=1);
~CallStack();
- // Copy the existing callstack (no other side effects).
- CallStack& operator = (const CallStack& rhs);
-
- // Compare call stacks by their backtrace frame memory.
- bool operator == (const CallStack& rhs) const;
- bool operator != (const CallStack& rhs) const;
- bool operator < (const CallStack& rhs) const;
- bool operator >= (const CallStack& rhs) const;
- bool operator > (const CallStack& rhs) const;
- bool operator <= (const CallStack& rhs) const;
-
- // Get the PC address for the stack frame specified by index.
- const void* operator [] (int index) const;
-
// Reset the stack frames (same as creating an empty call stack).
- void clear();
+ void clear() { mFrameLines.clear(); }
// Immediately collect the stack traces for the specified thread.
- void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH, pid_t tid=CURRENT_THREAD);
+ // The default is to dump the stack of the current call.
+ void update(int32_t ignoreDepth=1, pid_t tid=BACKTRACE_CURRENT_THREAD);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
@@ -83,11 +61,10 @@
void print(Printer& printer) const;
// Get the count of stack frames that are in this call stack.
- size_t size() const { return mCount; }
+ size_t size() const { return mFrameLines.size(); }
private:
- size_t mCount;
- backtrace_frame_t mStack[MAX_DEPTH];
+ Vector<String8> mFrameLines;
};
}; // namespace android
diff --git a/include/utils/ProcessCallStack.h b/include/utils/ProcessCallStack.h
index 4a86869..32458b8 100644
--- a/include/utils/ProcessCallStack.h
+++ b/include/utils/ProcessCallStack.h
@@ -39,7 +39,7 @@
~ProcessCallStack();
// Immediately collect the stack traces for all threads.
- void update(int32_t maxDepth = CallStack::MAX_DEPTH);
+ void update();
// Print all stack traces to the log using the supplied logtag.
void log(const char* logtag, android_LogPriority priority = ANDROID_LOG_DEBUG,
diff --git a/init/init.c b/init/init.c
index ab52749..4266a73 100644
--- a/init/init.c
+++ b/init/init.c
@@ -623,7 +623,7 @@
total_bytes_written += chunk_size;
}
- INFO("Mixed %d bytes from /dev/hw_random into /dev/urandom",
+ INFO("Mixed %zu bytes from /dev/hw_random into /dev/urandom",
total_bytes_written);
result = 0;
diff --git a/init/property_service.c b/init/property_service.c
index c370769..ac63377e 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -168,7 +168,7 @@
if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0)
goto err;
- if (selinux_check_access(sctx, tctx, class, perm, name) == 0)
+ if (selinux_check_access(sctx, tctx, class, perm, (void*) name) == 0)
result = 1;
freecon(tctx);
@@ -382,7 +382,7 @@
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
+ ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
r, sizeof(prop_msg), errno);
close(s);
return;
@@ -522,7 +522,7 @@
|| (sb.st_uid != 0)
|| (sb.st_gid != 0)
|| (sb.st_nlink != 1)) {
- ERROR("skipping insecure property file %s (uid=%lu gid=%lu nlink=%d mode=%o)\n",
+ ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n",
entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
close(fd);
continue;
diff --git a/init/util.c b/init/util.c
index 9aaa77d..5efd5be 100644
--- a/init/util.c
+++ b/init/util.c
@@ -524,31 +524,50 @@
return rc;
}
-int restorecon(const char *pathname)
+static int restorecon_sb(const char *pathname, const struct stat *sb)
{
char *secontext = NULL;
- struct stat sb;
+ char *oldsecontext = NULL;
int i;
+ if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
+ return -errno;
+
+ if (lgetfilecon(pathname, &oldsecontext) < 0) {
+ freecon(secontext);
+ return -errno;
+ }
+
+ if (strcmp(oldsecontext, secontext) != 0) {
+ if (lsetfilecon(pathname, secontext) < 0) {
+ freecon(oldsecontext);
+ freecon(secontext);
+ return -errno;
+ }
+ }
+ freecon(oldsecontext);
+ freecon(secontext);
+ return 0;
+}
+
+int restorecon(const char *pathname)
+{
+ struct stat sb;
+
if (is_selinux_enabled() <= 0 || !sehandle)
return 0;
if (lstat(pathname, &sb) < 0)
return -errno;
- if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)
- return -errno;
- if (lsetfilecon(pathname, secontext) < 0) {
- freecon(secontext);
- return -errno;
- }
- freecon(secontext);
- return 0;
+
+ return restorecon_sb(pathname, &sb);
}
static int nftw_restorecon(const char* filename, const struct stat* statptr,
- int fileflags, struct FTW* pftw)
+ int fileflags __attribute__((unused)),
+ struct FTW* pftw __attribute__((unused)))
{
- restorecon(filename);
+ restorecon_sb(filename, statptr);
return 0;
}
@@ -556,5 +575,9 @@
{
int fd_limit = 20;
int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
+
+ if (is_selinux_enabled() <= 0 || !sehandle)
+ return 0;
+
return nftw(pathname, nftw_restorecon, fd_limit, flags);
}
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index a6b9c2b..f23eefd 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -2,8 +2,8 @@
common_src := \
Backtrace.cpp \
+ BacktraceMap.cpp \
BacktraceThread.cpp \
- map_info.c \
thread_utils.c \
common_cflags := \
@@ -23,8 +23,7 @@
liblog \
# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures :=
-#libunwind_architectures := arm
+libunwind_architectures := arm64
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
@@ -148,6 +147,11 @@
-DGTEST_OS_LINUX_ANDROID \
-DGTEST_HAS_STD_STRING \
+ifeq ($(TARGET_ARCH),arm64)
+ $(info TODO: $(LOCAL_PATH)/Android.mk -fstack-protector not yet available for the AArch64 toolchain)
+ LOCAL_CFLAGS += -fno-stack-protector
+endif # arm64
+
LOCAL_CONLYFLAGS += \
$(common_conlyflags) \
@@ -168,18 +172,15 @@
include $(BUILD_NATIVE_TEST)
#----------------------------------------------------------------------------
-# Only linux-x86 host versions of libbacktrace supported.
+# Only x86 host versions of libbacktrace supported.
#----------------------------------------------------------------------------
-ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+ifeq ($(HOST_ARCH),x86)
#----------------------------------------------------------------------------
# The host libbacktrace library using libcorkscrew
#----------------------------------------------------------------------------
include $(CLEAR_VARS)
-LOCAL_SRC_FILES += \
- $(common_src) \
- Corkscrew.cpp \
LOCAL_CFLAGS += \
$(common_cflags) \
@@ -187,21 +188,12 @@
LOCAL_CONLYFLAGS += \
$(common_conlyflags) \
-LOCAL_CPPFLAGS += \
- $(common_cppflags) \
-
LOCAL_C_INCLUDES := \
$(common_c_includes) \
- system/core/libcorkscrew \
LOCAL_SHARED_LIBRARIES := \
libgccdemangle \
liblog \
- libcorkscrew \
-
-LOCAL_LDLIBS += \
- -ldl \
- -lrt \
LOCAL_MODULE := libbacktrace
LOCAL_MODULE_TAGS := optional
@@ -209,9 +201,38 @@
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(LOCAL_PATH)/Android.mk
+ifeq ($(HOST_OS),linux)
+LOCAL_SRC_FILES += \
+ $(common_src) \
+ Corkscrew.cpp \
+
+LOCAL_C_INCLUDES += \
+ system/core/libcorkscrew \
+
+LOCAL_SHARED_LIBRARIES := \
+ libcorkscrew \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+
+LOCAL_LDLIBS += \
+ -ldl \
+ -lrt \
+
+else
+LOCAL_SRC_FILES += \
+ BacktraceMap.cpp \
+
+endif
+
include $(BUILD_HOST_SHARED_LIBRARY)
#----------------------------------------------------------------------------
+# The host test is only supported on linux.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS),linux)
+
+#----------------------------------------------------------------------------
# libbacktrace host test library, all optimizations turned off
#----------------------------------------------------------------------------
include $(CLEAR_VARS)
@@ -263,4 +284,6 @@
include $(BUILD_HOST_NATIVE_TEST)
-endif # HOST_OS-HOST_ARCH == linux-x86
+endif # HOST_OS == linux
+
+endif # HOST_ARCH == x86
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index b22d301..d7b40ab 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,39 +27,28 @@
#include <string>
#include <backtrace/Backtrace.h>
-#include <cutils/log.h>
+#include <backtrace/BacktraceMap.h>
#include "Backtrace.h"
#include "thread_utils.h"
//-------------------------------------------------------------------------
-// BacktraceImpl functions.
-//-------------------------------------------------------------------------
-backtrace_t* BacktraceImpl::GetBacktraceData() {
- return &backtrace_obj_->backtrace_;
-}
-
-//-------------------------------------------------------------------------
// Backtrace functions.
//-------------------------------------------------------------------------
-Backtrace::Backtrace(BacktraceImpl* impl) : impl_(impl), map_info_(NULL) {
+Backtrace::Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map)
+ : pid_(pid), tid_(-1), map_(map), map_shared_(true), impl_(impl) {
impl_->SetParent(this);
- backtrace_.num_frames = 0;
- backtrace_.pid = -1;
- backtrace_.tid = -1;
+
+ if (map_ == NULL) {
+ // The map will be created when needed.
+ map_shared_ = false;
+ }
}
Backtrace::~Backtrace() {
- for (size_t i = 0; i < NumFrames(); i++) {
- if (backtrace_.frames[i].func_name) {
- free(backtrace_.frames[i].func_name);
- backtrace_.frames[i].func_name = NULL;
- }
- }
-
- if (map_info_) {
- backtrace_destroy_map_info_list(map_info_);
- map_info_ = NULL;
+ if (map_ && !map_shared_) {
+ delete map_;
+ map_ = NULL;
}
if (impl_) {
@@ -80,7 +69,7 @@
if (!func_name.empty()) {
#if defined(__APPLE__)
// Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
- if (symbol_name[0] != '_') {
+ if (func_name[0] != '_') {
return func_name;
}
#endif
@@ -102,59 +91,73 @@
return true;
}
-const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) {
- const backtrace_map_info_t* map_info = FindMapInfo(pc);
- if (map_info) {
- if (map_start) {
- *map_start = map_info->start;
- }
- return map_info->name;
- }
- return NULL;
-}
-
-const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) {
- return backtrace_find_map_info(map_info_, ptr);
-}
-
std::string Backtrace::FormatFrameData(size_t frame_num) {
- backtrace_frame_data_t* frame = &backtrace_.frames[frame_num];
+ if (frame_num >= frames_.size()) {
+ return "";
+ }
+ return FormatFrameData(&frames_[frame_num]);
+}
+
+std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
const char* map_name;
- if (frame->map_name) {
- map_name = frame->map_name;
+ if (frame->map && !frame->map->name.empty()) {
+ map_name = frame->map->name.c_str();
} else {
map_name = "<unknown>";
}
+
uintptr_t relative_pc;
- if (frame->map_offset) {
- relative_pc = frame->map_offset;
+ if (frame->map) {
+ relative_pc = frame->pc - frame->map->start;
} else {
relative_pc = frame->pc;
}
char buf[512];
- if (frame->func_name && frame->func_offset) {
+ if (!frame->func_name.empty() && frame->func_offset) {
snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
- frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
- frame->func_name, frame->func_offset);
- } else if (frame->func_name) {
- snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num,
- (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name);
+ frame->num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+ frame->func_name.c_str(), frame->func_offset);
+ } else if (!frame->func_name.empty()) {
+ snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame->num,
+ (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name.c_str());
} else {
- snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame_num,
+ snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame->num,
(int)sizeof(uintptr_t)*2, relative_pc, map_name);
}
return buf;
}
+bool Backtrace::BuildMap() {
+ map_ = impl_->CreateBacktraceMap(pid_);
+ if (!map_->Build()) {
+ BACK_LOGW("Failed to build map for process %d", pid_);
+ return false;
+ }
+ return true;
+}
+
+const backtrace_map_t* Backtrace::FindMap(uintptr_t pc) {
+ if (map_ == NULL) {
+ // Lazy eval, time to build the map.
+ if (!BuildMap()) {
+ return NULL;
+ }
+ }
+ return map_->Find(pc);
+}
+
+BacktraceMap* Backtrace::TakeMapOwnership() {
+ map_shared_ = true;
+ return map_;
+}
+
//-------------------------------------------------------------------------
// BacktraceCurrent functions.
//-------------------------------------------------------------------------
-BacktraceCurrent::BacktraceCurrent(BacktraceImpl* impl) : Backtrace(impl) {
- map_info_ = backtrace_create_map_info_list(-1);
-
- backtrace_.pid = getpid();
+BacktraceCurrent::BacktraceCurrent(
+ BacktraceImpl* impl, BacktraceMap* map) : Backtrace(impl, getpid(), map) {
}
BacktraceCurrent::~BacktraceCurrent() {
@@ -165,8 +168,8 @@
return false;
}
- const backtrace_map_info_t* map_info = FindMapInfo(ptr);
- if (map_info && map_info->is_readable) {
+ const backtrace_map_t* map = FindMap(ptr);
+ if (map && map->flags & PROT_READ) {
*out_value = *reinterpret_cast<uint32_t*>(ptr);
return true;
} else {
@@ -179,12 +182,10 @@
//-------------------------------------------------------------------------
// BacktracePtrace functions.
//-------------------------------------------------------------------------
-BacktracePtrace::BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid)
- : Backtrace(impl) {
- map_info_ = backtrace_create_map_info_list(tid);
-
- backtrace_.pid = pid;
- backtrace_.tid = tid;
+BacktracePtrace::BacktracePtrace(
+ BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map)
+ : Backtrace(impl, pid, map) {
+ tid_ = tid;
}
BacktracePtrace::~BacktracePtrace() {
@@ -212,96 +213,16 @@
#endif
}
-Backtrace* Backtrace::Create(pid_t pid, pid_t tid) {
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
if (pid == BACKTRACE_CURRENT_PROCESS || pid == getpid()) {
- if (tid == BACKTRACE_NO_TID || tid == gettid()) {
- return CreateCurrentObj();
+ if (tid == BACKTRACE_CURRENT_THREAD || tid == gettid()) {
+ return CreateCurrentObj(map);
} else {
- return CreateThreadObj(tid);
+ return CreateThreadObj(tid, map);
}
- } else if (tid == BACKTRACE_NO_TID) {
- return CreatePtraceObj(pid, pid);
+ } else if (tid == BACKTRACE_CURRENT_THREAD) {
+ return CreatePtraceObj(pid, pid, map);
} else {
- return CreatePtraceObj(pid, tid);
- }
-}
-
-//-------------------------------------------------------------------------
-// Common interface functions.
-//-------------------------------------------------------------------------
-bool backtrace_create_context(
- backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) {
- Backtrace* backtrace = Backtrace::Create(pid, tid);
- if (!backtrace) {
- return false;
- }
- if (!backtrace->Unwind(num_ignore_frames)) {
- delete backtrace;
- return false;
- }
-
- context->data = backtrace;
- context->backtrace = backtrace->GetBacktrace();
- return true;
-}
-
-void backtrace_destroy_context(backtrace_context_t* context) {
- if (context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- delete backtrace;
- context->data = NULL;
- }
- context->backtrace = NULL;
-}
-
-const backtrace_t* backtrace_get_data(backtrace_context_t* context) {
- if (context && context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- return backtrace->GetBacktrace();
- }
- return NULL;
-}
-
-bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) {
- if (context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- return backtrace->ReadWord(ptr, value);
- }
- return true;
-}
-
-const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) {
- if (context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- return backtrace->GetMapName(pc, map_start);
- }
- return NULL;
-}
-
-char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) {
- if (context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- std::string func_name = backtrace->GetFunctionName(pc, func_offset);
- if (!func_name.empty()) {
- return strdup(func_name.c_str());
- }
- }
- return NULL;
-}
-
-void backtrace_format_frame_data(
- const backtrace_context_t* context, size_t frame_num, char* buf,
- size_t buf_size) {
- if (buf_size == 0 || buf == NULL) {
- BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size);
- } else if (context->data) {
- Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
- std::string line = backtrace->FormatFrameData(frame_num);
- if (line.size() > buf_size) {
- memcpy(buf, line.c_str(), buf_size-1);
- buf[buf_size] = '\0';
- } else {
- memcpy(buf, line.c_str(), line.size()+1);
- }
+ return CreatePtraceObj(pid, tid, map);
}
}
diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h
index 00f0a10..31fcaf2 100644
--- a/libbacktrace/Backtrace.h
+++ b/libbacktrace/Backtrace.h
@@ -18,8 +18,10 @@
#define _LIBBACKTRACE_BACKTRACE_H
#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
#include <sys/types.h>
+#include <log/log.h>
// Macro to log the function name along with the warning message.
#define BACK_LOGW(format, ...) \
@@ -37,15 +39,19 @@
void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
+ virtual BacktraceMap* CreateBacktraceMap(pid_t pid) = 0;
+
protected:
- backtrace_t* GetBacktraceData();
+ inline std::vector<backtrace_frame_data_t>* GetFrames() { return &backtrace_obj_->frames_; }
+
+ inline bool BuildMap() { return backtrace_obj_->BuildMap(); }
Backtrace* backtrace_obj_;
};
class BacktraceCurrent : public Backtrace {
public:
- BacktraceCurrent(BacktraceImpl* impl);
+ BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
virtual ~BacktraceCurrent();
bool ReadWord(uintptr_t ptr, uint32_t* out_value);
@@ -53,14 +59,14 @@
class BacktracePtrace : public Backtrace {
public:
- BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid);
+ BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~BacktracePtrace();
bool ReadWord(uintptr_t ptr, uint32_t* out_value);
};
-Backtrace* CreateCurrentObj();
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid);
-Backtrace* CreateThreadObj(pid_t tid);
+Backtrace* CreateCurrentObj(BacktraceMap* map);
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map);
+Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map);
#endif // _LIBBACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
new file mode 100644
index 0000000..78f5b6b
--- /dev/null
+++ b/libbacktrace/BacktraceMap.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <backtrace/BacktraceMap.h>
+#include <log/log.h>
+
+BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
+ if (pid_ < 0) {
+ pid_ = getpid();
+ }
+}
+
+BacktraceMap::~BacktraceMap() {
+}
+
+const backtrace_map_t* BacktraceMap::Find(uintptr_t addr) {
+ for (BacktraceMap::const_iterator it = begin();
+ it != end(); ++it) {
+ if (addr >= it->start && addr < it->end) {
+ return &*it;
+ }
+ }
+ return NULL;
+}
+
+bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
+ unsigned long int start;
+ unsigned long int end;
+ char permissions[5];
+ int name_pos;
+
+#if defined(__APPLE__)
+// Mac OS vmmap(1) output:
+// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+ if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
+ &start, &end, permissions, &name_pos) != 3) {
+#else
+// Linux /proc/<pid>/maps lines:
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+ if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n",
+ &start, &end, permissions, &name_pos) != 3) {
+#endif
+ return false;
+ }
+
+ map->start = start;
+ map->end = end;
+ map->flags = PROT_NONE;
+ if (permissions[0] == 'r') {
+ map->flags |= PROT_READ;
+ }
+ if (permissions[1] == 'w') {
+ map->flags |= PROT_WRITE;
+ }
+ if (permissions[2] == 'x') {
+ map->flags |= PROT_EXEC;
+ }
+
+ while (isspace(line[name_pos])) {
+ name_pos += 1;
+ }
+ map->name = line+name_pos;
+ if (!map->name.empty() && map->name[map->name.length()-1] == '\n') {
+ map->name.erase(map->name.length()-1);
+ }
+
+ ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
+ map->start, map->end, map->flags, map->name.c_str());
+ return true;
+}
+
+bool BacktraceMap::Build() {
+#if defined(__APPLE__)
+ char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
+#else
+ char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
+#endif
+ char line[1024];
+
+#if defined(__APPLE__)
+ // cmd is guaranteed to always be big enough to hold this string.
+ sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
+ FILE* fp = popen(cmd, "r");
+#else
+ // path is guaranteed to always be big enough to hold this string.
+ sprintf(path, "/proc/%d/maps", pid_);
+ FILE* fp = fopen(path, "r");
+#endif
+ if (fp == NULL) {
+ return false;
+ }
+
+ while(fgets(line, sizeof(line), fp)) {
+ backtrace_map_t map;
+ if (ParseLine(line, &map)) {
+ maps_.push_back(map);
+ }
+ }
+#if defined(__APPLE__)
+ pclose(fp);
+#else
+ fclose(fp);
+#endif
+
+ return true;
+}
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 8e664c4..9953dc1 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -22,7 +22,6 @@
#include <sys/types.h>
#include <cutils/atomic.h>
-#include <cutils/log.h>
#include "BacktraceThread.h"
#include "thread_utils.h"
@@ -114,30 +113,22 @@
}
BacktraceThread::BacktraceThread(
- BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid)
- : BacktraceCurrent(impl), thread_intf_(thread_intf) {
- backtrace_.tid = tid;
+ BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
+ BacktraceMap* map)
+ : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
+ tid_ = tid;
}
BacktraceThread::~BacktraceThread() {
}
void BacktraceThread::FinishUnwind() {
- for (size_t i = 0; i < NumFrames(); i++) {
- backtrace_frame_data_t* frame = &backtrace_.frames[i];
+ for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
+ it != frames_.end(); ++it) {
+ it->map = FindMap(it->pc);
- frame->map_offset = 0;
- uintptr_t map_start;
- frame->map_name = GetMapName(frame->pc, &map_start);
- if (frame->map_name) {
- frame->map_offset = frame->pc - map_start;
- }
-
- frame->func_offset = 0;
- std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
- if (!func_name.empty()) {
- frame->func_name = strdup(func_name.c_str());
- }
+ it->func_offset = 0;
+ it->func_name = GetFunctionName(it->pc, &it->func_offset);
}
}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index 8ed1122..cae496a 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -18,17 +18,16 @@
#define _LIBBACKTRACE_BACKTRACE_THREAD_H
#include <inttypes.h>
-#include <pthread.h>
#include <sys/types.h>
#include "Backtrace.h"
-typedef enum {
+enum state_e {
STATE_WAITING = 0,
STATE_DUMPING,
STATE_DONE,
STATE_CANCEL,
-} state_e;
+};
class BacktraceThreadInterface;
@@ -71,7 +70,8 @@
// the compiler to catch if an implementation does not properly
// subclass both.
BacktraceThread(
- BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid);
+ BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
+ BacktraceMap* map);
virtual ~BacktraceThread();
virtual bool Unwind(size_t num_ignore_frames);
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
index 2be5930..fd31a26 100644
--- a/libbacktrace/Corkscrew.cpp
+++ b/libbacktrace/Corkscrew.cpp
@@ -16,12 +16,11 @@
#define LOG_TAG "libbacktrace"
-#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
#include <string.h>
#include <backtrace-arch.h>
-#include <cutils/log.h>
#include <corkscrew/backtrace.h>
#ifndef __USE_GNU
@@ -32,6 +31,48 @@
#include "Corkscrew.h"
//-------------------------------------------------------------------------
+// CorkscrewMap functions.
+//-------------------------------------------------------------------------
+CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) {
+}
+
+CorkscrewMap::~CorkscrewMap() {
+ if (map_info_) {
+ free_map_info_list(map_info_);
+ map_info_ = NULL;
+ }
+}
+
+bool CorkscrewMap::Build() {
+ map_info_ = load_map_info_list(pid_);
+
+ // Use the information in map_info_ to construct the BacktraceMap data
+ // rather than reparsing /proc/self/maps.
+ map_info_t* cur_map = map_info_;
+ while (cur_map) {
+ backtrace_map_t map;
+ map.start = cur_map->start;
+ map.end = cur_map->end;
+ map.flags = 0;
+ if (cur_map->is_readable) {
+ map.flags |= PROT_READ;
+ }
+ if (cur_map->is_writable) {
+ map.flags |= PROT_WRITE;
+ }
+ if (cur_map->is_executable) {
+ map.flags |= PROT_EXEC;
+ }
+ map.name = cur_map->name;
+
+ maps_.push_back(map);
+
+ cur_map = cur_map->next;
+ }
+ return map_info_ != NULL;
+}
+
+//-------------------------------------------------------------------------
// CorkscrewCommon functions.
//-------------------------------------------------------------------------
bool CorkscrewCommon::GenerateFrameData(
@@ -41,28 +82,19 @@
return false;
}
- backtrace_t* data = GetBacktraceData();
- data->num_frames = num_frames;
- for (size_t i = 0; i < data->num_frames; i++) {
- backtrace_frame_data_t* frame = &data->frames[i];
- frame->pc = cork_frames[i].absolute_pc;
- frame->sp = cork_frames[i].stack_top;
- frame->stack_size = cork_frames[i].stack_size;
- frame->map_name = NULL;
- frame->map_offset = 0;
- frame->func_name = NULL;
- frame->func_offset = 0;
+ std::vector<backtrace_frame_data_t>* frames = GetFrames();
+ frames->resize(num_frames);
+ size_t i = 0;
+ for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
+ it != frames->end(); ++it, ++i) {
+ it->num = i;
+ it->pc = cork_frames[i].absolute_pc;
+ it->sp = cork_frames[i].stack_top;
+ it->stack_size = cork_frames[i].stack_size;
+ it->func_offset = 0;
- uintptr_t map_start;
- frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
- if (frame->map_name) {
- frame->map_offset = frame->pc - map_start;
- }
-
- std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
- if (!func_name.empty()) {
- frame->func_name = strdup(func_name.c_str());
- }
+ it->map = backtrace_obj_->FindMap(it->pc);
+ it->func_name = backtrace_obj_->GetFunctionName(it->pc, &it->func_offset);
}
return true;
}
@@ -87,23 +119,23 @@
*offset = 0;
Dl_info info;
- const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc);
- if (map_info) {
+ const backtrace_map_t* map = backtrace_obj_->FindMap(pc);
+ if (map) {
if (dladdr((const void*)pc, &info)) {
if (info.dli_sname) {
- *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
+ *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
return info.dli_sname;
}
} else {
// dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file...
- symbol_table_t* symbol_table = load_symbol_table(map_info->name);
+ symbol_table_t* symbol_table = load_symbol_table(map->name.c_str());
if (symbol_table) {
// First check if we can find the symbol using a relative pc.
std::string name;
- const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map_info->start);
+ const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start);
if (elf_symbol) {
name = elf_symbol->name;
- *offset = pc - map_info->start - elf_symbol->start;
+ *offset = pc - map->start - elf_symbol->start;
} else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) {
// Found the symbol using the absolute pc.
name = elf_symbol->name;
@@ -124,38 +156,36 @@
}
CorkscrewThread::~CorkscrewThread() {
- if (corkscrew_map_info_) {
- free_map_info_list(corkscrew_map_info_);
- corkscrew_map_info_ = NULL;
- }
}
bool CorkscrewThread::Init() {
- corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid());
- return corkscrew_map_info_ != NULL;
+ if (backtrace_obj_->GetMap() == NULL) {
+ // Trigger the map object creation, which will create the corkscrew
+ // map information.
+ return BuildMap();
+ }
+ return true;
}
void CorkscrewThread::ThreadUnwind(
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
- backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+ backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES];
+ CorkscrewMap* map = static_cast<CorkscrewMap*>(backtrace_obj_->GetMap());
ssize_t num_frames = unwind_backtrace_signal_arch(
- siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames,
- MAX_BACKTRACE_FRAMES);
+ siginfo, sigcontext, map->GetMapInfo(), cork_frames,
+ num_ignore_frames, MAX_BACKTRACE_FRAMES);
if (num_frames > 0) {
- backtrace_t* data = GetBacktraceData();
- data->num_frames = num_frames;
- for (size_t i = 0; i < data->num_frames; i++) {
- backtrace_frame_data_t* frame = &data->frames[i];
- frame->pc = frames[i].absolute_pc;
- frame->sp = frames[i].stack_top;
- frame->stack_size = frames[i].stack_size;
-
- frame->map_offset = 0;
- frame->map_name = NULL;
- frame->map_offset = 0;
-
- frame->func_offset = 0;
- frame->func_name = NULL;
+ std::vector<backtrace_frame_data_t>* frames = GetFrames();
+ frames->resize(num_frames);
+ size_t i = 0;
+ for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
+ it != frames->end(); ++it, ++i) {
+ it->num = i;
+ it->pc = cork_frames[i].absolute_pc;
+ it->sp = cork_frames[i].stack_top;
+ it->stack_size = cork_frames[i].stack_size;
+ it->map = NULL;
+ it->func_offset = 0;
}
}
}
@@ -204,15 +234,15 @@
//-------------------------------------------------------------------------
// C++ object creation functions.
//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj() {
- return new BacktraceCurrent(new CorkscrewCurrent());
+Backtrace* CreateCurrentObj(BacktraceMap* map) {
+ return new BacktraceCurrent(new CorkscrewCurrent(), map);
}
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
- return new BacktracePtrace(new CorkscrewPtrace(), pid, tid);
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
+ return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map);
}
-Backtrace* CreateThreadObj(pid_t tid) {
+Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
CorkscrewThread* thread_obj = new CorkscrewThread();
- return new BacktraceThread(thread_obj, thread_obj, tid);
+ return new BacktraceThread(thread_obj, thread_obj, tid, map);
}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
index 7cb125c..229bb01 100644
--- a/libbacktrace/Corkscrew.h
+++ b/libbacktrace/Corkscrew.h
@@ -21,8 +21,8 @@
#include <string>
-#include <backtrace/backtrace.h>
#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
#include <corkscrew/backtrace.h>
@@ -32,6 +32,8 @@
class CorkscrewCommon : public BacktraceImpl {
public:
bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
+
+ virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); }
};
class CorkscrewCurrent : public CorkscrewCommon {
@@ -44,6 +46,19 @@
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
};
+class CorkscrewMap : public BacktraceMap {
+public:
+ CorkscrewMap(pid_t pid);
+ virtual ~CorkscrewMap();
+
+ virtual bool Build();
+
+ map_info_t* GetMapInfo() { return map_info_; }
+
+private:
+ map_info_t* map_info_;
+};
+
class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
public:
CorkscrewThread();
@@ -54,8 +69,7 @@
virtual void ThreadUnwind(
siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-private:
- map_info_t* corkscrew_map_info_;
+ virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new CorkscrewMap(pid); }
};
class CorkscrewPtrace : public CorkscrewCommon {
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 6c0cad6..d1195ee 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -18,9 +18,8 @@
#include <sys/types.h>
-#include <cutils/log.h>
-
-#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
#define UNW_LOCAL_ONLY
#include <libunwind.h>
@@ -44,7 +43,7 @@
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
typedef struct ucontext ucontext_t;
-#elif !defined(__mips__)
+#elif !defined(__mips__) && !defined(__aarch64__)
#error Unsupported architecture.
#endif
@@ -79,9 +78,6 @@
}
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
- backtrace_t* backtrace = GetBacktraceData();
- backtrace->num_frames = 0;
-
// The cursor structure is pretty large, do not put it on the stack.
unw_cursor_t* cursor = new unw_cursor_t;
int ret = unw_init_local(cursor, &context_);
@@ -91,6 +87,9 @@
return false;
}
+ std::vector<backtrace_frame_data_t>* frames = GetFrames();
+ frames->reserve(MAX_BACKTRACE_FRAMES);
+ size_t num_frames = 0;
do {
unw_word_t pc;
ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
@@ -106,41 +105,32 @@
}
if (num_ignore_frames == 0) {
- size_t num_frames = backtrace->num_frames;
- backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+ frames->resize(num_frames+1);
+ backtrace_frame_data_t* frame = &frames->at(num_frames);
+ frame->num = num_frames;
frame->pc = static_cast<uintptr_t>(pc);
frame->sp = static_cast<uintptr_t>(sp);
frame->stack_size = 0;
- frame->map_name = NULL;
- frame->map_offset = 0;
- frame->func_name = NULL;
- frame->func_offset = 0;
if (num_frames > 0) {
// Set the stack size for the previous frame.
- backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+ backtrace_frame_data_t* prev = &frames->at(num_frames-1);
prev->stack_size = frame->sp - prev->sp;
}
if (resolve) {
- std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
- if (!func_name.empty()) {
- frame->func_name = strdup(func_name.c_str());
- }
-
- uintptr_t map_start;
- frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
- if (frame->map_name) {
- frame->map_offset = frame->pc - map_start;
- }
+ frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+ frame->map = backtrace_obj_->FindMap(frame->pc);
+ } else {
+ frame->map = NULL;
+ frame->func_offset = 0;
}
-
- backtrace->num_frames++;
+ num_frames++;
} else {
num_ignore_frames--;
}
ret = unw_step (cursor);
- } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+ } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
delete cursor;
return true;
@@ -194,11 +184,11 @@
//-------------------------------------------------------------------------
// C++ object creation function.
//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj() {
- return new BacktraceCurrent(new UnwindCurrent());
+Backtrace* CreateCurrentObj(BacktraceMap* map) {
+ return new BacktraceCurrent(new UnwindCurrent(), map);
}
-Backtrace* CreateThreadObj(pid_t tid) {
+Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
UnwindThread* thread_obj = new UnwindThread();
- return new BacktraceThread(thread_obj, thread_obj, tid);
+ return new BacktraceThread(thread_obj, thread_obj, tid, map);
}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index 7dc977d..8302c0b 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -38,6 +38,8 @@
void ExtractContext(void* sigcontext);
+ virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); }
+
protected:
unw_context_t context_;
};
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index a734a24..e45c5f8 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -16,13 +16,12 @@
#define LOG_TAG "libbacktrace"
-#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
#include <sys/types.h>
#include <string.h>
-#include <cutils/log.h>
-
#include <libunwind.h>
#include <libunwind-ptrace.h>
@@ -55,9 +54,6 @@
return false;
}
- backtrace_t* backtrace = GetBacktraceData();
- backtrace->num_frames = 0;
-
unw_cursor_t cursor;
int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
if (ret < 0) {
@@ -65,6 +61,9 @@
return false;
}
+ std::vector<backtrace_frame_data_t>* frames = GetFrames();
+ frames->reserve(MAX_BACKTRACE_FRAMES);
+ size_t num_frames = 0;
do {
unw_word_t pc;
ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
@@ -80,38 +79,28 @@
}
if (num_ignore_frames == 0) {
- size_t num_frames = backtrace->num_frames;
- backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+ frames->resize(num_frames+1);
+ backtrace_frame_data_t* frame = &frames->at(num_frames);
+ frame->num = num_frames;
frame->pc = static_cast<uintptr_t>(pc);
frame->sp = static_cast<uintptr_t>(sp);
frame->stack_size = 0;
- frame->map_name = NULL;
- frame->map_offset = 0;
- frame->func_name = NULL;
- frame->func_offset = 0;
if (num_frames > 0) {
- backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+ backtrace_frame_data_t* prev = &frames->at(num_frames-1);
prev->stack_size = frame->sp - prev->sp;
}
- std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
- if (!func_name.empty()) {
- frame->func_name = strdup(func_name.c_str());
- }
+ frame->func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
- uintptr_t map_start;
- frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
- if (frame->map_name) {
- frame->map_offset = frame->pc - map_start;
- }
+ frame->map = backtrace_obj_->FindMap(frame->pc);
- backtrace->num_frames++;
+ num_frames++;
} else {
num_ignore_frames--;
}
ret = unw_step (&cursor);
- } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+ } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
return true;
}
@@ -131,6 +120,6 @@
//-------------------------------------------------------------------------
// C++ object creation function.
//-------------------------------------------------------------------------
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
- return new BacktracePtrace(new UnwindPtrace(), pid, tid);
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
+ return new BacktracePtrace(new UnwindPtrace(), pid, tid, map);
}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 781405b..05375dd 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -32,6 +32,8 @@
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+ virtual BacktraceMap* CreateBacktraceMap(pid_t pid) { return new BacktraceMap(pid); }
+
private:
unw_addr_space_t addr_space_;
struct UPT_info* upt_info_;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 2603e1f..0ff7897 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -28,7 +28,9 @@
#include <time.h>
#include <unistd.h>
-#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+#include <UniquePtr.h>
#include <cutils/atomic.h>
#include <gtest/gtest.h>
@@ -49,18 +51,18 @@
// Number of simultaneous threads running in our forked process.
#define NUM_PTRACE_THREADS 5
-typedef struct {
+struct thread_t {
pid_t tid;
int32_t state;
pthread_t threadId;
-} thread_t;
+};
-typedef struct {
+struct dump_thread_t {
thread_t thread;
- backtrace_context_t context;
+ Backtrace* backtrace;
int32_t* now;
int32_t done;
-} dump_thread_t;
+};
extern "C" {
// Prototypes for functions in the test library.
@@ -75,15 +77,14 @@
return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
}
-void DumpFrames(const backtrace_context_t* context) {
- if (context->backtrace->num_frames == 0) {
+void DumpFrames(Backtrace* backtrace) {
+ if (backtrace->NumFrames() == 0) {
printf(" No frames to dump\n");
- } else {
- char line[512];
- for (size_t i = 0; i < context->backtrace->num_frames; i++) {
- backtrace_format_frame_data(context, i, line, sizeof(line));
- printf(" %s\n", line);
- }
+ return;
+ }
+
+ for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+ printf(" %s\n", backtrace->FormatFrameData(i).c_str());
}
}
@@ -100,12 +101,11 @@
}
}
-bool ReadyLevelBacktrace(const backtrace_t* backtrace) {
+bool ReadyLevelBacktrace(Backtrace* backtrace) {
// See if test_level_four is in the backtrace.
bool found = false;
- for (size_t i = 0; i < backtrace->num_frames; i++) {
- if (backtrace->frames[i].func_name != NULL &&
- strcmp(backtrace->frames[i].func_name, "test_level_four") == 0) {
+ for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
+ if (it->func_name == "test_level_four") {
found = true;
break;
}
@@ -114,62 +114,55 @@
return found;
}
-void VerifyLevelDump(const backtrace_t* backtrace) {
- ASSERT_GT(backtrace->num_frames, static_cast<size_t>(0));
- ASSERT_LT(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+void VerifyLevelDump(Backtrace* backtrace) {
+ ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0));
+ ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
// Look through the frames starting at the highest to find the
// frame we want.
size_t frame_num = 0;
- for (size_t i = backtrace->num_frames-1; i > 2; i--) {
- if (backtrace->frames[i].func_name != NULL &&
- strcmp(backtrace->frames[i].func_name, "test_level_one") == 0) {
+ for (size_t i = backtrace->NumFrames()-1; i > 2; i--) {
+ if (backtrace->GetFrame(i)->func_name == "test_level_one") {
frame_num = i;
break;
}
}
- ASSERT_GT(frame_num, static_cast<size_t>(0));
+ ASSERT_LT(static_cast<size_t>(0), frame_num);
+ ASSERT_LE(static_cast<size_t>(3), frame_num);
- ASSERT_TRUE(NULL != backtrace->frames[frame_num].func_name);
- ASSERT_STREQ(backtrace->frames[frame_num].func_name, "test_level_one");
- ASSERT_TRUE(NULL != backtrace->frames[frame_num-1].func_name);
- ASSERT_STREQ(backtrace->frames[frame_num-1].func_name, "test_level_two");
- ASSERT_TRUE(NULL != backtrace->frames[frame_num-2].func_name);
- ASSERT_STREQ(backtrace->frames[frame_num-2].func_name, "test_level_three");
- ASSERT_TRUE(NULL != backtrace->frames[frame_num-3].func_name);
- ASSERT_STREQ(backtrace->frames[frame_num-3].func_name, "test_level_four");
+ ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one");
+ ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two");
+ ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three");
+ ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four");
}
void VerifyLevelBacktrace(void*) {
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0));
-
- VerifyLevelDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyLevelDump(backtrace.get());
}
-bool ReadyMaxBacktrace(const backtrace_t* backtrace) {
- return (backtrace->num_frames == MAX_BACKTRACE_FRAMES);
+bool ReadyMaxBacktrace(Backtrace* backtrace) {
+ return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES);
}
-void VerifyMaxDump(const backtrace_t* backtrace) {
- ASSERT_EQ(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+void VerifyMaxDump(Backtrace* backtrace) {
+ ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
// Verify that the last frame is our recursive call.
- ASSERT_TRUE(NULL != backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name);
- ASSERT_STREQ(backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name,
- "test_recursive_call");
+ ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name,
+ "test_recursive_call");
}
void VerifyMaxBacktrace(void*) {
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0));
-
- VerifyMaxDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyMaxDump(backtrace.get());
}
void ThreadSetState(void* data) {
@@ -181,14 +174,12 @@
}
}
-void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(const backtrace_t*)) {
- backtrace_context_t context;
+void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(Backtrace*)) {
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), tid));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- backtrace_create_context(&context, getpid(), tid, 0);
-
- VerifyFunc(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyFunc(backtrace.get());
}
bool WaitForNonZero(int32_t* value, uint64_t seconds) {
@@ -206,49 +197,46 @@
}
void VerifyIgnoreFrames(
- const backtrace_t* bt_all, const backtrace_t* bt_ign1,
- const backtrace_t* bt_ign2, const char* cur_proc) {
- EXPECT_EQ(bt_all->num_frames, bt_ign1->num_frames + 1);
- EXPECT_EQ(bt_all->num_frames, bt_ign2->num_frames + 2);
+ Backtrace* bt_all, Backtrace* bt_ign1,
+ Backtrace* bt_ign2, const char* cur_proc) {
+ EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1);
+ EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2);
// Check all of the frames are the same > the current frame.
bool check = (cur_proc == NULL);
- for (size_t i = 0; i < bt_ign2->num_frames; i++) {
+ for (size_t i = 0; i < bt_ign2->NumFrames(); i++) {
if (check) {
- EXPECT_EQ(bt_ign2->frames[i].pc, bt_ign1->frames[i+1].pc);
- EXPECT_EQ(bt_ign2->frames[i].sp, bt_ign1->frames[i+1].sp);
- EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_ign1->frames[i+1].stack_size);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_ign1->GetFrame(i+1)->pc);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->sp, bt_ign1->GetFrame(i+1)->sp);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->stack_size, bt_ign1->GetFrame(i+1)->stack_size);
- EXPECT_EQ(bt_ign2->frames[i].pc, bt_all->frames[i+2].pc);
- EXPECT_EQ(bt_ign2->frames[i].sp, bt_all->frames[i+2].sp);
- EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_all->frames[i+2].stack_size);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_all->GetFrame(i+2)->pc);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->sp, bt_all->GetFrame(i+2)->sp);
+ EXPECT_EQ(bt_ign2->GetFrame(i)->stack_size, bt_all->GetFrame(i+2)->stack_size);
}
- if (!check && bt_ign2->frames[i].func_name &&
- strcmp(bt_ign2->frames[i].func_name, cur_proc) == 0) {
+ if (!check && bt_ign2->GetFrame(i)->func_name == cur_proc) {
check = true;
}
}
}
void VerifyLevelIgnoreFrames(void*) {
- backtrace_context_t all;
- ASSERT_TRUE(backtrace_create_context(&all, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0));
- ASSERT_TRUE(all.backtrace != NULL);
+ UniquePtr<Backtrace> all(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(all.get() != NULL);
+ ASSERT_TRUE(all->Unwind(0));
- backtrace_context_t ign1;
- ASSERT_TRUE(backtrace_create_context(&ign1, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 1));
- ASSERT_TRUE(ign1.backtrace != NULL);
+ UniquePtr<Backtrace> ign1(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(ign1.get() != NULL);
+ ASSERT_TRUE(ign1->Unwind(1));
- backtrace_context_t ign2;
- ASSERT_TRUE(backtrace_create_context(&ign2, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 2));
- ASSERT_TRUE(ign2.backtrace != NULL);
+ UniquePtr<Backtrace> ign2(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(ign2.get() != NULL);
+ ASSERT_TRUE(ign2->Unwind(2));
- VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace,
- "VerifyLevelIgnoreFrames");
-
- backtrace_destroy_context(&all);
- backtrace_destroy_context(&ign1);
- backtrace_destroy_context(&ign2);
+ VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
}
TEST(libbacktrace, local_trace_ignore_frames) {
@@ -260,8 +248,8 @@
}
void VerifyProcTest(pid_t pid, pid_t tid,
- bool (*ReadyFunc)(const backtrace_t*),
- void (*VerifyFunc)(const backtrace_t*)) {
+ bool (*ReadyFunc)(Backtrace*),
+ void (*VerifyFunc)(Backtrace*)) {
pid_t ptrace_tid;
if (tid < 0) {
ptrace_tid = pid;
@@ -276,13 +264,14 @@
// Wait for the process to get to a stopping point.
WaitForStop(ptrace_tid);
- backtrace_context_t context;
- ASSERT_TRUE(backtrace_create_context(&context, pid, tid, 0));
- if (ReadyFunc(context.backtrace)) {
- VerifyFunc(context.backtrace);
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid));
+ ASSERT_TRUE(backtrace->Unwind(0));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ if (ReadyFunc(backtrace.get())) {
+ VerifyFunc(backtrace.get());
verified = true;
}
- backtrace_destroy_context(&context);
+
ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
}
// If 5 seconds have passed, then we are done.
@@ -296,7 +285,7 @@
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
exit(1);
}
- VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyLevelBacktrace, VerifyLevelDump);
+ VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump);
kill(pid, SIGKILL);
int status;
@@ -309,28 +298,23 @@
ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
exit(1);
}
- VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyMaxBacktrace, VerifyMaxDump);
+ VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump);
kill(pid, SIGKILL);
int status;
ASSERT_EQ(waitpid(pid, &status, 0), pid);
}
-void VerifyProcessIgnoreFrames(const backtrace_t* bt_all) {
- pid_t pid = bt_all->pid;
+void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
+ UniquePtr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(ign1.get() != NULL);
+ ASSERT_TRUE(ign1->Unwind(1));
- backtrace_context_t ign1;
- ASSERT_TRUE(backtrace_create_context(&ign1, pid, BACKTRACE_NO_TID, 1));
- ASSERT_TRUE(ign1.backtrace != NULL);
+ UniquePtr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(ign2.get() != NULL);
+ ASSERT_TRUE(ign2->Unwind(2));
- backtrace_context_t ign2;
- ASSERT_TRUE(backtrace_create_context(&ign2, pid, BACKTRACE_NO_TID, 2));
- ASSERT_TRUE(ign2.backtrace != NULL);
-
- VerifyIgnoreFrames(bt_all, ign1.backtrace, ign2.backtrace, NULL);
-
- backtrace_destroy_context(&ign1);
- backtrace_destroy_context(&ign2);
+ VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), NULL);
}
TEST(libbacktrace, ptrace_ignore_frames) {
@@ -339,7 +323,7 @@
ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
exit(1);
}
- VerifyProcTest(pid, BACKTRACE_NO_TID, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
+ VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
kill(pid, SIGKILL);
int status;
@@ -413,13 +397,11 @@
}
void VerifyLevelThread(void*) {
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
-
- VerifyLevelDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyLevelDump(backtrace.get());
}
TEST(libbacktrace, thread_current_level) {
@@ -427,13 +409,11 @@
}
void VerifyMaxThread(void*) {
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), gettid()));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
-
- VerifyMaxDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyMaxDump(backtrace.get());
}
TEST(libbacktrace, thread_current_max) {
@@ -464,13 +444,11 @@
struct sigaction cur_action;
ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid,0));
-
- VerifyLevelDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyLevelDump(backtrace.get());
// Tell the thread to exit its infinite loop.
android_atomic_acquire_store(0, &thread_data.state);
@@ -494,20 +472,19 @@
// Wait up to 2 seconds for the tid to be set.
ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
- backtrace_context_t all;
- ASSERT_TRUE(backtrace_create_context(&all, getpid(), thread_data.tid, 0));
+ UniquePtr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
+ ASSERT_TRUE(all.get() != NULL);
+ ASSERT_TRUE(all->Unwind(0));
- backtrace_context_t ign1;
- ASSERT_TRUE(backtrace_create_context(&ign1, getpid(), thread_data.tid, 1));
+ UniquePtr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
+ ASSERT_TRUE(ign1.get() != NULL);
+ ASSERT_TRUE(ign1->Unwind(1));
- backtrace_context_t ign2;
- ASSERT_TRUE(backtrace_create_context(&ign2, getpid(), thread_data.tid, 2));
+ UniquePtr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
+ ASSERT_TRUE(ign2.get() != NULL);
+ ASSERT_TRUE(ign2->Unwind(2));
- VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, NULL);
-
- backtrace_destroy_context(&all);
- backtrace_destroy_context(&ign1);
- backtrace_destroy_context(&ign2);
+ VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), NULL);
// Tell the thread to exit its infinite loop.
android_atomic_acquire_store(0, &thread_data.state);
@@ -533,13 +510,11 @@
// Wait for the tid to be set.
ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
+ ASSERT_TRUE(backtrace.get() != NULL);
+ ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid, 0));
-
- VerifyMaxDump(context.backtrace);
-
- backtrace_destroy_context(&context);
+ VerifyMaxDump(backtrace.get());
// Tell the thread to exit its infinite loop.
android_atomic_acquire_store(0, &thread_data.state);
@@ -553,11 +528,9 @@
}
}
- dump->context.data = NULL;
- dump->context.backtrace = NULL;
-
// The status of the actual unwind will be checked elsewhere.
- backtrace_create_context(&dump->context, getpid(), dump->thread.tid, 0);
+ dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid);
+ dump->backtrace->Unwind(0);
android_atomic_acquire_store(1, &dump->done);
@@ -605,56 +578,77 @@
// Tell the runner thread to exit its infinite loop.
android_atomic_acquire_store(0, &runners[i].state);
- ASSERT_TRUE(dumpers[i].context.backtrace != NULL);
- VerifyMaxDump(dumpers[i].context.backtrace);
- backtrace_destroy_context(&dumpers[i].context);
+ ASSERT_TRUE(dumpers[i].backtrace != NULL);
+ VerifyMaxDump(dumpers[i].backtrace);
+
+ delete dumpers[i].backtrace;
+ dumpers[i].backtrace = NULL;
}
}
TEST(libbacktrace, format_test) {
- backtrace_context_t context;
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != NULL);
- ASSERT_TRUE(backtrace_create_context(&context, BACKTRACE_CURRENT_PROCESS, BACKTRACE_NO_TID, 0));
- ASSERT_TRUE(context.backtrace != NULL);
+ backtrace_frame_data_t frame;
+ frame.num = 1;
+ frame.pc = 2;
+ frame.sp = 0;
+ frame.stack_size = 0;
+ frame.map = NULL;
+ frame.func_offset = 0;
- backtrace_frame_data_t* frame = const_cast<backtrace_frame_data_t*>(&context.backtrace->frames[1]);
- backtrace_frame_data_t save_frame = *frame;
+ backtrace_map_t map;
+ map.start = 0;
+ map.end = 0;
- memset(frame, 0, sizeof(backtrace_frame_data_t));
- char buf[512];
- backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+ // Check no map set.
+ frame.num = 1;
#if defined(__LP64__)
- EXPECT_STREQ(buf, "#01 pc 0000000000000000 <unknown>");
+ EXPECT_EQ("#01 pc 0000000000000002 <unknown>",
#else
- EXPECT_STREQ(buf, "#01 pc 00000000 <unknown>");
+ EXPECT_EQ("#01 pc 00000002 <unknown>",
#endif
+ backtrace->FormatFrameData(&frame));
- frame->pc = 0x12345678;
- frame->map_name = "MapFake";
- backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+ // Check map name empty, but exists.
+ frame.map = ↦
+ map.start = 1;
#if defined(__LP64__)
- EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake");
+ EXPECT_EQ("#01 pc 0000000000000001 <unknown>",
#else
- EXPECT_STREQ(buf, "#01 pc 12345678 MapFake");
+ EXPECT_EQ("#01 pc 00000001 <unknown>",
#endif
+ backtrace->FormatFrameData(&frame));
- frame->func_name = const_cast<char*>("ProcFake");
- backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+
+ // Check relative pc is set and map name is set.
+ frame.pc = 0x12345679;
+ frame.map = ↦
+ map.name = "MapFake";
+ map.start = 1;
#if defined(__LP64__)
- EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake)");
+ EXPECT_EQ("#01 pc 0000000012345678 MapFake",
#else
- EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake)");
+ EXPECT_EQ("#01 pc 12345678 MapFake",
#endif
+ backtrace->FormatFrameData(&frame));
- frame->func_offset = 645;
- backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+ // Check func_name is set, but no func offset.
+ frame.func_name = "ProcFake";
#if defined(__LP64__)
- EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake+645)");
+ EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake)",
#else
- EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake+645)");
+ EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake)",
#endif
+ backtrace->FormatFrameData(&frame));
- *frame = save_frame;
-
- backtrace_destroy_context(&context);
+ // Check func_name is set, and func offset is non-zero.
+ frame.func_offset = 645;
+#if defined(__LP64__)
+ EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake+645)",
+#else
+ EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake+645)",
+#endif
+ backtrace->FormatFrameData(&frame));
}
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
deleted file mode 100644
index 9cc6e01..0000000
--- a/libbacktrace/map_info.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2013 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <cutils/log.h>
-#include <sys/time.h>
-
-#include <backtrace/backtrace.h>
-
-#if defined(__APPLE__)
-
-// Mac OS vmmap(1) output:
-// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
-static backtrace_map_info_t* parse_vmmap_line(const char* line) {
- unsigned long int start;
- unsigned long int end;
- char permissions[4];
- int name_pos;
- if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
- &start, &end, permissions, &name_pos) != 3) {
- return NULL;
- }
-
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
-
- backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
- if (mi != NULL) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = permissions[0] == 'r';
- mi->is_writable = permissions[1] == 'w';
- mi->is_executable = permissions[2] == 'x';
- memcpy(mi->name, name, name_len);
- mi->name[name_len - 1] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
- char cmd[1024];
- if (pid < 0) {
- pid = getpid();
- }
- snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
- FILE* fp = popen(cmd, "r");
- if (fp == NULL) {
- return NULL;
- }
-
- char line[1024];
- backtrace_map_info_t* milist = NULL;
- while (fgets(line, sizeof(line), fp) != NULL) {
- backtrace_map_info_t* mi = parse_vmmap_line(line);
- if (mi != NULL) {
- mi->next = milist;
- milist = mi;
- }
- }
- pclose(fp);
- return milist;
-}
-
-#else
-
-// Linux /proc/<pid>/maps lines:
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
-static backtrace_map_info_t* parse_maps_line(const char* line)
-{
- unsigned long int start;
- unsigned long int end;
- char permissions[5];
- int name_pos;
- if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
- permissions, &name_pos) != 3) {
- return NULL;
- }
-
- while (isspace(line[name_pos])) {
- name_pos += 1;
- }
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
- if (name_len && name[name_len - 1] == '\n') {
- name_len -= 1;
- }
-
- backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
- if (mi) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
- mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
- mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
- memcpy(mi->name, name, name_len);
- mi->name[name_len] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
- char path[PATH_MAX];
- char line[1024];
- FILE* fp;
- backtrace_map_info_t* milist = NULL;
-
- if (tid < 0) {
- tid = getpid();
- }
- snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
- fp = fopen(path, "r");
- if (fp) {
- while(fgets(line, sizeof(line), fp)) {
- backtrace_map_info_t* mi = parse_maps_line(line);
- if (mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
- return milist;
-}
-
-#endif
-
-void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
- while (milist) {
- backtrace_map_info_t* next = milist->next;
- free(milist);
- milist = next;
- }
-}
-
-const backtrace_map_info_t* backtrace_find_map_info(
- const backtrace_map_info_t* milist, uintptr_t addr) {
- const backtrace_map_info_t* mi = milist;
- while (mi && !(addr >= mi->start && addr < mi->end)) {
- mi = mi->next;
- }
- return mi;
-}
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
index ff6c192..7bd0d8f 100644
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ b/libcorkscrew/arch-arm/backtrace-arm.c
@@ -59,7 +59,7 @@
#include <limits.h>
#include <errno.h>
#include <sys/ptrace.h>
-#include <sys/exec_elf.h>
+#include <elf.h>
#include <cutils/log.h>
#if !defined(__BIONIC_HAVE_UCONTEXT_T)
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
index 78a9ea9..a50844e 100644
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ b/libcorkscrew/arch-arm/ptrace-arm.c
@@ -19,7 +19,7 @@
#include "../ptrace-arch.h"
-#include <sys/exec_elf.h>
+#include <elf.h>
#include <cutils/log.h>
#ifndef PT_ARM_EXIDX
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index f8dda36..c08a50f 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -124,7 +124,7 @@
endif # !x86
endif # !arm
-LOCAL_C_INCLUDES := $(libcutils_c_includes) $(KERNEL_HEADERS)
+LOCAL_C_INCLUDES := $(libcutils_c_includes)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(targetSmpFlag)
include $(BUILD_STATIC_LIBRARY)
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 9425006..7d907fc 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -30,6 +30,7 @@
debugger_msg_t msg;
msg.tid = tid;
msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
+ msg.abort_msg_address = 0;
int result = 0;
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
@@ -63,6 +64,7 @@
debugger_msg_t msg;
msg.tid = tid;
msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
+ msg.abort_msg_address = 0;
int result = 0;
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
diff --git a/libdiskconfig/diskconfig.c b/libdiskconfig/diskconfig.c
index d5425de..6fd81b7 100644
--- a/libdiskconfig/diskconfig.c
+++ b/libdiskconfig/diskconfig.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -80,7 +81,7 @@
*plen *= multiple;
if (*plen > 0xffffffffULL) {
- ALOGE("Length specified is too large!: %llu KB", *plen);
+ ALOGE("Length specified is too large!: %"PRIu64" KB", *plen);
return 1;
}
}
@@ -371,8 +372,8 @@
/* only matters for disks, not files */
if (S_ISBLK(stat.st_mode) && total_size > disk_size) {
- ALOGE("Total requested size of partitions (%llu) is greater than disk "
- "size (%llu).", total_size, disk_size);
+ ALOGE("Total requested size of partitions (%"PRIu64") is greater than disk "
+ "size (%"PRIu64").", total_size, disk_size);
goto fail;
}
diff --git a/libion/ion_test.c b/libion/ion_test.c
index 12163e9..8872282 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -63,7 +63,7 @@
ret = ion_free(fd, handle);
if (ret) {
- printf("%s failed: %s %p\n", __func__, strerror(ret), handle);
+ printf("%s failed: %s %d\n", __func__, strerror(ret), handle);
return;
}
ion_close(fd);
diff --git a/libmemtrack/memtrack_test.c b/libmemtrack/memtrack_test.c
index cd94bc5..eaadfa7 100644
--- a/libmemtrack/memtrack_test.c
+++ b/libmemtrack/memtrack_test.c
@@ -35,7 +35,7 @@
return -1;
}
- if (asprintf(&filename, "/proc/%zd/cmdline", pid) < 0) {
+ if (asprintf(&filename, "/proc/%d/cmdline", pid) < 0) {
rc = 1;
goto exit;
}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 0f502c0..fe50cc6 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -52,11 +52,11 @@
LOCAL_SHARED_LIBRARIES := libcutils liblog
-ifeq ($(TARGET_ARCH),aarch64)
-PIXELFLINGER_SRC_FILES += arch-aarch64/t32cb16blend.S
-PIXELFLINGER_SRC_FILES += arch-aarch64/col32cb16blend.S
-PIXELFLINGER_SRC_FILES += codeflinger/Aarch64Assembler.cpp
-PIXELFLINGER_SRC_FILES += codeflinger/Aarch64Disassembler.cpp
+ifeq ($(TARGET_ARCH),arm64)
+PIXELFLINGER_SRC_FILES += arch-arm64/t32cb16blend.S
+PIXELFLINGER_SRC_FILES += arch-arm64/col32cb16blend.S
+PIXELFLINGER_SRC_FILES += codeflinger/Arm64Assembler.cpp
+PIXELFLINGER_SRC_FILES += codeflinger/Arm64Disassembler.cpp
PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
endif
diff --git a/libpixelflinger/arch-aarch64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
similarity index 97%
rename from libpixelflinger/arch-aarch64/col32cb16blend.S
rename to libpixelflinger/arch-arm64/col32cb16blend.S
index aa969a4..18a01fd 100644
--- a/libpixelflinger/arch-aarch64/col32cb16blend.S
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -28,7 +28,7 @@
.text
.align
- .global scanline_col32cb16blend_aarch64
+ .global scanline_col32cb16blend_arm64
//
// This function alpha blends a fixed color into a destination scanline, using
@@ -46,7 +46,7 @@
// w2 = count
-scanline_col32cb16blend_aarch64:
+scanline_col32cb16blend_arm64:
lsr w5, w1, #24 // shift down alpha
mov w9, #0xff // create mask
diff --git a/libpixelflinger/arch-aarch64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
similarity index 98%
rename from libpixelflinger/arch-aarch64/t32cb16blend.S
rename to libpixelflinger/arch-arm64/t32cb16blend.S
index b62ed36..7da8cf5 100644
--- a/libpixelflinger/arch-aarch64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -28,7 +28,7 @@
.text
.align
- .global scanline_t32cb16blend_aarch64
+ .global scanline_t32cb16blend_arm64
/*
* .macro pixel
@@ -155,7 +155,7 @@
// w12: scratch
// w14: pixel
-scanline_t32cb16blend_aarch64:
+scanline_t32cb16blend_arm64:
// align DST to 32 bits
tst x0, #0x3
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
index 6e0d7c6..40cbfcf 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
@@ -63,7 +63,7 @@
};
enum {
- CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_AARCH64
+ CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64
};
// -----------------------------------------------------------------------
diff --git a/libpixelflinger/codeflinger/Aarch64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
similarity index 81%
rename from libpixelflinger/codeflinger/Aarch64Assembler.cpp
rename to libpixelflinger/codeflinger/Arm64Assembler.cpp
index 0e4f7df..f37072a 100644
--- a/libpixelflinger/codeflinger/Aarch64Assembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Assembler.cpp
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
-#define LOG_TAG "ArmToAarch64Assembler"
+#define LOG_TAG "ArmToArm64Assembler"
#include <stdio.h>
#include <stdlib.h>
@@ -36,45 +36,45 @@
#include <cutils/properties.h>
#include <private/pixelflinger/ggl_context.h>
-#include "codeflinger/Aarch64Assembler.h"
+#include "codeflinger/Arm64Assembler.h"
#include "codeflinger/CodeCache.h"
-#include "codeflinger/Aarch64Disassembler.h"
+#include "codeflinger/Arm64Disassembler.h"
/*
** --------------------------------------------
-** Support for Aarch64 in GGLAssembler JIT
+** Support for Arm64 in GGLAssembler JIT
** --------------------------------------------
**
** Approach
** - GGLAssembler and associated files are largely un-changed.
** - A translator class maps ArmAssemblerInterface calls to
-** generate AArch64 instructions.
+** generate Arm64 instructions.
**
** ----------------------
-** ArmToAarch64Assembler
+** ArmToArm64Assembler
** ----------------------
**
** - Subclassed from ArmAssemblerInterface
**
** - Translates each ArmAssemblerInterface call to generate
-** one or more Aarch64 instructions as necessary.
+** one or more Arm64 instructions as necessary.
**
** - Does not implement ArmAssemblerInterface portions unused by GGLAssembler
** It calls NOT_IMPLEMENTED() for such cases, which in turn logs
** a fatal message.
**
** - Uses A64_.. series of functions to generate instruction machine code
-** for Aarch64 instructions. These functions also log the instruction
-** to LOG, if AARCH64_ASM_DEBUG define is set to 1
+** for Arm64 instructions. These functions also log the instruction
+** to LOG, if ARM64_ASM_DEBUG define is set to 1
**
** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
-** It uses aarch64_disassemble to perform disassembly
+** It uses arm64_disassemble to perform disassembly
**
** - Uses register 13 (SP in ARM), 15 (PC in ARM), 16, 17 for storing
** intermediate results. GGLAssembler does not use SP and PC as these
** registers are marked as reserved. The temporary registers are not
-** saved/restored on stack as these are caller-saved registers in Aarch64
+** saved/restored on stack as these are caller-saved registers in Arm64
**
** - Uses CSEL instruction to support conditional execution. The result is
** stored in a temporary register and then copied to the target register
@@ -89,10 +89,10 @@
** move immediate instructions followed by register-register instruction.
**
** --------------------------------------------
-** ArmToAarch64Assembler unit test bench
+** ArmToArm64Assembler unit test bench
** --------------------------------------------
**
-** - Tests ArmToAarch64Assembler interface for all the possible
+** - Tests ArmToArm64Assembler interface for all the possible
** ways in which GGLAssembler uses ArmAssemblerInterface interface.
**
** - Uses test jacket (written in assembly) to set the registers,
@@ -105,10 +105,10 @@
** (ii) data transfer tests and (iii) LDM/STM tests.
**
** ----------------------
-** Aarch64 disassembler
+** Arm64 disassembler
** ----------------------
** - This disassembler disassembles only those machine codes which can be
-** generated by ArmToAarch64Assembler. It has a unit testbench which
+** generated by ArmToArm64Assembler. It has a unit testbench which
** tests all the instructions supported by the disassembler.
**
** ------------------------------------------------------------------
@@ -122,13 +122,13 @@
** These are ADDR_LDR, ADDR_STR, ADDR_ADD, ADDR_SUB and they map to
** default 32 bit implementations in ARMAssemblerInterface.
**
-** - ArmToAarch64Assembler maps these functions to appropriate 64 bit
+** - ArmToArm64Assembler maps these functions to appropriate 64 bit
** functions.
**
** ----------------------
** GGLAssembler changes
** ----------------------
-** - Since ArmToAarch64Assembler can generate 4 Aarch64 instructions for
+** - Since ArmToArm64Assembler can generate 4 Arm64 instructions for
** each call in worst case, the memory required is set to 4 times
** ARM memory
**
@@ -140,9 +140,9 @@
#define NOT_IMPLEMENTED() LOG_FATAL("Arm instruction %s not yet implemented\n", __func__)
-#define AARCH64_ASM_DEBUG 0
+#define ARM64_ASM_DEBUG 0
-#if AARCH64_ASM_DEBUG
+#if ARM64_ASM_DEBUG
#define LOG_INSTR(...) ALOGD("\t" __VA_ARGS__)
#define LOG_LABEL(...) ALOGD(__VA_ARGS__)
#else
@@ -163,7 +163,7 @@
"GE", "LT", "GT", "LE", "AL", "NV"
};
-ArmToAarch64Assembler::ArmToAarch64Assembler(const sp<Assembly>& assembly)
+ArmToArm64Assembler::ArmToArm64Assembler(const sp<Assembly>& assembly)
: ARMAssemblerInterface(),
mAssembly(assembly)
{
@@ -175,7 +175,7 @@
mTmpReg3 = 17;
}
-ArmToAarch64Assembler::ArmToAarch64Assembler(void *base)
+ArmToArm64Assembler::ArmToArm64Assembler(void *base)
: ARMAssemblerInterface(), mAssembly(NULL)
{
mBase = mPC = (uint32_t *)base;
@@ -187,21 +187,21 @@
mTmpReg3 = 17;
}
-ArmToAarch64Assembler::~ArmToAarch64Assembler()
+ArmToArm64Assembler::~ArmToArm64Assembler()
{
}
-uint32_t* ArmToAarch64Assembler::pc() const
+uint32_t* ArmToArm64Assembler::pc() const
{
return mPC;
}
-uint32_t* ArmToAarch64Assembler::base() const
+uint32_t* ArmToArm64Assembler::base() const
{
return mBase;
}
-void ArmToAarch64Assembler::reset()
+void ArmToArm64Assembler::reset()
{
if(mAssembly == NULL)
mPC = mBase;
@@ -211,19 +211,19 @@
mLabels.clear();
mLabelsInverseMapping.clear();
mComments.clear();
-#if AARCH64_ASM_DEBUG
+#if ARM64_ASM_DEBUG
ALOGI("RESET\n");
#endif
}
-int ArmToAarch64Assembler::getCodegenArch()
+int ArmToArm64Assembler::getCodegenArch()
{
- return CODEGEN_ARCH_AARCH64;
+ return CODEGEN_ARCH_ARM64;
}
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::disassemble(const char* name)
+void ArmToArm64Assembler::disassemble(const char* name)
{
if(name)
{
@@ -246,34 +246,34 @@
printf("%p: %08x ", i, uint32_t(i[0]));
{
char instr[256];
- ::aarch64_disassemble(*i, instr);
+ ::arm64_disassemble(*i, instr);
printf("%s\n", instr);
}
i++;
}
}
-void ArmToAarch64Assembler::comment(const char* string)
+void ArmToArm64Assembler::comment(const char* string)
{
mComments.add(mPC, string);
LOG_INSTR("//%s\n", string);
}
-void ArmToAarch64Assembler::label(const char* theLabel)
+void ArmToArm64Assembler::label(const char* theLabel)
{
mLabels.add(theLabel, mPC);
mLabelsInverseMapping.add(mPC, theLabel);
LOG_LABEL("%s:\n", theLabel);
}
-void ArmToAarch64Assembler::B(int cc, const char* label)
+void ArmToArm64Assembler::B(int cc, const char* label)
{
mBranchTargets.add(branch_target_t(label, mPC));
LOG_INSTR("B%s %s\n", cc_codes[cc], label );
*mPC++ = (0x54 << 24) | cc;
}
-void ArmToAarch64Assembler::BL(int cc, const char* label)
+void ArmToArm64Assembler::BL(int cc, const char* label)
{
NOT_IMPLEMENTED(); //Not Required
}
@@ -282,21 +282,21 @@
//Prolog/Epilog & Generate...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::prolog()
+void ArmToArm64Assembler::prolog()
{
// write prolog code
mPrologPC = mPC;
*mPC++ = A64_MOVZ_X(mZeroReg,0,0);
}
-void ArmToAarch64Assembler::epilog(uint32_t touched)
+void ArmToArm64Assembler::epilog(uint32_t touched)
{
// write epilog code
static const int XLR = 30;
*mPC++ = A64_RET(XLR);
}
-int ArmToAarch64Assembler::generate(const char* name)
+int ArmToArm64Assembler::generate(const char* name)
{
// fixup all the branches
size_t count = mBranchTargets.size();
@@ -329,7 +329,7 @@
return NO_ERROR;
}
-uint32_t* ArmToAarch64Assembler::pcForLabel(const char* label)
+uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
{
return mLabels.valueFor(label);
}
@@ -337,7 +337,7 @@
// ----------------------------------------------------------------------------
// Data Processing...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::dataProcessingCommon(int opcode,
+void ArmToArm64Assembler::dataProcessingCommon(int opcode,
int s, int Rd, int Rn, uint32_t Op2)
{
if(opcode != opSUB && s == 1)
@@ -405,7 +405,7 @@
}
}
-void ArmToAarch64Assembler::dataProcessing(int opcode, int cc,
+void ArmToArm64Assembler::dataProcessing(int opcode, int cc,
int s, int Rd, int Rn, uint32_t Op2)
{
uint32_t Wd;
@@ -460,7 +460,7 @@
// Address Processing...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::ADDR_ADD(int cc,
+void ArmToArm64Assembler::ADDR_ADD(int cc,
int s, int Rd, int Rn, uint32_t Op2)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -495,7 +495,7 @@
}
}
-void ArmToAarch64Assembler::ADDR_SUB(int cc,
+void ArmToArm64Assembler::ADDR_SUB(int cc,
int s, int Rd, int Rn, uint32_t Op2)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -516,7 +516,7 @@
// ----------------------------------------------------------------------------
// multiply...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
+void ArmToArm64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -524,28 +524,28 @@
if(s == 1)
dataProcessingCommon(opSUB, 1, mTmpReg1, Rd, mZeroReg);
}
-void ArmToAarch64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
+void ArmToArm64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
*mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
}
-void ArmToAarch64Assembler::UMULL(int cc, int s,
+void ArmToArm64Assembler::UMULL(int cc, int s,
int RdLo, int RdHi, int Rm, int Rs)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::UMUAL(int cc, int s,
+void ArmToArm64Assembler::UMUAL(int cc, int s,
int RdLo, int RdHi, int Rm, int Rs)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::SMULL(int cc, int s,
+void ArmToArm64Assembler::SMULL(int cc, int s,
int RdLo, int RdHi, int Rm, int Rs)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::SMUAL(int cc, int s,
+void ArmToArm64Assembler::SMUAL(int cc, int s,
int RdLo, int RdHi, int Rm, int Rs)
{
NOT_IMPLEMENTED(); //Not required
@@ -554,15 +554,15 @@
// ----------------------------------------------------------------------------
// branches relative to PC...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::B(int cc, uint32_t* pc){
+void ArmToArm64Assembler::B(int cc, uint32_t* pc){
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::BL(int cc, uint32_t* pc){
+void ArmToArm64Assembler::BL(int cc, uint32_t* pc){
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::BX(int cc, int Rn){
+void ArmToArm64Assembler::BX(int cc, int Rn){
NOT_IMPLEMENTED(); //Not required
}
@@ -574,7 +574,7 @@
opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
};
-void ArmToAarch64Assembler::dataTransfer(int op, int cc,
+void ArmToArm64Assembler::dataTransfer(int op, int cc,
int Rd, int Rn, uint32_t op_type, uint32_t size)
{
const int XSP = 31;
@@ -631,46 +631,46 @@
return;
}
-void ArmToAarch64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
}
-void ArmToAarch64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
}
-void ArmToAarch64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opLDR, cc, Rd, Rn, op_type);
}
-void ArmToAarch64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
}
-void ArmToAarch64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opSTR, cc, Rd, Rn, op_type);
}
-void ArmToAarch64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
}
-void ArmToAarch64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
}
-void ArmToAarch64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
+void ArmToArm64Assembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
+void ArmToArm64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
{
return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
}
@@ -678,7 +678,7 @@
// ----------------------------------------------------------------------------
// block data transfer...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::LDM(int cc, int dir,
+void ArmToArm64Assembler::LDM(int cc, int dir,
int Rn, int W, uint32_t reg_list)
{
const int XSP = 31;
@@ -699,7 +699,7 @@
}
}
-void ArmToAarch64Assembler::STM(int cc, int dir,
+void ArmToArm64Assembler::STM(int cc, int dir,
int Rn, int W, uint32_t reg_list)
{
const int XSP = 31;
@@ -723,15 +723,15 @@
// ----------------------------------------------------------------------------
// special...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWP(int cc, int Rn, int Rd, int Rm)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
+void ArmToArm64Assembler::SWPB(int cc, int Rn, int Rd, int Rm)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::SWI(int cc, uint32_t comment)
+void ArmToArm64Assembler::SWI(int cc, uint32_t comment)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -739,31 +739,31 @@
// ----------------------------------------------------------------------------
// DSP instructions...
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::PLD(int Rn, uint32_t offset) {
+void ArmToArm64Assembler::PLD(int Rn, uint32_t offset) {
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::CLZ(int cc, int Rd, int Rm)
+void ArmToArm64Assembler::CLZ(int cc, int Rd, int Rm)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::QADD(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QADD(int cc, int Rd, int Rm, int Rn)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::QDADD(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDADD(int cc, int Rd, int Rm, int Rn)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::QSUB(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QSUB(int cc, int Rd, int Rm, int Rn)
{
NOT_IMPLEMENTED(); //Not required
}
-void ArmToAarch64Assembler::QDSUB(int cc, int Rd, int Rm, int Rn)
+void ArmToArm64Assembler::QDSUB(int cc, int Rd, int Rm, int Rn)
{
NOT_IMPLEMENTED(); //Not required
}
@@ -771,7 +771,7 @@
// ----------------------------------------------------------------------------
// 16 x 16 multiplication
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::SMUL(int cc, int xy,
+void ArmToArm64Assembler::SMUL(int cc, int xy,
int Rd, int Rm, int Rs)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -791,7 +791,7 @@
// ----------------------------------------------------------------------------
// 32 x 16 multiplication
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
+void ArmToArm64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -807,7 +807,7 @@
// ----------------------------------------------------------------------------
// 16 x 16 multiplication and accumulate
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
+void ArmToArm64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
if(xy != xyBB) { NOT_IMPLEMENTED(); return;} //Not required
@@ -817,14 +817,14 @@
*mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
}
-void ArmToAarch64Assembler::SMLAL(int cc, int xy,
+void ArmToArm64Assembler::SMLAL(int cc, int xy,
int RdHi, int RdLo, int Rs, int Rm)
{
NOT_IMPLEMENTED(); //Not required
return;
}
-void ArmToAarch64Assembler::SMLAW(int cc, int y,
+void ArmToArm64Assembler::SMLAW(int cc, int y,
int Rd, int Rm, int Rs, int Rn)
{
NOT_IMPLEMENTED(); //Not required
@@ -834,7 +834,7 @@
// ----------------------------------------------------------------------------
// Byte/half word extract and extend
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
+void ArmToArm64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
@@ -849,7 +849,7 @@
// ----------------------------------------------------------------------------
// Bit manipulation
// ----------------------------------------------------------------------------
-void ArmToAarch64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
+void ArmToArm64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
{
if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
*mPC++ = A64_UBFM_W(Rd, Rn, lsb, lsb + width - 1);
@@ -857,7 +857,7 @@
// ----------------------------------------------------------------------------
// Shifters...
// ----------------------------------------------------------------------------
-int ArmToAarch64Assembler::buildImmediate(
+int ArmToArm64Assembler::buildImmediate(
uint32_t immediate, uint32_t& rot, uint32_t& imm)
{
rot = 0;
@@ -866,13 +866,13 @@
}
-bool ArmToAarch64Assembler::isValidImmediate(uint32_t immediate)
+bool ArmToArm64Assembler::isValidImmediate(uint32_t immediate)
{
uint32_t rot, imm;
return buildImmediate(immediate, rot, imm) == 0;
}
-uint32_t ArmToAarch64Assembler::imm(uint32_t immediate)
+uint32_t ArmToArm64Assembler::imm(uint32_t immediate)
{
mAddrMode.immediate = immediate;
mAddrMode.writeback = false;
@@ -882,7 +882,7 @@
}
-uint32_t ArmToAarch64Assembler::reg_imm(int Rm, int type, uint32_t shift)
+uint32_t ArmToArm64Assembler::reg_imm(int Rm, int type, uint32_t shift)
{
mAddrMode.reg_imm_Rm = Rm;
mAddrMode.reg_imm_type = type;
@@ -890,13 +890,13 @@
return OPERAND_REG_IMM;
}
-uint32_t ArmToAarch64Assembler::reg_rrx(int Rm)
+uint32_t ArmToArm64Assembler::reg_rrx(int Rm)
{
NOT_IMPLEMENTED();
return OPERAND_UNSUPPORTED;
}
-uint32_t ArmToAarch64Assembler::reg_reg(int Rm, int type, int Rs)
+uint32_t ArmToArm64Assembler::reg_reg(int Rm, int type, int Rs)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
@@ -904,7 +904,7 @@
// ----------------------------------------------------------------------------
// Addressing modes...
// ----------------------------------------------------------------------------
-uint32_t ArmToAarch64Assembler::immed12_pre(int32_t immed12, int W)
+uint32_t ArmToArm64Assembler::immed12_pre(int32_t immed12, int W)
{
mAddrMode.immediate = immed12;
mAddrMode.writeback = W;
@@ -913,7 +913,7 @@
return OPERAND_IMM;
}
-uint32_t ArmToAarch64Assembler::immed12_post(int32_t immed12)
+uint32_t ArmToArm64Assembler::immed12_post(int32_t immed12)
{
mAddrMode.immediate = immed12;
mAddrMode.writeback = true;
@@ -922,7 +922,7 @@
return OPERAND_IMM;
}
-uint32_t ArmToAarch64Assembler::reg_scale_pre(int Rm, int type,
+uint32_t ArmToArm64Assembler::reg_scale_pre(int Rm, int type,
uint32_t shift, int W)
{
if(type != 0 || shift != 0 || W != 0)
@@ -937,13 +937,13 @@
}
}
-uint32_t ArmToAarch64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
+uint32_t ArmToArm64Assembler::reg_scale_post(int Rm, int type, uint32_t shift)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
}
-uint32_t ArmToAarch64Assembler::immed8_pre(int32_t immed8, int W)
+uint32_t ArmToArm64Assembler::immed8_pre(int32_t immed8, int W)
{
mAddrMode.immediate = immed8;
mAddrMode.writeback = W;
@@ -952,7 +952,7 @@
return OPERAND_IMM;
}
-uint32_t ArmToAarch64Assembler::immed8_post(int32_t immed8)
+uint32_t ArmToArm64Assembler::immed8_post(int32_t immed8)
{
mAddrMode.immediate = immed8;
mAddrMode.writeback = true;
@@ -961,7 +961,7 @@
return OPERAND_IMM;
}
-uint32_t ArmToAarch64Assembler::reg_pre(int Rm, int W)
+uint32_t ArmToArm64Assembler::reg_pre(int Rm, int W)
{
if(W != 0)
{
@@ -975,7 +975,7 @@
}
}
-uint32_t ArmToAarch64Assembler::reg_post(int Rm)
+uint32_t ArmToArm64Assembler::reg_post(int Rm)
{
NOT_IMPLEMENTED(); //Not required
return OPERAND_UNSUPPORTED;
@@ -999,7 +999,7 @@
((0x38u << 24) | (0x1 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
((0x78u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11))
};
-uint32_t ArmToAarch64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
+uint32_t ArmToArm64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
uint32_t size, uint32_t Rt,
uint32_t Rn, uint32_t Rm)
{
@@ -1017,7 +1017,7 @@
}
}
-uint32_t ArmToAarch64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
+uint32_t ArmToArm64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
uint32_t Rn, int32_t simm)
{
if(Rn == 31)
@@ -1029,7 +1029,7 @@
return (0xB8 << 24) | (imm9 << 12) | (0x3 << 10) | (Rn << 5) | Rt;
}
-uint32_t ArmToAarch64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
+uint32_t ArmToArm64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
uint32_t Rn, int32_t simm)
{
if(Rn == 31)
@@ -1042,7 +1042,7 @@
(imm9 << 12) | (0x1 << 10) | (Rn << 5) | Rt;
}
-uint32_t ArmToAarch64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
+uint32_t ArmToArm64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
uint32_t Rn,
uint32_t Rm,
uint32_t amount)
@@ -1053,7 +1053,7 @@
}
-uint32_t ArmToAarch64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
+uint32_t ArmToArm64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
uint32_t Rn,
uint32_t Rm,
uint32_t amount)
@@ -1064,13 +1064,13 @@
}
-uint32_t ArmToAarch64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
+uint32_t ArmToArm64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
{
LOG_INSTR("B.%s #.+%d\n", cc_codes[cc], offset);
return (0x54 << 24) | ((offset/4) << 5) | (cc);
}
-uint32_t ArmToAarch64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount)
{
@@ -1079,21 +1079,21 @@
return ((0x8B << 24) | (shift << 22) | ( Rm << 16) |
(amount << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
uint32_t imm, uint32_t shift)
{
LOG_INSTR("ADD X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
return (0x91 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
}
-uint32_t ArmToAarch64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
uint32_t imm, uint32_t shift)
{
LOG_INSTR("SUB X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
return (0xD1 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
}
-uint32_t ArmToAarch64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount)
{
@@ -1103,7 +1103,7 @@
(amount << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount,
uint32_t setflag)
@@ -1124,7 +1124,7 @@
}
}
-uint32_t ArmToAarch64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount)
{
@@ -1134,7 +1134,7 @@
(amount << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount)
{
@@ -1144,7 +1144,7 @@
(amount << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t shift,
uint32_t amount)
{
@@ -1154,76 +1154,76 @@
(amount << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t cond)
{
LOG_INSTR("CSEL X%d, X%d, X%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
return ((0x9A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t cond)
{
LOG_INSTR("CSEL W%d, W%d, W%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
return ((0x1A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_RET(uint32_t Rn)
+uint32_t ArmToArm64Assembler::A64_RET(uint32_t Rn)
{
LOG_INSTR("RET X%d\n", Rn);
return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
}
-uint32_t ArmToAarch64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
+uint32_t ArmToArm64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
uint32_t shift)
{
LOG_INSTR("MOVZ X%d, #0x%x, LSL #%d\n", Rd, imm, shift);
return(0xD2 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
}
-uint32_t ArmToAarch64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
+uint32_t ArmToArm64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
uint32_t shift)
{
LOG_INSTR("MOVK W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
return (0x72 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
}
-uint32_t ArmToAarch64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
+uint32_t ArmToArm64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
uint32_t shift)
{
LOG_INSTR("MOVZ W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
return(0x52 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
}
-uint32_t ArmToAarch64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t Ra)
{
LOG_INSTR("SMADDL X%d, W%d, W%d, X%d\n",Rd, Rn, Rm, Ra);
return ((0x9B << 24) | (0x1 << 21) | (Rm << 16)|(Ra << 10)|(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t Ra)
{
LOG_INSTR("MADD W%d, W%d, W%d, W%d\n",Rd, Rn, Rm, Ra);
return ((0x1B << 24) | (Rm << 16) | (Ra << 10) |(Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
uint32_t immr, uint32_t imms)
{
LOG_INSTR("SBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
return ((0x13 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
uint32_t immr, uint32_t imms)
{
LOG_INSTR("UBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
return ((0x53 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
uint32_t immr, uint32_t imms)
{
LOG_INSTR("UBFM X%d, X%d, #%d, #%d\n", Rd, Rn, immr, imms);
@@ -1231,7 +1231,7 @@
(immr << 16) | (imms << 10) | (Rn << 5) | Rd);
}
-uint32_t ArmToAarch64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
+uint32_t ArmToArm64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
uint32_t Rm, uint32_t lsb)
{
LOG_INSTR("EXTR W%d, W%d, W%d, #%d\n", Rd, Rn, Rm, lsb);
diff --git a/libpixelflinger/codeflinger/Aarch64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
similarity index 95%
rename from libpixelflinger/codeflinger/Aarch64Assembler.h
rename to libpixelflinger/codeflinger/Arm64Assembler.h
index 79c912b..8479270 100644
--- a/libpixelflinger/codeflinger/Aarch64Assembler.h
+++ b/libpixelflinger/codeflinger/Arm64Assembler.h
@@ -26,8 +26,8 @@
* SUCH DAMAGE.
*/
-#ifndef ANDROID_ARMTOAARCH64ASSEMBLER_H
-#define ANDROID_ARMTOAARCH64ASSEMBLER_H
+#ifndef ANDROID_ARMTOARM64ASSEMBLER_H
+#define ANDROID_ARMTOARM64ASSEMBLER_H
#include <stdint.h>
#include <sys/types.h>
@@ -44,12 +44,12 @@
// ----------------------------------------------------------------------------
-class ArmToAarch64Assembler : public ARMAssemblerInterface
+class ArmToArm64Assembler : public ARMAssemblerInterface
{
public:
- ArmToAarch64Assembler(const sp<Assembly>& assembly);
- ArmToAarch64Assembler(void *base);
- virtual ~ArmToAarch64Assembler();
+ ArmToArm64Assembler(const sp<Assembly>& assembly);
+ ArmToArm64Assembler(void *base);
+ virtual ~ArmToArm64Assembler();
uint32_t* base() const;
uint32_t* pc() const;
@@ -176,8 +176,8 @@
virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
private:
- ArmToAarch64Assembler(const ArmToAarch64Assembler& rhs);
- ArmToAarch64Assembler& operator = (const ArmToAarch64Assembler& rhs);
+ ArmToArm64Assembler(const ArmToArm64Assembler& rhs);
+ ArmToArm64Assembler& operator = (const ArmToArm64Assembler& rhs);
// -----------------------------------------------------------------------
// helper functions
@@ -189,7 +189,7 @@
int Rd, int Rn, uint32_t Op2);
// -----------------------------------------------------------------------
- // Aarch64 instructions
+ // Arm64 instructions
// -----------------------------------------------------------------------
uint32_t A64_B_COND(uint32_t cc, uint32_t offset);
uint32_t A64_RET(uint32_t Rn);
@@ -287,4 +287,4 @@
}; // namespace android
-#endif //ANDROID_AARCH64ASSEMBLER_H
+#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/Aarch64Disassembler.cpp b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
similarity index 99%
rename from libpixelflinger/codeflinger/Aarch64Disassembler.cpp
rename to libpixelflinger/codeflinger/Arm64Disassembler.cpp
index 4bb97b4..70f1ff1 100644
--- a/libpixelflinger/codeflinger/Aarch64Disassembler.cpp
+++ b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
@@ -267,7 +267,7 @@
return;
}
-int aarch64_disassemble(uint32_t code, char* instr)
+int arm64_disassemble(uint32_t code, char* instr)
{
uint32_t i;
char token[256];
diff --git a/libpixelflinger/codeflinger/Aarch64Disassembler.h b/libpixelflinger/codeflinger/Arm64Disassembler.h
similarity index 89%
rename from libpixelflinger/codeflinger/Aarch64Disassembler.h
rename to libpixelflinger/codeflinger/Arm64Disassembler.h
index 177d692..86f3aba 100644
--- a/libpixelflinger/codeflinger/Aarch64Disassembler.h
+++ b/libpixelflinger/codeflinger/Arm64Disassembler.h
@@ -26,10 +26,10 @@
* SUCH DAMAGE.
*/
-#ifndef ANDROID_AARCH64DISASSEMBLER_H
-#define ANDROID_AARCH64DISASSEMBLER_H
+#ifndef ANDROID_ARM64DISASSEMBLER_H
+#define ANDROID_ARM64DISASSEMBLER_H
#include <inttypes.h>
-int aarch64_disassemble(uint32_t code, char* instr);
+int arm64_disassemble(uint32_t code, char* instr);
-#endif //ANDROID_AARCH64ASSEMBLER_H
+#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
index 7f088db..2422d7b 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ b/libpixelflinger/codeflinger/GGLAssembler.cpp
@@ -901,7 +901,7 @@
AND( AL, 0, d, s, imm(mask) );
return;
}
- else if (getCodegenArch() == CODEGEN_ARCH_AARCH64) {
+ else if (getCodegenArch() == CODEGEN_ARCH_ARM64) {
AND( AL, 0, d, s, imm(mask) );
return;
}
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index bc774f3..aa23ca6 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -34,7 +34,7 @@
#if defined(__arm__)
#include "codeflinger/ARMAssembler.h"
#elif defined(__aarch64__)
-#include "codeflinger/Aarch64Assembler.h"
+#include "codeflinger/Arm64Assembler.h"
#elif defined(__mips__)
#include "codeflinger/MIPSAssembler.h"
#endif
@@ -128,8 +128,8 @@
extern "C" void scanline_col32cb16blend_neon(uint16_t *dst, uint32_t *col, size_t ct);
extern "C" void scanline_col32cb16blend_arm(uint16_t *dst, uint32_t col, size_t ct);
#elif defined(__aarch64__)
-extern "C" void scanline_t32cb16blend_aarch64(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_col32cb16blend_aarch64(uint16_t *dst, uint32_t col, size_t ct);
+extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
+extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
#elif defined(__mips__)
extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
#endif
@@ -405,7 +405,7 @@
#if defined(__mips__)
GGLAssembler assembler( new ArmToMipsAssembler(a) );
#elif defined(__aarch64__)
- GGLAssembler assembler( new ArmToAarch64Assembler(a) );
+ GGLAssembler assembler( new ArmToArm64Assembler(a) );
#endif
// generate the scanline code for the given needs
int err = assembler.scanline(c->state.needs, c);
@@ -2098,7 +2098,7 @@
scanline_col32cb16blend_arm(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
#endif // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__aarch64__))
- scanline_col32cb16blend_aarch64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
+ scanline_col32cb16blend_arm64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
#else
uint32_t s = GGL_RGBA_TO_HOST(c->packed8888);
int sA = (s>>24);
@@ -2186,7 +2186,7 @@
#ifdef __arm__
scanline_t32cb16blend_arm(dst, src, ct);
#elif defined(__aarch64__)
- scanline_t32cb16blend_aarch64(dst, src, ct);
+ scanline_t32cb16blend_arm64(dst, src, ct);
#elif defined(__mips__)
scanline_t32cb16blend_mips(dst, src, ct);
#endif
diff --git a/libpixelflinger/tests/arch-aarch64/Android.mk b/libpixelflinger/tests/arch-aarch64/Android.mk
deleted file mode 100644
index f096491..0000000
--- a/libpixelflinger/tests/arch-aarch64/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-ifeq ($(TARGET_ARCH),aarch64)
-include $(all-subdir-makefiles)
-endif
diff --git a/libpixelflinger/tests/arch-arm64/Android.mk b/libpixelflinger/tests/arch-arm64/Android.mk
new file mode 100644
index 0000000..ca58b4b
--- /dev/null
+++ b/libpixelflinger/tests/arch-arm64/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(TARGET_ARCH),arm64)
+include $(all-subdir-makefiles)
+endif
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
similarity index 75%
rename from libpixelflinger/tests/arch-aarch64/assembler/Android.mk
rename to libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 10e06c4..36db49c 100644
--- a/libpixelflinger/tests/arch-aarch64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- aarch64_assembler_test.cpp\
+ arm64_assembler_test.cpp\
asm_test_jacket.S
LOCAL_SHARED_LIBRARIES := \
@@ -12,7 +12,7 @@
LOCAL_C_INCLUDES := \
system/core/libpixelflinger
-LOCAL_MODULE:= test-pixelflinger-aarch64-assembler-test
+LOCAL_MODULE:= test-pixelflinger-arm64-assembler-test
LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
similarity index 99%
rename from libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp
rename to libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
index d3e57b3..84381d5 100644
--- a/libpixelflinger/tests/arch-aarch64/assembler/aarch64_assembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
@@ -40,7 +40,7 @@
#include <inttypes.h>
#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/Aarch64Assembler.h"
+#include "codeflinger/Arm64Assembler.h"
using namespace android;
#define TESTS_DATAOP_ENABLE 1
@@ -712,7 +712,7 @@
{
uint32_t i;
- /* Allocate memory to store instructions generated by ArmToAarch64Assembler */
+ /* Allocate memory to store instructions generated by ArmToArm64Assembler */
{
int fd = ashmem_create_region("code cache", instrMemSize);
if(fd < 0)
@@ -723,7 +723,7 @@
MAP_PRIVATE, fd, 0);
}
- ArmToAarch64Assembler a64asm(instrMem);
+ ArmToArm64Assembler a64asm(instrMem);
if(TESTS_DATAOP_ENABLE)
{
diff --git a/libpixelflinger/tests/arch-aarch64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
similarity index 100%
rename from libpixelflinger/tests/arch-aarch64/assembler/asm_test_jacket.S
rename to libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
diff --git a/libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
similarity index 67%
rename from libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk
rename to libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index 7445fc8..ac890c7 100644
--- a/libpixelflinger/tests/arch-aarch64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -3,13 +3,13 @@
LOCAL_SRC_FILES:= \
col32cb16blend_test.c \
- ../../../arch-aarch64/col32cb16blend.S
+ ../../../arch-arm64/col32cb16blend.S
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES :=
-LOCAL_MODULE:= test-pixelflinger-aarch64-col32cb16blend
+LOCAL_MODULE:= test-pixelflinger-arm64-col32cb16blend
LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
similarity index 95%
rename from libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c
rename to libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
index f057884..c6a3017 100644
--- a/libpixelflinger/tests/arch-aarch64/col32cb16blend/col32cb16blend_test.c
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
@@ -60,7 +60,7 @@
{"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
};
-void scanline_col32cb16blend_aarch64(uint16_t *dst, int32_t src, size_t count);
+void scanline_col32cb16blend_arm64(uint16_t *dst, int32_t src, size_t count);
void scanline_col32cb16blend_c(uint16_t * dst, int32_t src, size_t count)
{
int srcAlpha = (src>>24);
@@ -103,7 +103,7 @@
scanline_col32cb16blend_c(dst_c, test.src_color, test.count);
- scanline_col32cb16blend_aarch64(dst_asm, test.src_color, test.count);
+ scanline_col32cb16blend_arm64(dst_asm, test.src_color, test.count);
if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
diff --git a/libpixelflinger/tests/arch-aarch64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
similarity index 61%
rename from libpixelflinger/tests/arch-aarch64/disassembler/Android.mk
rename to libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index 376c3b7..baf4070 100644
--- a/libpixelflinger/tests/arch-aarch64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -2,15 +2,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- aarch64_diassembler_test.cpp \
- ../../../codeflinger/Aarch64Disassembler.cpp
+ arm64_diassembler_test.cpp \
+ ../../../codeflinger/Arm64Disassembler.cpp
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES := \
system/core/libpixelflinger/codeflinger
-LOCAL_MODULE:= test-pixelflinger-aarch64-disassembler-test
+LOCAL_MODULE:= test-pixelflinger-arm64-disassembler-test
LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp b/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
similarity index 98%
rename from libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp
rename to libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
index 17caee1..af3183b 100644
--- a/libpixelflinger/tests/arch-aarch64/disassembler/aarch64_diassembler_test.cpp
+++ b/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
@@ -29,7 +29,7 @@
#include <inttypes.h>
#include <string.h>
-int aarch64_disassemble(uint32_t code, char* instr);
+int arm64_disassemble(uint32_t code, char* instr);
struct test_table_entry_t
{
@@ -298,7 +298,7 @@
{
test_table_entry_t *test;
test = &test_table[i];
- aarch64_disassemble(test->code, instr);
+ arm64_disassemble(test->code, instr);
if(strcmp(instr, test->instr) != 0)
{
printf("Test Failed \n"
diff --git a/libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
similarity index 68%
rename from libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk
rename to libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index a67f0e3..1cce1bd 100644
--- a/libpixelflinger/tests/arch-aarch64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -3,13 +3,13 @@
LOCAL_SRC_FILES:= \
t32cb16blend_test.c \
- ../../../arch-aarch64/t32cb16blend.S
+ ../../../arch-arm64/t32cb16blend.S
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES :=
-LOCAL_MODULE:= test-pixelflinger-aarch64-t32cb16blend
+LOCAL_MODULE:= test-pixelflinger-arm64-t32cb16blend
LOCAL_MODULE_TAGS := tests
diff --git a/libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
similarity index 96%
rename from libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c
rename to libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
index bcde3e6..afb36fb 100644
--- a/libpixelflinger/tests/arch-aarch64/t32cb16blend/t32cb16blend_test.c
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
@@ -61,7 +61,7 @@
};
-void scanline_t32cb16blend_aarch64(uint16_t*, uint32_t*, size_t);
+void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
void scanline_t32cb16blend_c(uint16_t * dst, uint32_t* src, size_t count)
{
while (count--)
@@ -112,7 +112,7 @@
}
scanline_t32cb16blend_c(dst_c,src,test.count);
- scanline_t32cb16blend_aarch64(dst_asm,src,test.count);
+ scanline_t32cb16blend_arm64(dst_asm,src,test.count);
if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index e8a4f5e..e9f6c61 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -10,7 +10,7 @@
#include "codeflinger/GGLAssembler.h"
#include "codeflinger/ARMAssembler.h"
#include "codeflinger/MIPSAssembler.h"
-#include "codeflinger/Aarch64Assembler.h"
+#include "codeflinger/Arm64Assembler.h"
#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
# define ANDROID_ARM_CODEGEN 1
@@ -57,7 +57,7 @@
#endif
#if defined(__aarch64__)
- GGLAssembler assembler( new ArmToAarch64Assembler(a) );
+ GGLAssembler assembler( new ArmToArm64Assembler(a) );
#endif
int err = assembler.scanline(needs, (context_t*)c);
@@ -66,7 +66,7 @@
}
gglUninit(c);
#else
- printf("This test runs only on ARM, Aarch64 or MIPS\n");
+ printf("This test runs only on ARM, Arm64 or MIPS\n");
#endif
}
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
index 103e4e9..073368e 100644
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ b/libpixelflinger/tests/gglmul/gglmul_test.cpp
@@ -225,8 +225,6 @@
}
// gglMulii() tests
-const int32_t INT32_MAX = 0x7FFFFFFF;
-const int32_t INT32_MIN = 0x80000000;
struct gglMulii_test_t
{
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index a28b0a5..e63c4a9 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -18,6 +18,7 @@
#define _LARGEFILE64_SOURCE 1
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
@@ -342,7 +343,7 @@
int ret, chunk;
if (skip_len % out->block_size) {
- error("don't care size %llu is not a multiple of the block size %u",
+ error("don't care size %"PRIi64" is not a multiple of the block size %u",
skip_len, out->block_size);
return -1;
}
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 1d396b2..1451b0d 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -16,7 +16,7 @@
LOCAL_MODULE:= libsysutils
-LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+LOCAL_C_INCLUDES :=
LOCAL_CFLAGS :=
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 720443e..1710d36 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -116,10 +116,12 @@
libcutils
LOCAL_SHARED_LIBRARIES := \
- libcorkscrew \
+ libbacktrace \
liblog \
libdl
+include external/stlport/libstlport.mk
+
LOCAL_MODULE:= libutils
include $(BUILD_STATIC_LIBRARY)
@@ -129,10 +131,12 @@
LOCAL_MODULE:= libutils
LOCAL_WHOLE_STATIC_LIBRARIES := libutils
LOCAL_SHARED_LIBRARIES := \
- liblog \
+ libbacktrace \
libcutils \
libdl \
- libcorkscrew
+ liblog \
+
+include external/stlport/libstlport.mk
include $(BUILD_SHARED_LIBRARY)
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index 4ceaa7c..0bfb520 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -20,93 +20,33 @@
#include <utils/Printer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <corkscrew/backtrace.h>
+#include <UniquePtr.h>
+
+#include <backtrace/Backtrace.h>
namespace android {
-CallStack::CallStack() :
- mCount(0) {
+CallStack::CallStack() {
}
-CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
- this->update(ignoreDepth+1, maxDepth, CURRENT_THREAD);
+CallStack::CallStack(const char* logtag, int32_t ignoreDepth) {
+ this->update(ignoreDepth+1);
this->log(logtag);
}
-CallStack::CallStack(const CallStack& rhs) :
- mCount(rhs.mCount) {
- if (mCount) {
- memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
- }
-}
-
CallStack::~CallStack() {
}
-CallStack& CallStack::operator = (const CallStack& rhs) {
- mCount = rhs.mCount;
- if (mCount) {
- memcpy(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t));
+void CallStack::update(int32_t ignoreDepth, pid_t tid) {
+ mFrameLines.clear();
+
+ UniquePtr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
+ if (!backtrace->Unwind(ignoreDepth)) {
+ ALOGW("%s: Failed to unwind callstack.", __FUNCTION__);
}
- return *this;
-}
-
-bool CallStack::operator == (const CallStack& rhs) const {
- if (mCount != rhs.mCount)
- return false;
- return !mCount || memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) == 0;
-}
-
-bool CallStack::operator != (const CallStack& rhs) const {
- return !operator == (rhs);
-}
-
-bool CallStack::operator < (const CallStack& rhs) const {
- if (mCount != rhs.mCount)
- return mCount < rhs.mCount;
- return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) < 0;
-}
-
-bool CallStack::operator >= (const CallStack& rhs) const {
- return !operator < (rhs);
-}
-
-bool CallStack::operator > (const CallStack& rhs) const {
- if (mCount != rhs.mCount)
- return mCount > rhs.mCount;
- return memcmp(mStack, rhs.mStack, mCount * sizeof(backtrace_frame_t)) > 0;
-}
-
-bool CallStack::operator <= (const CallStack& rhs) const {
- return !operator > (rhs);
-}
-
-const void* CallStack::operator [] (int index) const {
- if (index >= int(mCount))
- return 0;
- return reinterpret_cast<const void*>(mStack[index].absolute_pc);
-}
-
-void CallStack::clear() {
- mCount = 0;
-}
-
-void CallStack::update(int32_t ignoreDepth, int32_t maxDepth, pid_t tid) {
- if (maxDepth > MAX_DEPTH) {
- maxDepth = MAX_DEPTH;
+ for (size_t i = 0; i < backtrace->NumFrames(); i++) {
+ mFrameLines.push_back(String8(backtrace->FormatFrameData(i).c_str()));
}
- ssize_t count;
-
- if (tid >= 0) {
- count = unwind_backtrace_thread(tid, mStack, ignoreDepth + 1, maxDepth);
- } else if (tid == CURRENT_THREAD) {
- count = unwind_backtrace(mStack, ignoreDepth + 1, maxDepth);
- } else {
- ALOGE("%s: Invalid tid specified (%d)", __FUNCTION__, tid);
- count = 0;
- }
-
- mCount = count > 0 ? count : 0;
}
void CallStack::log(const char* logtag, android_LogPriority priority, const char* prefix) const {
@@ -129,16 +69,9 @@
}
void CallStack::print(Printer& printer) const {
- backtrace_symbol_t symbols[mCount];
-
- get_backtrace_symbols(mStack, mCount, symbols);
- for (size_t i = 0; i < mCount; i++) {
- char line[MAX_BACKTRACE_LINE_LENGTH];
- format_backtrace_line(i, &mStack[i], &symbols[i],
- line, MAX_BACKTRACE_LINE_LENGTH);
- printer.printLine(line);
+ for (size_t i = 0; i < mFrameLines.size(); i++) {
+ printer.printLine(mFrameLines[i]);
}
- free_backtrace_symbols(symbols, mCount);
}
}; // namespace android
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index ac729e0..263e740 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -145,6 +145,7 @@
return;
}
+ mTarget->append(mPrefix);
mTarget->append(string);
mTarget->append("\n");
}
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index f9340c5..f837bcb 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -123,7 +123,7 @@
mTimeUpdated = tm();
}
-void ProcessCallStack::update(int32_t maxDepth) {
+void ProcessCallStack::update() {
DIR *dp;
struct dirent *ep;
struct dirent entry;
@@ -181,14 +181,13 @@
int ignoreDepth = (selfPid == tid) ? IGNORE_DEPTH_CURRENT_THREAD : 0;
// Update thread's call stacks
- CallStack& cs = threadInfo.callStack;
- cs.update(ignoreDepth, maxDepth, tid);
+ threadInfo.callStack.update(ignoreDepth, tid);
// Read/save thread name
threadInfo.threadName = getThreadName(tid);
ALOGV("%s: Got call stack for tid %d (size %zu)",
- __FUNCTION__, tid, cs.size());
+ __FUNCTION__, tid, threadInfo.callStack.size());
}
if (code != 0) { // returns positive error value on error
ALOGE("%s: Failed to readdir from %s (errno = %d, '%s')",
@@ -221,13 +220,12 @@
for (size_t i = 0; i < mThreadMap.size(); ++i) {
pid_t tid = mThreadMap.keyAt(i);
const ThreadInfo& threadInfo = mThreadMap.valueAt(i);
- const CallStack& cs = threadInfo.callStack;
const String8& threadName = threadInfo.threadName;
printer.printLine("");
printer.printFormatLine("\"%s\" sysTid=%d", threadName.string(), tid);
- cs.print(csPrinter);
+ threadInfo.callStack.print(csPrinter);
}
dumpProcessFooter(printer, getpid());
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 8436d49..a23d4ae 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -756,7 +756,7 @@
}
const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
- if (data_offset >= cd_offset) {
+ if (data_offset > cd_offset) {
ALOGW("Zip: bad data offset %lld in zip", (off64_t) data_offset);
return kInvalidOffset;
}
@@ -1021,6 +1021,13 @@
return kIoError;
}
+ // Don't attempt to map a region of length 0. We still need the
+ // ftruncate() though, since the API guarantees that we will truncate
+ // the file to the end of the uncompressed output.
+ if (declared_length == 0) {
+ return 0;
+ }
+
android::FileMap* map = MapFileSegment(fd, current_offset, declared_length,
false, kTempMappingFileName);
if (map == NULL) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 022be5b..3082216 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -140,8 +140,45 @@
CloseArchive(handle);
}
+TEST(ziparchive, EmptyEntries) {
+ char temp_file_pattern[] = "empty_entries_test_XXXXXX";
+ int fd = mkstemp(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+ const uint32_t data[] = {
+ 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
+ 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
+ 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
+ 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
+ 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
+ 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
+ 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
+ const ssize_t file_size = 168;
+ ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+
+ ZipEntry entry;
+ ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
+ ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
+ uint8_t buffer[1];
+ ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
+
+ char output_file_pattern[] = "empty_entries_output_XXXXXX";
+ int output_fd = mkstemp(output_file_pattern);
+ ASSERT_NE(-1, output_fd);
+ ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+ struct stat stat_buf;
+ ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+ ASSERT_EQ(0, stat_buf.st_size);
+
+ close(fd);
+ close(output_fd);
+}
+
TEST(ziparchive, ExtractToFile) {
- char kTempFilePattern[] = "zip_archive_test_XXXXXX";
+ char kTempFilePattern[] = "zip_archive_input_XXXXXX";
int fd = mkstemp(kTempFilePattern);
ASSERT_NE(-1, fd);
const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d44c679..4c6139c 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -298,7 +298,7 @@
}
else if (entry->entry.len != ret - sizeof(struct logger_entry)) {
fprintf(stderr, "read: unexpected length. Expected %d, got %d\n",
- entry->entry.len, ret - sizeof(struct logger_entry));
+ entry->entry.len, ret - (int) sizeof(struct logger_entry));
exit(EXIT_FAILURE);
}
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index db6cb4c..9e0385d 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -90,7 +90,8 @@
}
if (seg_fault_on_exit) {
- *(int *)status = 0; // causes SIGSEGV with fault_address = status
+ uintptr_t fault_address = (uintptr_t) status;
+ *(int *) fault_address = 0; // causes SIGSEGV with fault_address = status
}
return rc;
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index d2f74c0..927c33d 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -1,7 +1,6 @@
# set up the global environment
on init
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
- export LD_LIBRARY_PATH /vendor/lib:/system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1129206..a32366c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -222,6 +222,7 @@
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
+ restorecon_recursive /data/misc/media
# Set security context of any pre-existing /data/misc/adb/adb_keys file.
restorecon /data/misc/adb
@@ -257,6 +258,7 @@
# create directory for MediaDrm plug-ins - give drm the read/write access to
# the following directory.
mkdir /data/mediadrm 0770 mediadrm mediadrm
+ restorecon_recursive /data/mediadrm
# symlink to bugreport storage location
symlink /data/data/com.android.shell/files/bugreports /data/bugreports
@@ -440,7 +442,7 @@
start console
# adbd is controlled via property triggers in init.<platform>.usb.rc
-service adbd /sbin/adbd
+service adbd /sbin/adbd --root_seclabel=u:r:su:s0
class core
socket adbd stream 660 system system
disabled
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index 8a05fd0..50944e6 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -9,6 +9,7 @@
chown root shell /sys/kernel/debug/tracing/trace_clock
chown root shell /sys/kernel/debug/tracing/buffer_size_kb
chown root shell /sys/kernel/debug/tracing/options/overwrite
+ chown root shell /sys/kernel/debug/tracing/options/print-tgid
chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
@@ -20,6 +21,7 @@
chmod 0664 /sys/kernel/debug/tracing/trace_clock
chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
chmod 0664 /sys/kernel/debug/tracing/options/overwrite
+ chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 75ce53f..4fff9f5 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -12,7 +12,6 @@
rmmod \
lsmod \
ifconfig \
- setconsole \
rm \
mkdir \
rmdir \
@@ -89,6 +88,8 @@
LOCAL_C_INCLUDES := bionic/libc/bionic
+LOCAL_CFLAGS += -Wno-unused-parameter
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
diff --git a/toolbox/date.c b/toolbox/date.c
index ed307c0..d6c9052 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -16,7 +16,7 @@
if (fd < 0)
return fd;
- ret = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
+ ret = ioctl(fd, ANDROID_ALARM_SET_RTC, ts);
close(fd);
return ret;
}
diff --git a/toolbox/dd.c b/toolbox/dd.c
index a8c12d2..6b61ffb 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -92,9 +92,6 @@
extern int progress;
extern const u_char *ctab;
-
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define DEFFILEMODE (S_IRUSR | S_IWUSR)
static void dd_close(void);
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index 5f5e16b..ed381f5 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -166,7 +166,7 @@
if(bit_labels && (print_flags & PRINT_LABELS)) {
bit_label = get_label(bit_labels, j * 8 + k);
if(bit_label)
- printf(" %.20s%c%*s", bit_label, down, 20 - strlen(bit_label), "");
+ printf(" %.20s%c%*s", bit_label, down, (int) (20 - strlen(bit_label)), "");
else
printf(" %04x%c ", j * 8 + k, down);
} else {
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
index 756a64b..fb1448b 100644
--- a/toolbox/insmod.c
+++ b/toolbox/insmod.c
@@ -4,6 +4,7 @@
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -45,7 +46,6 @@
return buffer;
}
-#define min(x,y) ((x) < (y) ? (x) : (y))
int insmod_main(int argc, char **argv)
{
void *file;
@@ -73,7 +73,7 @@
char *ptr = opts;
for (i = 2; (i < argc) && (ptr < end); i++) {
- len = min(strlen(argv[i]), end - ptr);
+ len = MIN(strlen(argv[i]), end - ptr);
memcpy(ptr, argv[i], len);
ptr += len;
*ptr++ = ' ';
diff --git a/toolbox/ls.c b/toolbox/ls.c
index c740f84..3cc5bb2 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -182,8 +182,8 @@
mode2str(s->st_mode, mode);
if (flags & LIST_LONG_NUMERIC) {
- snprintf(user, sizeof(user), "%ld", s->st_uid);
- snprintf(group, sizeof(group), "%ld", s->st_gid);
+ snprintf(user, sizeof(user), "%u", s->st_uid);
+ snprintf(group, sizeof(group), "%u", s->st_gid);
} else {
user2str(s->st_uid, user, sizeof(user));
group2str(s->st_gid, group, sizeof(group));
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index 4666f26..d43b2fe 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -158,7 +158,7 @@
printf("oobavail: %u\n", ecclayout.oobavail);
}
if (ecclayout.oobavail > spare_size)
- printf("oobavail, %d > image spare size, %d\n", ecclayout.oobavail, spare_size);
+ printf("oobavail, %d > image spare size, %zu\n", ecclayout.oobavail, spare_size);
ret = ioctl(fd, ECCGETSTATS, &initial_ecc);
if (ret) {
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 6d78eb6..27dca42 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -234,13 +234,6 @@
static void setstr(u_int8_t *, const char *, size_t);
static void usage(void);
-#ifdef ANDROID
-#define powerof2(x) ((((x) - 1) & (x)) == 0)
-#define howmany(x, y) (((x) + ((y) - 1)) / (y))
-#define MAX(x,y) ((x) > (y) ? (x) : (y))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-#endif
/*
* Construct a FAT12, FAT16, or FAT32 file system.
*/
diff --git a/toolbox/r.c b/toolbox/r.c
index eb8ea0b..3b80db7 100644
--- a/toolbox/r.c
+++ b/toolbox/r.c
@@ -1,8 +1,16 @@
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include <sys/mman.h>
-#include <fcntl.h>
#include <string.h>
+#include <sys/mman.h>
+
+#if __LP64__
+#define strtoptr strtoull
+#else
+#define strtoptr strtoul
+#endif
static int usage()
{
@@ -12,14 +20,9 @@
int r_main(int argc, char *argv[])
{
- int width = 4, set = 0, fd;
- unsigned addr, value, endaddr = 0;
- unsigned long mmap_start, mmap_size;
- void *page;
- char *end;
-
if(argc < 2) return usage();
+ int width = 4;
if(!strcmp(argv[1], "-b")) {
width = 1;
argc--;
@@ -31,37 +34,40 @@
}
if(argc < 2) return usage();
- addr = strtoul(argv[1], 0, 16);
+ uintptr_t addr = strtoptr(argv[1], 0, 16);
- end = strchr(argv[1], '-');
+ uintptr_t endaddr = 0;
+ char* end = strchr(argv[1], '-');
if (end)
- endaddr = strtoul(end + 1, 0, 16);
+ endaddr = strtoptr(end + 1, 0, 16);
if (!endaddr)
endaddr = addr + width - 1;
if (endaddr <= addr) {
- fprintf(stderr, "invalid end address\n");
+ fprintf(stderr, "end address <= start address\n");
return -1;
}
+ bool set = false;
+ uint32_t value = 0;
if(argc > 2) {
- set = 1;
+ set = true;
value = strtoul(argv[2], 0, 16);
}
- fd = open("/dev/mem", O_RDWR | O_SYNC);
+ int fd = open("/dev/mem", O_RDWR | O_SYNC);
if(fd < 0) {
fprintf(stderr,"cannot open /dev/mem\n");
return -1;
}
-
- mmap_start = addr & ~(PAGE_SIZE - 1);
- mmap_size = endaddr - mmap_start + 1;
+
+ off64_t mmap_start = addr & ~(PAGE_SIZE - 1);
+ size_t mmap_size = endaddr - mmap_start + 1;
mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
- page = mmap(0, mmap_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, mmap_start);
+ void* page = mmap64(0, mmap_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, mmap_start);
if(page == MAP_FAILED){
fprintf(stderr,"cannot mmap region\n");
@@ -71,21 +77,21 @@
while (addr <= endaddr) {
switch(width){
case 4: {
- unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
+ uint32_t* x = (uint32_t*) (((uintptr_t) page) + (addr & 4095));
if(set) *x = value;
- fprintf(stderr,"%08x: %08x\n", addr, *x);
+ fprintf(stderr,"%08"PRIxPTR": %08x\n", addr, *x);
break;
}
case 2: {
- unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
+ uint16_t* x = (uint16_t*) (((uintptr_t) page) + (addr & 4095));
if(set) *x = value;
- fprintf(stderr,"%08x: %04x\n", addr, *x);
+ fprintf(stderr,"%08"PRIxPTR": %04x\n", addr, *x);
break;
}
case 1: {
- unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
+ uint8_t* x = (uint8_t*) (((uintptr_t) page) + (addr & 4095));
if(set) *x = value;
- fprintf(stderr,"%08x: %02x\n", addr, *x);
+ fprintf(stderr,"%08"PRIxPTR": %02x\n", addr, *x);
break;
}
}
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
index 6859b50..a76f968 100644
--- a/toolbox/schedtop.c
+++ b/toolbox/schedtop.c
@@ -212,7 +212,7 @@
}
if (!(flags & FLAG_BATCH))
printf("\e[H\e[0J");
- printf("Processes: %d, Threads %d\n", processes.active, threads.active);
+ printf("Processes: %zu, Threads %zu\n", processes.active, threads.active);
switch (time_dp) {
case 3:
printf(" TID --- SINCE LAST ---- ---------- TOTAL ----------\n");
diff --git a/toolbox/setconsole.c b/toolbox/setconsole.c
deleted file mode 100644
index 0159c07..0000000
--- a/toolbox/setconsole.c
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <errno.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-static int activate_thread_switch_vc;
-static void *activate_thread(void *arg)
-{
- int res;
- int fd = (int)arg;
- while(activate_thread_switch_vc >= 0) {
- do {
- res = ioctl(fd, VT_ACTIVATE, (void*)activate_thread_switch_vc);
- } while(res < 0 && errno == EINTR);
- if (res < 0) {
- fprintf(stderr, "ioctl( vcfd, VT_ACTIVATE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), activate_thread_switch_vc);
- }
- if(activate_thread_switch_vc >= 0)
- sleep(1);
- }
- return NULL;
-}
-
-
-int setconsole_main(int argc, char *argv[])
-{
- int c;
- int fd;
- int res;
-
- int mode = -1;
- int new_vc = 0;
- int close_vc = 0;
- int switch_vc = -1;
- int printvc = 0;
- char *ttydev = "/dev/tty0";
-
- do {
- c = getopt(argc, argv, "d:gtncv:poh");
- if (c == EOF)
- break;
- switch (c) {
- case 'd':
- ttydev = optarg;
- break;
- case 'g':
- if(mode == KD_TEXT) {
- fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
- exit(1);
- }
- mode = KD_GRAPHICS;
- break;
- case 't':
- if(mode == KD_GRAPHICS) {
- fprintf(stderr, "%s: cannot specify both -g and -t\n", argv[0]);
- exit(1);
- }
- mode = KD_TEXT;
- break;
- case 'n':
- new_vc = 1;
- break;
- case 'c':
- close_vc = 1;
- break;
- case 'v':
- switch_vc = atoi(optarg);
- break;
- case 'p':
- printvc |= 1;
- break;
- case 'o':
- printvc |= 2;
- break;
- case 'h':
- fprintf(stderr, "%s [-d <dev>] [-v <vc>] [-gtncpoh]\n"
- " -d <dev> Use <dev> instead of /dev/tty0\n"
- " -v <vc> Switch to virtual console <vc>\n"
- " -g Switch to graphics mode\n"
- " -t Switch to text mode\n"
- " -n Create and switch to new virtual console\n"
- " -c Close unused virtual consoles\n"
- " -p Print new virtual console\n"
- " -o Print old virtual console\n"
- " -h Print help\n", argv[0]);
- return -1;
- case '?':
- fprintf(stderr, "%s: invalid option -%c\n",
- argv[0], optopt);
- exit(1);
- }
- } while (1);
- if(mode == -1 && new_vc == 0 && close_vc == 0 && switch_vc == -1 && printvc == 0) {
- fprintf(stderr,"%s [-d <dev>] [-v <vc>] [-gtncpoh]\n", argv[0]);
- return -1;
- }
-
- fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd < 0) {
- fprintf(stderr, "cannot open %s\n", ttydev);
- return -1;
- }
-
- if ((printvc && !new_vc) || (printvc & 2)) {
- struct vt_stat vs;
-
- res = ioctl(fd, VT_GETSTATE, &vs);
- if (res < 0) {
- fprintf(stderr, "ioctl(vcfd, VT_GETSTATE, &vs) failed, %d\n", res);
- }
- printf("%d\n", vs.v_active);
- }
-
- if (new_vc) {
- int vtnum;
- res = ioctl(fd, VT_OPENQRY, &vtnum);
- if (res < 0 || vtnum == -1) {
- fprintf(stderr, "ioctl(vcfd, VT_OPENQRY, &vtnum) failed, res %d, vtnum %d\n", res, vtnum);
- }
- switch_vc = vtnum;
- }
- if (switch_vc != -1) {
- pthread_t thread;
- pthread_attr_t attr;
- activate_thread_switch_vc = switch_vc;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&thread, &attr, activate_thread, (void*)fd);
-
- do {
- res = ioctl(fd, VT_WAITACTIVE, (void*)switch_vc);
- } while(res < 0 && errno == EINTR);
- activate_thread_switch_vc = -1;
- if (res < 0) {
- fprintf(stderr, "ioctl( vcfd, VT_WAITACTIVE, vtnum) failed, %d %d %s for %d\n", res, errno, strerror(errno), switch_vc);
- }
- if(printvc & 1)
- printf("%d\n", switch_vc);
-
- close(fd);
- fd = open(ttydev, O_RDWR | O_SYNC);
- if (fd < 0) {
- fprintf(stderr, "cannot open %s\n", ttydev);
- return -1;
- }
- }
- if (close_vc) {
- res = ioctl(fd, VT_DISALLOCATE, 0);
- if (res < 0) {
- fprintf(stderr, "ioctl(vcfd, VT_DISALLOCATE, 0) failed, %d\n", res);
- }
- }
- if (mode != -1) {
- if (ioctl(fd, KDSETMODE, (void*)mode) < 0) {
- fprintf(stderr, "KDSETMODE %d failed\n", mode);
- return -1;
- }
- }
- return 0;
-}
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
index afa6868..a810b3d 100644
--- a/toolbox/swapon.c
+++ b/toolbox/swapon.c
@@ -5,12 +5,6 @@
#include <asm/page.h>
#include <sys/swap.h>
-/* XXX These need to be obtained from kernel headers. See b/9336527 */
-#define SWAP_FLAG_PREFER 0x8000
-#define SWAP_FLAG_PRIO_MASK 0x7fff
-#define SWAP_FLAG_PRIO_SHIFT 0
-#define SWAP_FLAG_DISCARD 0x10000
-
void usage(char *name)
{
fprintf(stderr, "Usage: %s [-p prio] <filename>\n"