am 1c39fdcd: merge in KQS81M
* commit '1c39fdcd9eb628338d7f273e43723585ca35721a':
Only check caller when deriving permissions.
Fix recursive locking bug.
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index 20c08d2..fa7fd98 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -55,13 +55,13 @@
void framebuffer_service(int fd, void *cookie)
{
struct fbinfo fbinfo;
- unsigned int i;
+ unsigned int i, bsize;
char buf[640];
int fd_screencap;
int w, h, f;
int fds[2];
- if (pipe(fds) < 0) goto done;
+ if (pipe(fds) < 0) goto pipefail;
pid_t pid = fork();
if (pid < 0) goto done;
@@ -164,17 +164,19 @@
if(writex(fd, &fbinfo, sizeof(fbinfo))) goto done;
/* write data */
- for(i = 0; i < fbinfo.size; i += sizeof(buf)) {
- if(readx(fd_screencap, buf, sizeof(buf))) goto done;
- if(writex(fd, buf, sizeof(buf))) goto done;
+ for(i = 0; i < fbinfo.size; i += bsize) {
+ bsize = sizeof(buf);
+ if (i + bsize > fbinfo.size)
+ bsize = fbinfo.size - i;
+ if(readx(fd_screencap, buf, bsize)) goto done;
+ if(writex(fd, buf, bsize)) goto done;
}
- if(readx(fd_screencap, buf, fbinfo.size % sizeof(buf))) goto done;
- if(writex(fd, buf, fbinfo.size % sizeof(buf))) goto done;
done:
TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
close(fds[0]);
close(fds[1]);
+pipefail:
close(fd);
}
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 68bb232..19b3022 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -155,7 +155,10 @@
#define VENDOR_ID_QISDA 0x1D45
// ECS's USB Vendor ID
#define VENDOR_ID_ECS 0x03fc
-
+// MSI's USB Vendor ID
+#define VENDOR_ID_MSI 0x0DB0
+// Wacom's USB Vendor ID
+#define VENDOR_ID_WACOM 0x0531
/** built-in vendor list */
int builtInVendorIds[] = {
@@ -219,6 +222,8 @@
VENDOR_ID_NOOK,
VENDOR_ID_QISDA,
VENDOR_ID_ECS,
+ VENDOR_ID_MSI,
+ VENDOR_ID_WACOM,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 8621e9c..2fe7c7a 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -24,11 +24,11 @@
endif # ARCH_ARM_HAVE_VFP_D32
LOCAL_SHARED_LIBRARIES := \
+ libbacktrace \
+ libc \
libcutils \
liblog \
- libc \
- libcorkscrew \
- libselinux
+ libselinux \
include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 67e3028..6bcd07e 100644
--- a/debuggerd/arm/machine.c
+++ b/debuggerd/arm/machine.c
@@ -42,7 +42,7 @@
#endif
#endif
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
+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;
@@ -102,7 +102,7 @@
p += 4;
}
*asc_out = '\0';
- _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer);
+ _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
}
}
@@ -110,16 +110,13 @@
* If configured to do so, dump memory around *all* registers
* for the crashing thread.
*/
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault) {
+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;
}
- int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
- if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+ if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
for (int reg = 0; reg < 14; reg++) {
@@ -134,39 +131,36 @@
continue;
}
- _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+ _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, scopeFlags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.ARM_pc, scopeFlags);
+ _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, scopeFlags, "\ncode around lr:\n");
- dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scopeFlags);
+ _LOG(log, scope_flags, "\ncode around lr:\n");
+ dump_memory(log, tid, (uintptr_t)regs.ARM_lr, scope_flags);
}
}
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault)
+void dump_registers(log_t* log, pid_t tid, int scope_flags)
{
struct pt_regs r;
- int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scopeFlags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ _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, scopeFlags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ _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, scopeFlags, " r8 %08x r9 %08x sl %08x fp %08x\n",
+ _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, scopeFlags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
+ _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);
@@ -175,14 +169,14 @@
int i;
if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
return;
}
for (i = 0; i < NUM_VFP_REGS; i += 2) {
- _LOG(log, scopeFlags, " d%-2d %016llx d%-2d %016llx\n",
+ _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, scopeFlags, " scr %08lx\n", vfp_regs.fpscr);
+ _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
#endif
}
diff --git a/debuggerd/backtrace.c b/debuggerd/backtrace.c
index f42f24c..6f82792 100644
--- a/debuggerd/backtrace.c
+++ b/debuggerd/backtrace.c
@@ -27,13 +27,11 @@
#include <sys/types.h>
#include <sys/ptrace.h>
-#include <corkscrew/backtrace.h>
+#include <backtrace/backtrace.h>
-#include "tombstone.h"
+#include "backtrace.h"
#include "utility.h"
-#define STACK_DEPTH 32
-
static void dump_process_header(log_t* log, pid_t pid) {
char path[PATH_MAX];
char procnamebuf[1024];
@@ -62,7 +60,7 @@
_LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
}
-static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool attached,
+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];
@@ -91,20 +89,12 @@
wait_for_stop(tid, total_sleep_time_usec);
- backtrace_frame_t backtrace[STACK_DEPTH];
- ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
- if (frames <= 0) {
- _LOG(log, SCOPE_AT_FAULT, "Could not obtain stack trace for thread.\n");
+ backtrace_t backtrace;
+ if (!backtrace_get_data(&backtrace, tid)) {
+ _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n");
} else {
- backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
- get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
- for (size_t i = 0; i < (size_t)frames; i++) {
- char line[MAX_BACKTRACE_LINE_LENGTH];
- format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
- line, MAX_BACKTRACE_LINE_LENGTH);
- _LOG(log, SCOPE_AT_FAULT, " %s\n", line);
- }
- free_backtrace_symbols(backtrace_symbols, frames);
+ dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, " ");
+ backtrace_free_data(&backtrace);
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
@@ -120,9 +110,8 @@
log.amfd = amfd;
log.quiet = true;
- ptrace_context_t* context = load_ptrace_context(tid);
dump_process_header(&log, pid);
- dump_thread(&log, tid, context, true, detach_failed, total_sleep_time_usec);
+ 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);
@@ -140,11 +129,19 @@
continue;
}
- dump_thread(&log, new_tid, context, false, detach_failed, total_sleep_time_usec);
+ dump_thread(&log, new_tid, false, detach_failed, total_sleep_time_usec);
}
closedir(d);
}
dump_process_footer(&log, pid);
- free_ptrace_context(context);
+}
+
+void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
+ int scope_flags, const char* prefix) {
+ char buf[512];
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ backtrace_format_frame_data(&backtrace->frames[i], i, buf, sizeof(buf));
+ _LOG(log, scope_flags, "%s%s\n", prefix, buf);
+ }
}
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index c5c786a..9d61e6f 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -21,11 +21,17 @@
#include <stdbool.h>
#include <sys/types.h>
-#include <corkscrew/ptrace.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. */
void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
int* total_sleep_time_usec);
+/* Dumps the backtrace in the backtrace data structure to the log. */
+void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
+ int scope_flags, const char* prefix);
+
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index 1619dd3..2f1e201 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -17,15 +17,11 @@
#ifndef _DEBUGGERD_MACHINE_H
#define _DEBUGGERD_MACHINE_H
-#include <stddef.h>
-#include <stdbool.h>
#include <sys/types.h>
-#include <corkscrew/ptrace.h>
-
#include "utility.h"
-void dump_memory_and_code(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault);
-void dump_registers(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault);
+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);
#endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.c b/debuggerd/mips/machine.c
index 65fdf02..e06a50c 100644
--- a/debuggerd/mips/machine.c
+++ b/debuggerd/mips/machine.c
@@ -36,7 +36,7 @@
#define R(x) ((unsigned int)(x))
-static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
+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;
@@ -92,7 +92,7 @@
p += 4;
}
*asc_out = '\0';
- _LOG(log, scopeFlags, " %s %s\n", code_buffer, ascii_buffer);
+ _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
}
}
@@ -100,15 +100,13 @@
* If configured to do so, dump memory around *all* registers
* for the crashing thread.
*/
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault) {
+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;
}
- int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
- if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
+ if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
for (int reg = 0; reg < 32; reg++) {
@@ -130,50 +128,47 @@
continue;
}
- _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+ _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, scopeFlags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc, scopeFlags);
+ _LOG(log, scope_flags, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)pc, scope_flags);
if (pc != ra) {
- _LOG(log, scopeFlags, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra, scopeFlags);
+ _LOG(log, scope_flags, "\ncode around ra:\n");
+ dump_memory(log, tid, (uintptr_t)ra, scope_flags);
}
}
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault)
+void dump_registers(log_t* log, pid_t tid, int scope_flags)
{
pt_regs_mips_t r;
- int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
-
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scopeFlags, " zr %08x at %08x v0 %08x v1 %08x\n",
+ _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, scopeFlags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
+ _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, scopeFlags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
+ _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, scopeFlags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
+ _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, scopeFlags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
+ _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, scopeFlags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
+ _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, scopeFlags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
+ _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, scopeFlags, " gp %08x sp %08x s8 %08x ra %08x\n",
+ _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, scopeFlags, " hi %08x lo %08x bva %08x epc %08x\n",
+ _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
index 7009a8e..6fb2191 100644
--- a/debuggerd/tombstone.c
+++ b/debuggerd/tombstone.c
@@ -32,8 +32,7 @@
#include <log/logger.h>
#include <cutils/properties.h>
-#include <corkscrew/demangle.h>
-#include <corkscrew/backtrace.h>
+#include <backtrace/backtrace.h>
#include <sys/socket.h>
#include <linux/un.h>
@@ -42,9 +41,8 @@
#include "machine.h"
#include "tombstone.h"
-#include "utility.h"
+#include "backtrace.h"
-#define STACK_DEPTH 32
#define STACK_WORDS 16
#define MAX_TOMBSTONES 10
@@ -193,7 +191,7 @@
}
}
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
+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;
@@ -211,7 +209,7 @@
}
}
- if (at_fault) {
+ if (IS_AT_FAULT(scope_flags)) {
char procnamebuf[1024];
char* procname = NULL;
@@ -230,64 +228,46 @@
}
}
-static void dump_backtrace(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid __attribute((unused)), bool at_fault,
- const backtrace_frame_t* backtrace, size_t frames) {
- int scopeFlags = at_fault ? SCOPE_AT_FAULT : 0;
- _LOG(log, scopeFlags, "\nbacktrace:\n");
-
- backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
- get_backtrace_symbols_ptrace(context, backtrace, frames, backtrace_symbols);
- for (size_t i = 0; i < frames; i++) {
- char line[MAX_BACKTRACE_LINE_LENGTH];
- format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
- line, MAX_BACKTRACE_LINE_LENGTH);
- _LOG(log, scopeFlags, " %s\n", line);
- }
- free_backtrace_symbols(backtrace_symbols, frames);
-}
-
-static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_t tid,
- int scopeFlags, uintptr_t* sp, size_t words, int label) {
+static void dump_stack_segment(const backtrace_t* 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 (!try_get_word_ptrace(tid, *sp, &stack_content)) {
+ if (!backtrace_read_word(backtrace, *sp, &stack_content)) {
break;
}
- const map_info_t* mi;
- const symbol_t* symbol;
- find_symbol_ptrace(context, stack_content, &mi, &symbol);
-
- if (symbol) {
- char* demangled_name = demangle_symbol_name(symbol->name);
- const char* symbol_name = demangled_name ? demangled_name : symbol->name;
- uint32_t offset = stack_content - (mi->start + symbol->start);
+ const char* map_name = backtrace_get_map_info(backtrace, stack_content, NULL);
+ if (!map_name) {
+ map_name = "";
+ }
+ uintptr_t offset = 0;
+ char* proc_name = backtrace_get_proc_name(backtrace, stack_content, &offset);
+ if (proc_name) {
if (!i && label >= 0) {
if (offset) {
- _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s+%u)\n",
- label, *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
+ _LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n",
+ label, *sp, stack_content, map_name, proc_name, offset);
} else {
- _LOG(log, scopeFlags, " #%02d %08x %08x %s (%s)\n",
- label, *sp, stack_content, mi ? mi->name : "", symbol_name);
+ _LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n",
+ label, *sp, stack_content, map_name, proc_name);
}
} else {
if (offset) {
- _LOG(log, scopeFlags, " %08x %08x %s (%s+%u)\n",
- *sp, stack_content, mi ? mi->name : "", symbol_name, offset);
+ _LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n",
+ *sp, stack_content, map_name, proc_name, offset);
} else {
- _LOG(log, scopeFlags, " %08x %08x %s (%s)\n",
- *sp, stack_content, mi ? mi->name : "", symbol_name);
+ _LOG(log, scope_flags, " %08x %08x %s (%s)\n",
+ *sp, stack_content, map_name, proc_name);
}
}
- free(demangled_name);
+ free(proc_name);
} else {
if (!i && label >= 0) {
- _LOG(log, scopeFlags, " #%02d %08x %08x %s\n",
- label, *sp, stack_content, mi ? mi->name : "");
+ _LOG(log, scope_flags, " #%02d %08x %08x %s\n",
+ label, *sp, stack_content, map_name);
} else {
- _LOG(log, scopeFlags, " %08x %08x %s\n",
- *sp, stack_content, mi ? mi->name : "");
+ _LOG(log, scope_flags, " %08x %08x %s\n",
+ *sp, stack_content, map_name);
}
}
@@ -295,45 +275,42 @@
}
}
-static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
- const backtrace_frame_t* backtrace, size_t frames) {
- bool have_first = false;
- size_t first, last;
- for (size_t i = 0; i < frames; i++) {
- if (backtrace[i].stack_top) {
- if (!have_first) {
- have_first = true;
- first = i;
+static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) {
+ 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 (!have_first) {
+ if (!first) {
return;
}
+ first--;
- int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
- _LOG(log, scopeFlags, "\nstack:\n");
+ scope_flags |= SCOPE_SENSITIVE;
// Dump a few words before the first frame.
- uintptr_t sp = backtrace[first].stack_top - STACK_WORDS * sizeof(uint32_t);
- dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, -1);
+ uintptr_t sp = backtrace->frames[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_t* frame = &backtrace[i];
- if (sp != frame->stack_top) {
- _LOG(log, scopeFlags, " ........ ........\n");
- sp = frame->stack_top;
+ 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) {
- scopeFlags &= (~SCOPE_AT_FAULT);
+ scope_flags &= (~SCOPE_AT_FAULT);
}
if (i == last) {
- dump_stack_segment(context, log, tid, scopeFlags, &sp, STACK_WORDS, i);
- if (sp < frame->stack_top + frame->stack_size) {
- _LOG(log, scopeFlags, " ........ ........\n");
+ 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);
@@ -342,39 +319,40 @@
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
+ dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
}
}
}
-static void dump_backtrace_and_stack(const ptrace_context_t* context, log_t* log, pid_t tid,
- bool at_fault) {
- backtrace_frame_t backtrace[STACK_DEPTH];
- ssize_t frames = unwind_backtrace_ptrace(tid, context, backtrace, 0, STACK_DEPTH);
- if (frames > 0) {
- dump_backtrace(context, log, tid, at_fault, backtrace, frames);
- dump_stack(context, log, tid, at_fault, backtrace, frames);
+static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log,
+ int scope_flags) {
+ if (backtrace->num_frames) {
+ _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, map_info_t* m, const char* what, int scopeFlags) {
+static void dump_map(log_t* log, const backtrace_map_info_t* m, const char* what, int scope_flags) {
if (m != NULL) {
- _LOG(log, scopeFlags, " %08x-%08x %c%c%c %s\n", m->start, m->end,
+ _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, scopeFlags, " (no %s)\n", what);
+ _LOG(log, scope_flags, " (no %s)\n", what);
}
}
-static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault) {
- int scopeFlags = SCOPE_SENSITIVE | (at_fault ? SCOPE_AT_FAULT : 0);
+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, scopeFlags, "cannot get siginfo for %d: %s\n",
+ _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n",
tid, strerror(errno));
return;
}
@@ -388,15 +366,15 @@
return;
}
- _LOG(log, scopeFlags, "\nmemory map around fault addr %08x:\n", (int)si.si_addr);
+ _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.
*/
- map_info_t* map = context->map_info_list;
- map_info_t *next = NULL;
- map_info_t *prev = NULL;
+ 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;
@@ -416,31 +394,31 @@
* Show "next" then "match" then "prev" so that the addresses appear in
* ascending order (like /proc/pid/maps).
*/
- dump_map(log, next, "map below", scopeFlags);
- dump_map(log, map, "map for address", scopeFlags);
- dump_map(log, prev, "map above", scopeFlags);
+ 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 ptrace_context_t* context, log_t* log, pid_t tid, bool at_fault,
+static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags,
int* total_sleep_time_usec) {
- wait_for_stop(tid, total_sleep_time_usec);
+ wait_for_stop(backtrace->tid, total_sleep_time_usec);
- dump_registers(context, log, tid, at_fault);
- dump_backtrace_and_stack(context, log, tid, at_fault);
- if (at_fault) {
- dump_memory_and_code(context, log, tid, at_fault);
- dump_nearby_maps(context, log, tid, at_fault);
+ 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->map_info_list, log, backtrace->tid, scope_flags);
}
}
/* Return true if some thread is not detached cleanly */
-static bool dump_sibling_thread_report(const ptrace_context_t* context,
+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 cannot open the task directory */
+ /* Bail early if the task directory cannot be opened */
if (d == NULL) {
XLOG("Cannot open /proc/%d/task\n", pid);
return false;
@@ -467,8 +445,12 @@
}
_LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
- dump_thread_info(log, pid, new_tid, false);
- dump_thread(context, log, new_tid, false, total_sleep_time_usec);
+ dump_thread_info(log, pid, new_tid, 0);
+ backtrace_t new_backtrace;
+ if (backtrace_get_data(&new_backtrace, new_tid)) {
+ dump_thread(&new_backtrace, log, 0, total_sleep_time_usec);
+ }
+ backtrace_free_data(&new_backtrace);
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
@@ -624,7 +606,7 @@
dump_log_file(log, pid, "/dev/log/main", tailOnly);
}
-static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
+static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) {
if (address == 0) {
return;
}
@@ -636,9 +618,10 @@
char* p = &msg[0];
while (p < &msg[sizeof(msg)]) {
uint32_t data;
- if (!try_get_word_ptrace(tid, address, &data)) {
+ if (!backtrace_read_word(backtrace, address, &data)) {
break;
}
+ data = 0;
address += sizeof(uint32_t);
if ((*p++ = (data >> 0) & 0xff) == 0) {
@@ -686,14 +669,17 @@
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_build_info(log);
dump_revision_info(log);
- dump_thread_info(log, pid, tid, true);
+ dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
if (signal) {
dump_fault_addr(log, tid, signal);
}
- dump_abort_message(log, tid, abort_msg_address);
- ptrace_context_t* context = load_ptrace_context(tid);
- dump_thread(context, log, tid, true, total_sleep_time_usec);
+ backtrace_t backtrace;
+ if (backtrace_get_data(&backtrace, tid)) {
+ dump_abort_message(&backtrace, log, abort_msg_address);
+ dump_thread(&backtrace, log, SCOPE_AT_FAULT, total_sleep_time_usec);
+ backtrace_free_data(&backtrace);
+ }
if (want_logs) {
dump_logs(log, pid, true);
@@ -701,11 +687,9 @@
bool detach_failed = false;
if (dump_sibling_threads) {
- detach_failed = dump_sibling_thread_report(context, log, pid, tid, total_sleep_time_usec);
+ detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec);
}
- free_ptrace_context(context);
-
if (want_logs) {
dump_logs(log, pid, false);
}
diff --git a/debuggerd/x86/machine.c b/debuggerd/x86/machine.c
index af79092..e00208d 100644
--- a/debuggerd/x86/machine.c
+++ b/debuggerd/x86/machine.c
@@ -31,28 +31,24 @@
#include "../utility.h"
#include "../machine.h"
-void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault) {
+void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
}
-void dump_registers(const ptrace_context_t* context __attribute((unused)),
- log_t* log, pid_t tid, bool at_fault) {
+void dump_registers(log_t* log, pid_t tid, int scope_flags) {
struct pt_regs_x86 r;
- int scopeFlags = (at_fault ? SCOPE_AT_FAULT : 0);
-
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scopeFlags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
return;
}
//if there is no stack, no print just like arm
if(!r.ebp)
return;
- _LOG(log, scopeFlags, " eax %08x ebx %08x ecx %08x edx %08x\n",
+ _LOG(log, scope_flags, " eax %08x ebx %08x ecx %08x edx %08x\n",
r.eax, r.ebx, r.ecx, r.edx);
- _LOG(log, scopeFlags, " esi %08x edi %08x\n",
+ _LOG(log, scope_flags, " esi %08x edi %08x\n",
r.esi, r.edi);
- _LOG(log, scopeFlags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
+ _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, scopeFlags, " eip %08x ebp %08x esp %08x flags %08x\n",
+ _LOG(log, scope_flags, " eip %08x ebp %08x esp %08x flags %08x\n",
r.eip, r.ebp, r.esp, r.eflags);
}
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..9153c8d 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -75,10 +75,18 @@
unsigned char ep_out;
};
+/* True if name isn't a valid name for a USB device in /sys/bus/usb/devices.
+ * Device names are made up of numbers, dots, and dashes, e.g., '7-1.5'.
+ * We reject interfaces (e.g., '7-1.5:1.0') and host controllers (e.g. 'usb1').
+ * The name must also start with a digit, to disallow '.' and '..'
+ */
static inline int badname(const char *name)
{
- while(*name) {
- if(!isdigit(*name++)) return 1;
+ if (!isdigit(*name))
+ return 1;
+ while(*++name) {
+ if(!isdigit(*name) && *name != '.' && *name != '-')
+ return 1;
}
return 0;
}
@@ -95,7 +103,8 @@
return 0;
}
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(int fd, char* sysfs_name,
+ char *ptr, int len, int writable,
ifc_match_func callback,
int *ept_in_id, int *ept_out_id, int *ifc_id)
{
@@ -131,69 +140,35 @@
info.dev_protocol = dev->bDeviceProtocol;
info.writable = writable;
- // read device serial number (if there is one)
- info.serial_number[0] = 0;
- if (dev->iSerialNumber) {
- struct usbdevfs_ctrltransfer ctrl;
- // Keep it short enough because some bootloaders are borked if the URB len is > 255
- // 128 is too big by 1.
- __u16 buffer[127];
+ snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
- memset(buffer, 0, sizeof(buffer));
-
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | dev->iSerialNumber;
- //language ID (en-us) for serial number string
- ctrl.wIndex = 0x0409;
- ctrl.wLength = sizeof(buffer);
- ctrl.data = buffer;
- ctrl.timeout = 50;
-
- result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
- if (result > 0) {
- int i;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
- result /= 2;
- for (i = 1; i < result; i++)
- info.serial_number[i - 1] = buffer[i];
- info.serial_number[i - 1] = 0;
- }
- }
-
- /* We need to get a path that represents a particular port on a particular
- * hub. We are passed an fd that was obtained by opening an entry under
- * /dev/bus/usb. Unfortunately, the names of those entries change each
- * time devices are plugged and unplugged. So how to get a repeatable
- * path? udevadm provided the inspiration. We can get the major and
- * minor of the device file, read the symlink that can be found here:
- * /sys/dev/char/<major>:<minor>
- * and then use the last element of that path. As a concrete example, I
- * have an Android device at /dev/bus/usb/001/027 so working with bash:
- * $ ls -l /dev/bus/usb/001/027
- * crw-rw-r-- 1 root plugdev 189, 26 Apr 9 11:03 /dev/bus/usb/001/027
- * $ ls -l /sys/dev/char/189:26
- * lrwxrwxrwx 1 root root 0 Apr 9 11:03 /sys/dev/char/189:26 ->
- * ../../devices/pci0000:00/0000:00:1a.7/usb1/1-4/1-4.2/1-4.2.3
- * So our device_path would be 1-4.2.3 which says my device is connected
- * to port 3 of a hub on port 2 of a hub on port 4 of bus 1 (per
- * http://www.linux-usb.org/FAQ.html).
+ /* Read device serial number (if there is one).
+ * We read the serial number from sysfs, since it's faster and more
+ * reliable than issuing a control pipe read, and also won't
+ * cause problems for devices which don't like getting descriptor
+ * requests while they're in the middle of flashing.
*/
- info.device_path[0] = '\0';
- result = fstat(fd, &st);
- if (!result && S_ISCHR(st.st_mode)) {
- char cdev[128];
- char link[256];
- char *slash;
- ssize_t link_len;
- snprintf(cdev, sizeof(cdev), "/sys/dev/char/%d:%d",
- major(st.st_rdev), minor(st.st_rdev));
- link_len = readlink(cdev, link, sizeof(link) - 1);
- if (link_len > 0) {
- link[link_len] = '\0';
- slash = strrchr(link, '/');
- if (slash)
- snprintf(info.device_path, sizeof(info.device_path), "usb:%s", slash+1);
+ info.serial_number[0] = '\0';
+ if (dev->iSerialNumber) {
+ char path[80];
+ int fd;
+
+ snprintf(path, sizeof(path),
+ "/sys/bus/usb/devices/%s/serial", sysfs_name);
+ path[sizeof(path) - 1] = '\0';
+
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
+ int chars_read = read(fd, info.serial_number,
+ sizeof(info.serial_number) - 1);
+ close(fd);
+
+ if (chars_read <= 0)
+ info.serial_number[0] = '\0';
+ else if (info.serial_number[chars_read - 1] == '\n') {
+ // strip trailing newline
+ info.serial_number[chars_read - 1] = '\0';
+ }
}
}
@@ -241,14 +216,73 @@
return -1;
}
+static int read_sysfs_string(const char *sysfs_name, const char *sysfs_node,
+ char* buf, int bufsize)
+{
+ char path[80];
+ int fd, n;
+
+ snprintf(path, sizeof(path),
+ "/sys/bus/usb/devices/%s/%s", sysfs_name, sysfs_node);
+ path[sizeof(path) - 1] = '\0';
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ n = read(fd, buf, bufsize - 1);
+ close(fd);
+
+ if (n < 0)
+ return -1;
+
+ buf[n] = '\0';
+
+ return n;
+}
+
+static int read_sysfs_number(const char *sysfs_name, const char *sysfs_node)
+{
+ char buf[16];
+ int value;
+
+ if (read_sysfs_string(sysfs_name, sysfs_node, buf, sizeof(buf)) < 0)
+ return -1;
+
+ if (sscanf(buf, "%d", &value) != 1)
+ return -1;
+
+ return value;
+}
+
+/* Given the name of a USB device in sysfs, get the name for the same
+ * device in devfs. Returns 0 for success, -1 for failure.
+ */
+static int convert_to_devfs_name(const char* sysfs_name,
+ char* devname, int devname_size)
+{
+ int busnum, devnum;
+
+ busnum = read_sysfs_number(sysfs_name, "busnum");
+ if (busnum < 0)
+ return -1;
+
+ devnum = read_sysfs_number(sysfs_name, "devnum");
+ if (devnum < 0)
+ return -1;
+
+ snprintf(devname, devname_size, "/dev/bus/usb/%03d/%03d", busnum, devnum);
+ return 0;
+}
+
static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
{
usb_handle *usb = 0;
- char busname[64], devname[64];
+ char devname[64];
char desc[1024];
int n, in, out, ifc;
- DIR *busdir, *devdir;
+ DIR *busdir;
struct dirent *de;
int fd;
int writable;
@@ -259,15 +293,7 @@
while((de = readdir(busdir)) && (usb == 0)) {
if(badname(de->d_name)) continue;
- sprintf(busname, "%s/%s", base, de->d_name);
- devdir = opendir(busname);
- if(devdir == 0) continue;
-
-// DBG("[ scanning %s ]\n", busname);
- while((de = readdir(devdir)) && (usb == 0)) {
-
- if(badname(de->d_name)) continue;
- sprintf(devname, "%s/%s", busname, de->d_name);
+ if(!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
// DBG("[ scanning %s ]\n", devname);
writable = 1;
@@ -282,7 +308,7 @@
n = read(fd, desc, sizeof(desc));
- if(filter_usb_device(fd, desc, n, writable, callback,
+ if(filter_usb_device(fd, de->d_name, desc, n, writable, callback,
&in, &out, &ifc) == 0) {
usb = calloc(1, sizeof(usb_handle));
strcpy(usb->fname, devname);
@@ -301,7 +327,6 @@
close(fd);
}
}
- closedir(devdir);
}
closedir(busdir);
@@ -431,5 +456,5 @@
usb_handle *usb_open(ifc_match_func callback)
{
- return find_usb_device("/dev/bus/usb", callback);
+ return find_usb_device("/sys/bus/usb/devices", callback);
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index f432f6a..13b71ee 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -238,74 +238,16 @@
return f;
}
-/* Read a line of text till the next newline character.
- * If no newline is found before the buffer is full, continue reading till a new line is seen,
- * then return an empty buffer. This effectively ignores lines that are too long.
- * On EOF, return null.
- */
-static char *fs_getline(char *buf, int size, FILE *file)
-{
- int cnt = 0;
- int eof = 0;
- int eol = 0;
- int c;
-
- if (size < 1) {
- return NULL;
- }
-
- while (cnt < (size - 1)) {
- c = getc(file);
- if (c == EOF) {
- eof = 1;
- break;
- }
-
- *(buf + cnt) = c;
- cnt++;
-
- if (c == '\n') {
- eol = 1;
- break;
- }
- }
-
- /* Null terminate what we've read */
- *(buf + cnt) = '\0';
-
- if (eof) {
- if (cnt) {
- return buf;
- } else {
- return NULL;
- }
- } else if (eol) {
- return buf;
- } else {
- /* The line is too long. Read till a newline or EOF.
- * If EOF, return null, if newline, return an empty buffer.
- */
- while(1) {
- c = getc(file);
- if (c == EOF) {
- return NULL;
- } else if (c == '\n') {
- *buf = '\0';
- return buf;
- }
- }
- }
-}
-
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
FILE *fstab_file;
int cnt, entries;
- int len;
- char line[256];
+ ssize_t len;
+ size_t alloc_len = 0;
+ char *line = NULL;
const char *delim = " \t";
char *save_ptr, *p;
- struct fstab *fstab;
+ struct fstab *fstab = NULL;
struct fstab_rec *recs;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
@@ -318,9 +260,8 @@
}
entries = 0;
- while (fs_getline(line, sizeof(line), fstab_file)) {
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
- len = strlen(line);
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
@@ -337,7 +278,7 @@
if (!entries) {
ERROR("No entries found in fstab\n");
- return 0;
+ goto err;
}
/* Allocate and init the fstab structure */
@@ -349,9 +290,8 @@
fseek(fstab_file, 0, SEEK_SET);
cnt = 0;
- while (fs_getline(line, sizeof(line), fstab_file)) {
+ while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
- len = strlen(line);
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
@@ -376,25 +316,25 @@
if (!(p = strtok_r(line, delim, &save_ptr))) {
ERROR("Error parsing mount source\n");
- return 0;
+ goto err;
}
fstab->recs[cnt].blk_device = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
ERROR("Error parsing mount_point\n");
- return 0;
+ goto err;
}
fstab->recs[cnt].mount_point = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
ERROR("Error parsing fs_type\n");
- return 0;
+ goto err;
}
fstab->recs[cnt].fs_type = strdup(p);
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
ERROR("Error parsing mount_flags\n");
- return 0;
+ goto err;
}
tmp_fs_options[0] = '\0';
fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
@@ -409,7 +349,7 @@
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
ERROR("Error parsing fs_mgr_options\n");
- return 0;
+ goto err;
}
fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
&flag_vals, NULL, 0);
@@ -422,8 +362,15 @@
cnt++;
}
fclose(fstab_file);
-
+ free(line);
return fstab;
+
+err:
+ fclose(fstab_file);
+ free(line);
+ if (fstab)
+ fs_mgr_free_fstab(fstab);
+ return NULL;
}
void fs_mgr_free_fstab(struct fstab *fstab)
@@ -442,7 +389,6 @@
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
free(fstab->recs[i].label);
- i++;
}
/* Free the fstab_recs array created by calloc(3) */
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
new file mode 100644
index 0000000..b6bff38
--- /dev/null
+++ b/include/backtrace/backtrace.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#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* proc_name; /* The function name associated with this pc, NULL if not found. */
+ uintptr_t proc_offset; /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */
+} backtrace_frame_data_t;
+
+typedef struct {
+ backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
+ size_t num_frames;
+
+ pid_t tid;
+ backtrace_map_info_t* map_info_list;
+ void* private_data;
+} backtrace_t;
+
+/* Gather the backtrace data for tid and fill in the backtrace structure.
+ * If tid < 0, then gather the backtrace for the current thread.
+ */
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid);
+
+/* Free any memory associated with the backtrace structure. */
+void backtrace_free_data(backtrace_t* backtrace);
+
+/* Read data at a specific address for a process. */
+bool backtrace_read_word(
+ const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value);
+
+/* Get information about the map associated with a pc. If NULL is
+ * returned, then map_start is not set.
+ */
+const char* backtrace_get_map_info(
+ const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start);
+
+/* Get the procedure name and offest given the pc. If NULL is returned,
+ * then proc_offset is not set. The returned string is allocated using
+ * malloc and must be freed by the caller.
+ */
+char* backtrace_get_proc_name(
+ const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset);
+
+/* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory
+ * map for the current process.
+ */
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid);
+
+/* 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_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BACKTRACE_H */
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 3881fc9..72395f4 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,6 +44,11 @@
#define list_for_each_reverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev)
+#define list_for_each_safe(node, next, list) \
+ for (node = (list)->next, next = node->next; \
+ node != (list); \
+ node = next, next = node->next)
+
void list_init(struct listnode *list);
void list_add_tail(struct listnode *list, struct listnode *item);
void list_remove(struct listnode *item);
diff --git a/init/devices.c b/init/devices.c
index 1893642..af88c5f 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -33,6 +33,7 @@
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
+#include <selinux/avc.h>
#include <private/android_filesystem_config.h>
#include <sys/time.h>
@@ -830,6 +831,15 @@
struct uevent uevent;
parse_event(msg, &uevent);
+ if (sehandle && selinux_status_updated() > 0) {
+ struct selabel_handle *sehandle2;
+ sehandle2 = selinux_android_file_context_handle();
+ if (sehandle2) {
+ selabel_close(sehandle);
+ sehandle = sehandle2;
+ }
+ }
+
handle_device_event(&uevent);
handle_firmware_event(&uevent);
}
@@ -896,6 +906,7 @@
sehandle = NULL;
if (is_selinux_enabled() > 0) {
sehandle = selinux_android_file_context_handle();
+ selinux_status_open(true);
}
/* is 256K enough? udev uses 16MB! */
diff --git a/init/init.c b/init/init.c
index 94a2011..feac8ad 100644
--- a/init/init.c
+++ b/init/init.c
@@ -250,14 +250,12 @@
for (ei = svc->envvars; ei; ei = ei->next)
add_environment(ei->name, ei->value);
- setsockcreatecon(scon);
-
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
- si->perm, si->uid, si->gid);
+ si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
@@ -265,7 +263,6 @@
freecon(scon);
scon = NULL;
- setsockcreatecon(NULL);
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
diff --git a/init/init.h b/init/init.h
index aa6a4ab..3928d52 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@
uid_t uid;
gid_t gid;
int perm;
+ const char *socketcon;
};
struct svcenvinfo {
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..667c7ab 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -552,12 +552,14 @@
if (length > PROP_NAME_MAX) {
ERROR("property name too long in trigger %s", act->name);
} else {
+ int ret;
memcpy(prop_name, name, length);
prop_name[length] = 0;
/* does the property exist, and match the trigger value? */
- property_get(prop_name, value);
- if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
+ ret = property_get(prop_name, value);
+ if (ret > 0 && (!strcmp(equals + 1, value) ||
+ !strcmp(equals + 1, "*"))) {
action_add_queue_tail(act);
}
}
@@ -771,7 +773,7 @@
svc->envvars = ei;
break;
}
- case K_socket: {/* name type perm [ uid gid ] */
+ case K_socket: {/* name type perm [ uid gid context ] */
struct socketinfo *si;
if (nargs < 4) {
parse_error(state, "socket option requires name, type, perm arguments\n");
@@ -794,6 +796,8 @@
si->uid = decode_uid(args[4]);
if (nargs > 5)
si->gid = decode_uid(args[5]);
+ if (nargs > 6)
+ si->socketcon = args[6];
si->next = svc->sockets;
svc->sockets = si;
break;
diff --git a/init/property_service.c b/init/property_service.c
index 9ac2781..c370769 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -81,6 +81,7 @@
{ "sys.powerctl", AID_SHELL, 0 },
{ "service.", AID_SYSTEM, 0 },
{ "wlan.", AID_SYSTEM, 0 },
+ { "gps.", AID_GPS, 0 },
{ "bluetooth.", AID_BLUETOOTH, 0 },
{ "dhcp.", AID_SYSTEM, 0 },
{ "dhcp.", AID_DHCP, 0 },
@@ -92,6 +93,7 @@
{ "persist.sys.", AID_SYSTEM, 0 },
{ "persist.service.", AID_SYSTEM, 0 },
{ "persist.security.", AID_SYSTEM, 0 },
+ { "persist.gps.", AID_GPS, 0 },
{ "persist.service.bdroid.", AID_BLUETOOTH, 0 },
{ "selinux." , AID_SYSTEM, 0 },
{ NULL, 0, 0 }
@@ -437,10 +439,13 @@
*sz = pa_workspace.size;
}
-static void load_properties(char *data)
+static void load_properties(char *data, char *prefix)
{
char *key, *value, *eol, *sol, *tmp;
+ size_t plen;
+ if (prefix)
+ plen = strlen(prefix);
sol = data;
while((eol = strchr(sol, '\n'))) {
key = sol;
@@ -456,6 +461,9 @@
tmp = value - 2;
while((tmp > key) && isspace(*tmp)) *tmp-- = 0;
+ if (prefix && strncmp(key, prefix, plen))
+ continue;
+
while(isspace(*value)) value++;
tmp = eol - 2;
while((tmp > value) && isspace(*tmp)) *tmp-- = 0;
@@ -464,7 +472,7 @@
}
}
-static void load_properties_from_file(const char *fn)
+static void load_properties_from_file(const char *fn, char *prefix)
{
char *data;
unsigned sz;
@@ -472,7 +480,7 @@
data = read_file(fn, &sz);
if(data != 0) {
- load_properties(data);
+ load_properties(data, prefix);
free(data);
}
}
@@ -545,7 +553,7 @@
void property_load_boot_defaults(void)
{
- load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+ load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);
}
int properties_inited(void)
@@ -560,7 +568,7 @@
ret = property_get("ro.debuggable", debuggable);
if (ret && (strcmp(debuggable, "1") == 0)) {
- load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
+ load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);
}
#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
}
@@ -582,13 +590,14 @@
{
int fd;
- load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
- load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
+ load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
+ load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
+ load_properties_from_file(PROP_PATH_FACTORY, "ro.");
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
- fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
+ fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
if(fd < 0) return;
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, O_NONBLOCK);
diff --git a/init/readme.txt b/init/readme.txt
index 7a5997d..1e8c392 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@
setenv <name> <value>
Set the environment variable <name> to <value> in the launched process.
-socket <name> <type> <perm> [ <user> [ <group> ] ]
+socket <name> <type> <perm> [ <user> [ <group> [ <context> ] ] ]
Create a unix domain socket named /dev/socket/<name> and pass
its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
User and group default to 0.
+ Context is the SELinux security context for the socket.
+ It defaults to the service security context, as specified by seclabel or
+ computed based on the service executable file security context.
user <username>
Change to username before exec'ing this service.
diff --git a/init/util.c b/init/util.c
index 1908b3a..9aaa77d 100644
--- a/init/util.c
+++ b/init/util.c
@@ -84,11 +84,15 @@
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
*/
-int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
+int create_socket(const char *name, int type, mode_t perm, uid_t uid,
+ gid_t gid, const char *socketcon)
{
struct sockaddr_un addr;
int fd, ret;
- char *secon;
+ char *filecon;
+
+ if (socketcon)
+ setsockcreatecon(socketcon);
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
@@ -96,6 +100,9 @@
return -1;
}
+ if (socketcon)
+ setsockcreatecon(NULL);
+
memset(&addr, 0 , sizeof(addr));
addr.sun_family = AF_UNIX;
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
@@ -107,11 +114,11 @@
goto out_close;
}
- secon = NULL;
+ filecon = NULL;
if (sehandle) {
- ret = selabel_lookup(sehandle, &secon, addr.sun_path, S_IFSOCK);
+ ret = selabel_lookup(sehandle, &filecon, addr.sun_path, S_IFSOCK);
if (ret == 0)
- setfscreatecon(secon);
+ setfscreatecon(filecon);
}
ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
@@ -121,7 +128,7 @@
}
setfscreatecon(NULL);
- freecon(secon);
+ freecon(filecon);
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
@@ -398,7 +405,9 @@
void get_hardware_name(char *hardware, unsigned int *revision)
{
- char data[1024];
+ const char *cpuinfo = "/proc/cpuinfo";
+ char *data = NULL;
+ size_t len = 0, limit = 1024;
int fd, n;
char *x, *hw, *rev;
@@ -406,14 +415,32 @@
if (hardware[0])
return;
- fd = open("/proc/cpuinfo", O_RDONLY);
+ fd = open(cpuinfo, O_RDONLY);
if (fd < 0) return;
- n = read(fd, data, 1023);
- close(fd);
- if (n < 0) return;
+ for (;;) {
+ x = realloc(data, limit);
+ if (!x) {
+ ERROR("Failed to allocate memory to read %s\n", cpuinfo);
+ goto done;
+ }
+ data = x;
- data[n] = 0;
+ n = read(fd, data + len, limit - len);
+ if (n < 0) {
+ ERROR("Failed reading %s: %s (%d)\n", cpuinfo, strerror(errno), errno);
+ goto done;
+ }
+ len += n;
+
+ if (len < limit)
+ break;
+
+ /* We filled the buffer, so increase size and loop to read more */
+ limit *= 2;
+ }
+
+ data[len] = 0;
hw = strstr(data, "\nHardware");
rev = strstr(data, "\nRevision");
@@ -438,18 +465,22 @@
*revision = strtoul(x + 2, 0, 16);
}
}
+
+done:
+ close(fd);
+ free(data);
}
void import_kernel_cmdline(int in_qemu,
void (*import_kernel_nv)(char *name, int in_qemu))
{
- char cmdline[1024];
+ char cmdline[2048];
char *ptr;
int fd;
fd = open("/proc/cmdline", O_RDONLY);
if (fd >= 0) {
- int n = read(fd, cmdline, 1023);
+ int n = read(fd, cmdline, sizeof(cmdline) - 1);
if (n < 0) n = 0;
/* get rid of trailing newline, it happens */
diff --git a/init/util.h b/init/util.h
index 6bca4e6..04b8129 100644
--- a/init/util.h
+++ b/init/util.h
@@ -26,7 +26,7 @@
int mtd_name_to_number(const char *name);
int create_socket(const char *name, int type, mode_t perm,
- uid_t uid, gid_t gid);
+ uid_t uid, gid_t gid, const char *socketcon);
void *read_file(const char *fn, unsigned *_sz);
time_t gettime(void);
unsigned int decode_uid(const char *s);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
new file mode 100644
index 0000000..4197bbb
--- /dev/null
+++ b/libbacktrace/Android.mk
@@ -0,0 +1,176 @@
+LOCAL_PATH:= $(call my-dir)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libunwind
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ unwind.c \
+ unwind_remote.c \
+ unwind_local.c \
+ common.c \
+ demangle.c \
+ map_info.c \
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+ -std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libunwind \
+ libunwind-ptrace \
+ libgccdemangle \
+
+LOCAL_C_INCLUDES := \
+ external/libunwind/include \
+
+# The libunwind code is not in the tree yet, so don't build this library yet.
+#include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# The libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ corkscrew.c \
+ common.c \
+ demangle.c \
+ map_info.c \
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+ -std=gnu99 \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := \
+ libcorkscrew \
+ libdl \
+ libgccdemangle \
+ liblog \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test library, all optimizations turned off
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+ backtrace_testlib.c
+
+LOCAL_CFLAGS += \
+ -std=gnu99 \
+ -O0 \
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+ backtrace_test.c \
+
+LOCAL_CFLAGS += \
+ -std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace_test \
+ libbacktrace \
+
+include $(BUILD_EXECUTABLE)
+
+#----------------------------------------------------------------------------
+# Only linux-x86 host versions of libbacktrace supported.
+#----------------------------------------------------------------------------
+ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
+
+#----------------------------------------------------------------------------
+# The host libbacktrace library using libcorkscrew
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES += \
+ corkscrew.c \
+ common.c \
+ demangle.c \
+ map_info.c \
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+ -std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcorkscrew \
+ libgccdemangle \
+ liblog \
+
+LOCAL_LDLIBS += \
+ -ldl \
+ -lrt \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace host test library, all optimizations turned off
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+ backtrace_testlib.c
+
+LOCAL_CFLAGS += \
+ -std=gnu99 \
+ -O0 \
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace host test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+ backtrace_test.c \
+
+LOCAL_CFLAGS += \
+ -std=gnu99 \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace_test \
+ libbacktrace \
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/backtrace_test.c b/libbacktrace/backtrace_test.c
new file mode 100644
index 0000000..6155c9b
--- /dev/null
+++ b/libbacktrace/backtrace_test.c
@@ -0,0 +1,239 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <backtrace/backtrace.h>
+
+#define FINISH(pid) dump_frames(&backtrace); if (pid < 0) exit(1); else return false;
+
+#define WAIT_INTERVAL_USECS 1000
+
+// Prototypes for functions in the test library.
+int test_level_one(int, int, int, int, bool (*)(pid_t));
+
+int test_recursive_call(int, bool (*)(pid_t));
+
+void dump_frames(const backtrace_t* backtrace) {
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ printf("%zu ", i);
+ if (backtrace->frames[i].map_name) {
+ printf("%s", backtrace->frames[i].map_name);
+ } else {
+ printf("<unknown>");
+ }
+ if (backtrace->frames[i].proc_name) {
+ printf(" %s", backtrace->frames[i].proc_name);
+ if (backtrace->frames[i].proc_offset) {
+ printf("+%" PRIuPTR, backtrace->frames[i].proc_offset);
+ }
+ }
+ printf("\n");
+ }
+}
+
+void wait_for_stop(pid_t pid, size_t max_usecs_to_wait) {
+ siginfo_t si;
+ size_t usecs_waited = 0;
+
+ while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
+ if (usecs_waited >= max_usecs_to_wait) {
+ printf("The process did not get to a stopping point in %zu usecs.\n",
+ usecs_waited);
+ break;
+ }
+ usleep(WAIT_INTERVAL_USECS);
+ usecs_waited += WAIT_INTERVAL_USECS;
+ }
+}
+
+bool check_frame(const backtrace_t* backtrace, size_t frame_num,
+ const char* expected_name) {
+ if (backtrace->frames[frame_num].proc_name == NULL) {
+ printf(" Frame %zu function name expected %s, real value is NULL.\n",
+ frame_num, expected_name);
+ return false;
+ }
+ if (strcmp(backtrace->frames[frame_num].proc_name, expected_name) != 0) {
+ printf(" Frame %zu function name expected %s, real value is %s.\n",
+ frame_num, expected_name, backtrace->frames[frame_num].proc_name);
+ return false;
+ }
+ return true;
+}
+
+bool verify_level_backtrace(pid_t pid) {
+ const char* test_type;
+ if (pid < 0) {
+ test_type = "current";
+ } else {
+ test_type = "running";
+ }
+
+ backtrace_t backtrace;
+ if (!backtrace_get_data(&backtrace, pid)) {
+ printf(" backtrace_get_data failed on %s process.\n", test_type);
+ FINISH(pid);
+ }
+
+ if (backtrace.num_frames == 0) {
+ printf(" backtrace_get_data returned no frames for %s process.\n",
+ test_type);
+ FINISH(pid);
+ }
+
+ // 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].proc_name != NULL &&
+ strcmp(backtrace.frames[i].proc_name, "test_level_one") == 0) {
+ frame_num = i;
+ break;
+ }
+ }
+ if (!frame_num) {
+ printf(" backtrace_get_data did not include the test_level_one frame.\n");
+ FINISH(pid);
+ }
+
+ if (!check_frame(&backtrace, frame_num, "test_level_one")) {
+ FINISH(pid);
+ }
+ if (!check_frame(&backtrace, frame_num-1, "test_level_two")) {
+ FINISH(pid);
+ }
+ if (!check_frame(&backtrace, frame_num-2, "test_level_three")) {
+ FINISH(pid);
+ }
+ if (!check_frame(&backtrace, frame_num-3, "test_level_four")) {
+ FINISH(pid);
+ }
+ backtrace_free_data(&backtrace);
+
+ return true;
+}
+
+bool verify_max_backtrace(pid_t pid) {
+ const char* test_type;
+ if (pid < 0) {
+ test_type = "current";
+ } else {
+ test_type = "running";
+ }
+
+ backtrace_t backtrace;
+ if (!backtrace_get_data(&backtrace, pid)) {
+ printf(" backtrace_get_data failed on %s process.\n", test_type);
+ FINISH(pid);
+ }
+
+ if (backtrace.num_frames != MAX_BACKTRACE_FRAMES) {
+ printf(" backtrace_get_data %s process max frame check failed:\n",
+ test_type);
+ printf(" Expected num frames to be %zu, found %zu\n",
+ MAX_BACKTRACE_FRAMES, backtrace.num_frames);
+ FINISH(pid);
+ }
+ backtrace_free_data(&backtrace);
+
+ return true;
+}
+
+void verify_proc_test(pid_t pid, bool (*verify_func)(pid_t)) {
+ printf(" Waiting 5 seconds for process to get to infinite loop.\n");
+ sleep(5);
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) {
+ printf("Failed to attach to pid %d\n", pid);
+ kill(pid, SIGKILL);
+ exit(1);
+ }
+
+ // Wait up to 1 second for the process to get to a point that we can trace it.
+ wait_for_stop(pid, 1000000);
+
+ bool pass = verify_func(pid);
+ if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
+ printf("Failed to detach from pid %d\n", pid);
+ kill(pid, SIGKILL);
+ exit(1);
+ }
+
+ kill(pid, SIGKILL);
+ int status;
+ if (waitpid(pid, &status, 0) != pid) {
+ printf("Forked process did not terminate properly.\n");
+ exit(1);
+ }
+
+ if (!pass) {
+ exit(1);
+ }
+}
+
+int main() {
+ printf("Running level test on current process...\n");
+ int value = test_level_one(1, 2, 3, 4, verify_level_backtrace);
+ if (value == 0) {
+ printf("This should never happen.\n");
+ exit(1);
+ }
+ printf(" Passed.\n");
+
+ printf("Running max level test on current process...\n");
+ value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, verify_max_backtrace);
+ if (value == 0) {
+ printf("This should never happen.\n");
+ exit(1);
+ }
+ printf(" Passed.\n");
+
+ printf("Running level test on process...\n");
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ value = test_level_one(1, 2, 3, 4, NULL);
+ if (value == 0) {
+ printf("This should never happen.\n");
+ }
+ exit(1);
+ }
+ verify_proc_test(pid, verify_level_backtrace);
+ printf(" Passed.\n");
+
+ printf("Running max frame test on process...\n");
+ if ((pid = fork()) == 0) {
+ value = test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL);
+ if (value == 0) {
+ printf("This should never happen.\n");
+ }
+ exit(1);
+ }
+ verify_proc_test(pid, verify_max_backtrace);
+ printf(" Passed.\n");
+
+ printf("All tests passed.\n");
+ return 0;
+}
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
new file mode 100644
index 0000000..9400549
--- /dev/null
+++ b/libbacktrace/backtrace_testlib.c
@@ -0,0 +1,56 @@
+/*
+ * 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 <stdbool.h>
+#include <unistd.h>
+
+int test_level_four(int one, int two, int three, int four,
+ bool (*callback_func)(pid_t)) {
+ if (callback_func != NULL) {
+ callback_func(-1);
+ } else {
+ while (1) {
+ }
+ }
+ return one + two + three + four;
+}
+
+int test_level_three(int one, int two, int three, int four,
+ bool (*callback_func)(pid_t)) {
+ return test_level_four(one+3, two+6, three+9, four+12, callback_func) + 3;
+}
+
+int test_level_two(int one, int two, int three, int four,
+ bool (*callback_func)(pid_t)) {
+ return test_level_three(one+2, two+4, three+6, four+8, callback_func) + 2;
+}
+
+int test_level_one(int one, int two, int three, int four,
+ bool (*callback_func)(pid_t)) {
+ return test_level_two(one+1, two+2, three+3, four+4, callback_func) + 1;
+}
+
+int test_recursive_call(int level, bool (*callback_func)(pid_t)) {
+ if (level > 0) {
+ return test_recursive_call(level - 1, callback_func) + level;
+ } else if (callback_func != NULL) {
+ callback_func(-1);
+ } else {
+ while (1) {
+ }
+ }
+ return 0;
+}
diff --git a/libbacktrace/common.c b/libbacktrace/common.c
new file mode 100644
index 0000000..20786f4
--- /dev/null
+++ b/libbacktrace/common.c
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+#include <inttypes.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include "common.h"
+
+bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
+ uint32_t* out_value) {
+ if (ptr & 3) {
+ ALOGW("backtrace_read_word: invalid pointer %p", (void*)ptr);
+ *out_value = (uint32_t)-1;
+ return false;
+ }
+
+ // Check if reading from the current process, or a different process.
+ if (backtrace->tid < 0) {
+ const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, ptr);
+ if (map_info && map_info->is_readable) {
+ *out_value = *(uint32_t*)ptr;
+ return true;
+ } else {
+ ALOGW("backtrace_read_word: pointer %p not in a readbale map", (void*)ptr);
+ *out_value = (uint32_t)-1;
+ return false;
+ }
+ } else {
+#if defined(__APPLE__)
+ ALOGW("read_word: MacOS does not support reading from another pid.\n");
+ return false;
+#else
+ // ptrace() returns -1 and sets errno when the operation fails.
+ // To disambiguate -1 from a valid result, we clear errno beforehand.
+ errno = 0;
+ *out_value = ptrace(PTRACE_PEEKTEXT, backtrace->tid, (void*)ptr, NULL);
+ if (*out_value == (uint32_t)-1 && errno) {
+ ALOGW("try_get_word: invalid pointer 0x%08x reading from tid %d, "
+ "ptrace() errno=%d", ptr, backtrace->tid, errno);
+ return false;
+ }
+ return true;
+ }
+#endif
+}
+
+const char *backtrace_get_map_info(
+ const backtrace_t* backtrace, uintptr_t pc, uintptr_t* start_pc) {
+ const backtrace_map_info_t* map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
+ if (map_info) {
+ if (start_pc) {
+ *start_pc = map_info->start;
+ }
+ return map_info->name;
+ }
+ return NULL;
+}
+
+void backtrace_format_frame_data(
+ const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
+ uintptr_t relative_pc;
+ const char* map_name;
+ if (frame->map_name) {
+ map_name = frame->map_name;
+ } else {
+ map_name = "<unknown>";
+ }
+ if (frame->map_offset) {
+ relative_pc = frame->map_offset;
+ } else {
+ relative_pc = frame->pc;
+ }
+ if (frame->proc_name && frame->proc_offset) {
+ snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
+ frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+ frame->proc_name, frame->proc_offset);
+ } else if (frame->proc_name) {
+ snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num,
+ (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->proc_name);
+ } else {
+ snprintf(buf, buf_size, "#%02zu pc %0*" PRIxPTR " %s", frame_num,
+ (int)sizeof(uintptr_t)*2, relative_pc, map_name);
+ }
+}
+
+void free_frame_data(backtrace_t* backtrace) {
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ if (backtrace->frames[i].proc_name) {
+ free(backtrace->frames[i].proc_name);
+ }
+ }
+ backtrace->num_frames = 0;
+}
diff --git a/libbacktrace/common.h b/libbacktrace/common.h
new file mode 100644
index 0000000..9eef964
--- /dev/null
+++ b/libbacktrace/common.h
@@ -0,0 +1,25 @@
+/*
+ * 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 _COMMON_H
+#define _COMMON_H
+
+#include <backtrace/backtrace.h>
+
+/* Common routine to free any data allocated to store frame information. */
+void free_frame_data(backtrace_t* backtrace);
+
+#endif /* _COMMON_H */
diff --git a/libbacktrace/corkscrew.c b/libbacktrace/corkscrew.c
new file mode 100644
index 0000000..899409a
--- /dev/null
+++ b/libbacktrace/corkscrew.c
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include <corkscrew/backtrace.h>
+
+#define __USE_GNU
+#include <dlfcn.h>
+
+#include "common.h"
+#include "demangle.h"
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+ backtrace->num_frames = 0;
+ backtrace->tid = tid;
+ backtrace->private_data = NULL;
+ backtrace->map_info_list = backtrace_create_map_info_list(tid);
+
+ backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+ ssize_t num_frames;
+ if (tid < 0) {
+ // Get data for the current thread.
+ num_frames = unwind_backtrace(frames, 0, MAX_BACKTRACE_FRAMES);
+ } else {
+ // Get data for a different thread.
+ ptrace_context_t* ptrace_context = load_ptrace_context(tid);
+ backtrace->private_data = ptrace_context;
+
+ num_frames = unwind_backtrace_ptrace(
+ tid, ptrace_context, frames, 0, MAX_BACKTRACE_FRAMES);
+ }
+ if (num_frames < 0) {
+ ALOGW("backtrace_get_data: unwind_backtrace_ptrace failed %d\n",
+ num_frames);
+ backtrace_free_data(backtrace);
+ return false;
+ }
+
+ backtrace->num_frames = num_frames;
+ backtrace_frame_data_t* frame;
+ uintptr_t map_start;
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ frame = &backtrace->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 = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ frame->proc_offset = 0;
+ frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+ }
+
+ return true;
+}
+
+void backtrace_free_data(backtrace_t* backtrace) {
+ free_frame_data(backtrace);
+
+ if (backtrace->map_info_list) {
+ backtrace_destroy_map_info_list(backtrace->map_info_list);
+ backtrace->map_info_list = NULL;
+ }
+
+ if (backtrace->private_data) {
+ ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
+ free_ptrace_context(ptrace_context);
+ backtrace->private_data = NULL;
+ }
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset) {
+ const char* symbol_name = NULL;
+ *offset = 0;
+ if (backtrace->tid < 0) {
+ // Get information about the current thread.
+ Dl_info info;
+ const backtrace_map_info_t* map_info;
+ map_info = backtrace_find_map_info(backtrace->map_info_list, pc);
+ if (map_info && dladdr((const void*)pc, &info) && info.dli_sname) {
+ *offset = pc - map_info->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
+ symbol_name = info.dli_sname;
+ }
+ } else {
+ // Get information about a different thread.
+ ptrace_context_t* ptrace_context = (ptrace_context_t*)backtrace->private_data;
+ const map_info_t* map_info;
+ const symbol_t* symbol;
+ find_symbol_ptrace(ptrace_context, pc, &map_info, &symbol);
+ if (symbol) {
+ if (map_info) {
+ *offset = pc - map_info->start - symbol->start;
+ }
+ symbol_name = symbol->name;
+ }
+ }
+
+ char* name = NULL;
+ if (symbol_name) {
+ name = demangle_symbol_name(symbol_name);
+ if (!name) {
+ name = strdup(symbol_name);
+ }
+ }
+ return name;
+}
diff --git a/libbacktrace/demangle.c b/libbacktrace/demangle.c
new file mode 100644
index 0000000..de9a460
--- /dev/null
+++ b/libbacktrace/demangle.c
@@ -0,0 +1,33 @@
+/*
+ * 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 <sys/types.h>
+
+#include "demangle.h"
+
+extern char* __cxa_demangle (const char* mangled, char* buf, size_t* len,
+ int* status);
+
+char* demangle_symbol_name(const char* name) {
+#if defined(__APPLE__)
+ // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+ if (name != NULL && name[0] != '_') {
+ return NULL;
+ }
+#endif
+ // __cxa_demangle handles NULL by returning NULL
+ return __cxa_demangle(name, 0, 0, 0);
+}
diff --git a/libbacktrace/demangle.h b/libbacktrace/demangle.h
new file mode 100644
index 0000000..a5318ac
--- /dev/null
+++ b/libbacktrace/demangle.h
@@ -0,0 +1,25 @@
+/*
+ * 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 _DEMANGLE_H
+#define _DEMANGLE_H
+
+/* Called to demangle a symbol name to be printed. Returns an allocated
+ * string that must be freed by the caller.
+ */
+char* demangle_symbol_name(const char* name);
+
+#endif /* _DEMANGLE_H */
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..9cc6e01
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * 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/libbacktrace/stubs.c b/libbacktrace/stubs.c
new file mode 100644
index 0000000..1741601
--- /dev/null
+++ b/libbacktrace/stubs.c
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+ ALOGW("backtrace_get_data: unsupported architecture.\n");
+ return true;
+}
+
+void backtrace_free_data(backtrace_t* backtrace) {
+ ALOGW("backtrace_free_data: unsupported architecture.\n");
+}
+
+bool backtrace_read_word(const backtrace_t* backtrace, uintptr_t ptr,
+ uint32_t* out_value) {
+ ALOGW("backtrace_read_word: unsupported architecture.\n");
+ return false;
+}
+
+const char *backtrace_get_map_info(const backtrace_t* backtrace,
+ uintptr_t pc, uintptr_t* start_pc) {
+ ALOGW("backtrace_get_map_info: unsupported architecture.\n");
+ return NULL;
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset) {
+ ALOGW("backtrace_get_proc_name: unsupported architecture.\n");
+ return NULL;
+}
+
+void backtrace_format_frame_data(
+ const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size) {
+ ALOGW("backtrace_format_frame_data: unsupported architecture.\n");
+ buf[0] = '\0';
+}
diff --git a/libbacktrace/unwind.c b/libbacktrace/unwind.c
new file mode 100644
index 0000000..f75e518
--- /dev/null
+++ b/libbacktrace/unwind.c
@@ -0,0 +1,57 @@
+/*
+ * 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 <backtrace/backtrace.h>
+
+#include "common.h"
+#include "unwind.h"
+
+bool backtrace_get_data(backtrace_t* backtrace, pid_t tid) {
+ backtrace->num_frames = 0;
+ backtrace->tid = tid;
+
+ backtrace->map_info_list = backtrace_create_map_info_list(tid);
+ if (tid < 0) {
+ return local_get_data(backtrace);
+ } else {
+ return remote_get_data(backtrace);
+ }
+}
+
+/* Free any memory related to the frame data. */
+void backtrace_free_data(backtrace_t* backtrace) {
+ free_frame_data(backtrace);
+
+ if (backtrace->map_info_list) {
+ backtrace_destroy_map_info_list(backtrace->map_info_list);
+ backtrace->map_info_list = NULL;
+ }
+
+ if (backtrace->tid < 0) {
+ local_free_data(backtrace);
+ } else {
+ remote_free_data(backtrace);
+ }
+}
+
+char* backtrace_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset) {
+ if (backtrace->tid < 0) {
+ return local_get_proc_name(backtrace, pc, offset);
+ } else {
+ return remote_get_proc_name(backtrace, pc, offset);
+ }
+}
diff --git a/libbacktrace/unwind.h b/libbacktrace/unwind.h
new file mode 100644
index 0000000..9ba96a4
--- /dev/null
+++ b/libbacktrace/unwind.h
@@ -0,0 +1,34 @@
+/*
+ * 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 _UNWIND_H
+#define _UNWIND_H
+
+bool local_get_data(backtrace_t* backtrace);
+
+void local_free_data(backtrace_t* backtrace);
+
+char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset);
+
+bool remote_get_data(backtrace_t* backtrace);
+
+void remote_free_data(backtrace_t* backtrace);
+
+char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset);
+
+#endif /* _UNWIND_H */
diff --git a/libbacktrace/unwind_local.c b/libbacktrace/unwind_local.c
new file mode 100644
index 0000000..d467d8a
--- /dev/null
+++ b/libbacktrace/unwind_local.c
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "common.h"
+#include "demangle.h"
+
+static bool local_get_frames(backtrace_t* backtrace) {
+ unw_context_t* context = (unw_context_t*)backtrace->private_data;
+ unw_cursor_t cursor;
+
+ int ret = unw_getcontext(context);
+ if (ret < 0) {
+ ALOGW("local_get_frames: unw_getcontext failed %d\n", ret);
+ return false;
+ }
+
+ ret = unw_init_local(&cursor, context);
+ if (ret < 0) {
+ ALOGW("local_get_frames: unw_init_local failed %d\n", ret);
+ return false;
+ }
+
+ backtrace_frame_data_t* frame;
+ bool returnValue = true;
+ backtrace->num_frames = 0;
+ uintptr_t map_start;
+ unw_word_t value;
+ do {
+ frame = &backtrace->frames[backtrace->num_frames];
+ frame->stack_size = 0;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+ frame->proc_name = NULL;
+ frame->proc_offset = 0;
+
+ ret = unw_get_reg(&cursor, UNW_REG_IP, &value);
+ if (ret < 0) {
+ ALOGW("get_frames: Failed to read IP %d\n", ret);
+ returnValue = false;
+ break;
+ }
+ frame->pc = (uintptr_t)value;
+ ret = unw_get_reg(&cursor, UNW_REG_SP, &value);
+ if (ret < 0) {
+ ALOGW("get_frames: Failed to read IP %d\n", ret);
+ returnValue = false;
+ break;
+ }
+ frame->sp = (uintptr_t)value;
+
+ if (backtrace->num_frames) {
+ backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
+ prev->stack_size = frame->sp - prev->sp;
+ }
+
+ frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+
+ frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ backtrace->num_frames++;
+ ret = unw_step (&cursor);
+ } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+ return returnValue;
+}
+
+bool local_get_data(backtrace_t* backtrace) {
+ unw_context_t *context = (unw_context_t*)malloc(sizeof(unw_context_t));
+ backtrace->private_data = context;
+
+ if (!local_get_frames(backtrace)) {
+ backtrace_free_data(backtrace);
+ return false;
+ }
+
+ return true;
+}
+
+void local_free_data(backtrace_t* backtrace) {
+ if (backtrace->private_data) {
+ free(backtrace->private_data);
+ backtrace->private_data = NULL;
+ }
+}
+
+char* local_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset) {
+ unw_context_t* context = (unw_context_t*)backtrace->private_data;
+ char buf[512];
+
+ *offset = 0;
+ unw_word_t value;
+ if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
+ &value, context) >= 0 && buf[0] != '\0') {
+ *offset = (uintptr_t)value;
+ char* symbol = demangle_symbol_name(buf);
+ if (!symbol) {
+ symbol = strdup(buf);
+ }
+ return symbol;
+ }
+ return NULL;
+}
diff --git a/libbacktrace/unwind_remote.c b/libbacktrace/unwind_remote.c
new file mode 100644
index 0000000..1c624d7
--- /dev/null
+++ b/libbacktrace/unwind_remote.c
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libbacktrace"
+
+#include <sys/ptrace.h>
+#include <string.h>
+
+#include <cutils/log.h>
+#include <backtrace/backtrace.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "common.h"
+#include "demangle.h"
+
+typedef struct {
+ unw_addr_space_t addr_space;
+ struct UPT_info* upt_info;
+} backtrace_private_t;
+
+static bool remote_get_frames(backtrace_t* backtrace) {
+ backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+ unw_cursor_t cursor;
+ int ret = unw_init_remote(&cursor, data->addr_space, data->upt_info);
+ if (ret < 0) {
+ ALOGW("remote_get_frames: unw_init_remote failed %d\n", ret);
+ return false;
+ }
+
+ backtrace_frame_data_t* frame;
+ bool returnValue = true;
+ backtrace->num_frames = 0;
+ uintptr_t map_start;
+ unw_word_t value;
+ do {
+ frame = &backtrace->frames[backtrace->num_frames];
+ frame->stack_size = 0;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+ frame->proc_name = NULL;
+ frame->proc_offset = 0;
+
+ ret = unw_get_reg(&cursor, UNW_REG_IP, &value);
+ if (ret < 0) {
+ ALOGW("remote_get_frames: Failed to read IP %d\n", ret);
+ returnValue = false;
+ break;
+ }
+ frame->pc = (uintptr_t)value;
+ ret = unw_get_reg(&cursor, UNW_REG_SP, &value);
+ if (ret < 0) {
+ ALOGW("remote_get_frames: Failed to read SP %d\n", ret);
+ returnValue = false;
+ break;
+ }
+ frame->sp = (uintptr_t)value;
+
+ if (backtrace->num_frames) {
+ backtrace_frame_data_t* prev = &backtrace->frames[backtrace->num_frames-1];
+ prev->stack_size = frame->sp - prev->sp;
+ }
+
+ frame->proc_name = backtrace_get_proc_name(backtrace, frame->pc, &frame->proc_offset);
+
+ frame->map_name = backtrace_get_map_info(backtrace, frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ backtrace->num_frames++;
+ ret = unw_step (&cursor);
+ } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+ return returnValue;
+}
+
+bool remote_get_data(backtrace_t* backtrace) {
+ backtrace_private_t* data = (backtrace_private_t*)malloc(sizeof(backtrace_private_t));
+ if (!data) {
+ ALOGW("remote_get_data: Failed to allocate memory.\n");
+ backtrace_free_data(backtrace);
+ return false;
+ }
+ data->addr_space = NULL;
+ data->upt_info = NULL;
+
+ backtrace->private_data = data;
+ data->addr_space = unw_create_addr_space(&_UPT_accessors, 0);
+ if (!data->addr_space) {
+ ALOGW("remote_get_data: Failed to create unw address space.\n");
+ backtrace_free_data(backtrace);
+ return false;
+ }
+
+ data->upt_info = _UPT_create(backtrace->tid);
+ if (!data->upt_info) {
+ ALOGW("remote_get_data: Failed to create upt info.\n");
+ backtrace_free_data(backtrace);
+ return false;
+ }
+
+ if (!remote_get_frames(backtrace)) {
+ backtrace_free_data(backtrace);
+ return false;
+ }
+
+ return true;
+}
+
+void remote_free_data(backtrace_t* backtrace) {
+ if (backtrace->private_data) {
+ backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+ if (data->upt_info) {
+ _UPT_destroy(data->upt_info);
+ data->upt_info = NULL;
+ }
+ if (data->addr_space) {
+ unw_destroy_addr_space(data->addr_space);
+ }
+
+ free(backtrace->private_data);
+ backtrace->private_data = NULL;
+ }
+}
+
+char* remote_get_proc_name(const backtrace_t* backtrace, uintptr_t pc,
+ uintptr_t* offset) {
+ backtrace_private_t* data = (backtrace_private_t*)backtrace->private_data;
+ char buf[512];
+
+ *offset = 0;
+ unw_word_t value;
+ if (unw_get_proc_name_by_ip(data->addr_space, pc, buf, sizeof(buf), &value,
+ data->upt_info) >= 0 && buf[0] != '\0') {
+ *offset = (uintptr_t)value;
+ char* symbol = demangle_symbol_name(buf);
+ if (!symbol) {
+ symbol = strdup(buf);
+ }
+ return symbol;
+ }
+ return NULL;
+}
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index d62c2d5..e275317 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -51,7 +51,7 @@
LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
@@ -81,7 +81,7 @@
LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
LOCAL_LDLIBS += -lrt
endif
-LOCAL_CFLAGS += -std=gnu99 -Werror
+LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index e133ab6..ef22821 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -380,7 +380,7 @@
case DW_CFA_offset_extended: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
- if (reg > DWARF_REGISTERS) {
+ if (reg >= DWARF_REGISTERS) {
ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
return false;
}
@@ -390,39 +390,39 @@
break;
case DW_CFA_restore_extended: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- dstate->regs[reg].rule = stack->regs[reg].rule;
- dstate->regs[reg].value = stack->regs[reg].value;
- if (reg > DWARF_REGISTERS) {
+ if (reg >= DWARF_REGISTERS) {
ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
return false;
}
+ dstate->regs[reg].rule = stack->regs[reg].rule;
+ dstate->regs[reg].value = stack->regs[reg].value;
ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value);
break;
case DW_CFA_undefined: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- dstate->regs[reg].rule = 'u';
- dstate->regs[reg].value = 0;
- if (reg > DWARF_REGISTERS) {
+ if (reg >= DWARF_REGISTERS) {
ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
return false;
}
+ dstate->regs[reg].rule = 'u';
+ dstate->regs[reg].value = 0;
ALOGV("DW_CFA_undefined: r%d", reg);
break;
case DW_CFA_same_value: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- dstate->regs[reg].rule = 's';
- dstate->regs[reg].value = 0;
- if (reg > DWARF_REGISTERS) {
+ if (reg >= DWARF_REGISTERS) {
ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
return false;
}
+ dstate->regs[reg].rule = 's';
+ dstate->regs[reg].value = 0;
ALOGV("DW_CFA_same_value: r%d", reg);
break;
case DW_CFA_register: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
/* that's new register actually, not offset */
if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
- if (reg > DWARF_REGISTERS || offset > DWARF_REGISTERS) {
+ if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) {
ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
return false;
}
@@ -520,7 +520,7 @@
/* Updaing state based on dwarf state. */
static bool update_state(const memory_t* memory, unwind_state_t* state,
- dwarf_state_t* dstate, cie_info_t* cie_info) {
+ dwarf_state_t* dstate) {
unwind_state_t newstate;
/* We can restore more registers here if we need them. Meanwile doing minimal work here. */
/* Getting CFA. */
@@ -550,7 +550,6 @@
/* Execute CIE and FDE instructions for FDE found with find_fde. */
static bool execute_fde(const memory_t* memory,
- const map_info_t* map_info_list,
uintptr_t fde,
unwind_state_t* state) {
uint32_t fde_length = 0;
@@ -753,7 +752,7 @@
ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
}
- return update_state(memory, state, dstate, cie_info);
+ return update_state(memory, state, dstate);
}
static ssize_t unwind_backtrace_common(const memory_t* memory,
@@ -805,7 +804,7 @@
uint32_t stack_top = state->reg[DWARF_ESP];
- if (!execute_fde(memory, map_info_list, fde, state)) break;
+ if (!execute_fde(memory, fde, state)) break;
if (frame) {
frame->stack_top = stack_top;
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 0fd5a57..62f4290 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -115,18 +115,22 @@
uevent.c
ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += arch-arm/memset32.S
+ LOCAL_SRC_FILES += arch-arm/memset32.S
else # !arm
-ifeq ($(TARGET_ARCH_VARIANT),x86-atom)
-LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
-LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
-else # !x86-atom
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += arch-mips/android_memset.c
-else # !mips
-LOCAL_SRC_FILES += memory.c
-endif # !mips
-endif # !x86-atom
+ ifeq ($(TARGET_ARCH),x86)
+ ifeq ($(ARCH_X86_HAVE_SSE2),true)
+ LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 -DUSE_SSE2
+ LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
+ else # !ARCH_X86_HAVE_SSE2
+ LOCAL_SRC_FILES += memory.c
+ endif # !ARCH_X86_HAVE_SSE2
+ else # !x86
+ ifeq ($(TARGET_ARCH),mips)
+ LOCAL_SRC_FILES += arch-mips/android_memset.c
+ else # !mips
+ LOCAL_SRC_FILES += memory.c
+ endif # !mips
+ endif # !x86
endif # !arm
LOCAL_C_INCLUDES := $(libcutils_c_includes) $(KERNEL_HEADERS)
diff --git a/libcutils/ashmem-dev.c b/libcutils/ashmem-dev.c
index 8b71f87..3089a94 100644
--- a/libcutils/ashmem-dev.c
+++ b/libcutils/ashmem-dev.c
@@ -48,7 +48,7 @@
return fd;
if (name) {
- char buf[ASHMEM_NAME_LEN];
+ char buf[ASHMEM_NAME_LEN] = {0};
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5014e4a..2428022 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -46,15 +46,6 @@
#define off64_t off_t
#endif
-#ifdef __BIONIC__
-extern void* __mmap2(void *, size_t, int, int, int, off_t);
-static inline void *mmap64(void *addr, size_t length, int prot, int flags,
- int fd, off64_t offset)
-{
- return __mmap2(addr, length, prot, flags, fd, offset >> 12);
-}
-#endif
-
#define min(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 242ab35..9171d85 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -24,6 +24,7 @@
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
+#define BOOT_EXTRA_ARGS_SIZE 1024
struct boot_img_hdr
{
@@ -43,10 +44,14 @@
unsigned unused[2]; /* future expansion: should be 0 */
unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
-
+
unsigned char cmdline[BOOT_ARGS_SIZE];
unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+
+ /* Supplemental command line data; kept here to maintain
+ * binary compatibility with older versions of mkbootimg */
+ unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
};
/*
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 34a879b..d598f03 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -114,6 +114,7 @@
unsigned ramdisk_offset = 0x01000000;
unsigned second_offset = 0x00f00000;
unsigned tags_offset = 0x00000100;
+ size_t cmdlen;
argc--;
argv++;
@@ -192,11 +193,19 @@
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
- if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
+ cmdlen = strlen(cmdline);
+ if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
fprintf(stderr,"error: kernel commandline too large\n");
return 1;
}
- strcpy((char*)hdr.cmdline, cmdline);
+ /* Even if we need to use the supplemental field, ensure we
+ * are still NULL-terminated */
+ strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
+ hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
+ if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
+ cmdline += (BOOT_ARGS_SIZE - 1);
+ strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
+ }
kernel_data = load_file(kernel_fn, &hdr.kernel_size);
if(kernel_data == 0) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 86e124f..7a189e3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -17,6 +17,9 @@
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
+ # Set the security context of /adb_keys if present.
+ restorecon /adb_keys
+
start ueventd
# create mountpoints
@@ -219,6 +222,10 @@
mkdir /data/local 0751 root root
mkdir /data/misc/media 0700 media media
+ # Set security context of any pre-existing /data/misc/adb/adb_keys file.
+ restorecon /data/misc/adb
+ restorecon /data/misc/adb/adb_keys
+
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
@@ -256,6 +263,9 @@
# Separate location for storing security policy files on data
mkdir /data/security 0711 system system
+ # Reload policy from /data/security if present.
+ setprop selinux.reload_policy 1
+
# If there is no fs-post-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
# won't work.
@@ -350,7 +360,6 @@
chown root radio /proc/cmdline
# Set these so we can remotely update SELinux policy
- chown system system /sys/fs/selinux/load
chown system system /sys/fs/selinux/enforce
# Define TCP buffer sizes for various networks
@@ -420,10 +429,6 @@
critical
seclabel u:r:healthd:s0
-on property:selinux.reload_policy=1
- restart ueventd
- restart installd
-
service console /system/bin/sh
class core
console
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2cf0265..a60cfc5 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -5,6 +5,8 @@
/dev/tty 0666 root root
/dev/random 0666 root root
/dev/urandom 0666 root root
+# Make HW RNG readable by group system to let EntropyMixer read it.
+/dev/hw_random 0440 root system
/dev/ashmem 0666 root root
/dev/binder 0666 root root