summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adb/adb_client.c4
-rw-r--r--adb/commandline.c2
-rw-r--r--adb/file_sync_client.c2
-rw-r--r--adb/file_sync_service.c1
-rw-r--r--adb/framebuffer_service.c16
-rw-r--r--adb/usb_vendors.c7
-rw-r--r--cpio/mkbootfs.c2
-rw-r--r--debuggerd/Android.mk6
-rw-r--r--debuggerd/arm/machine.c44
-rw-r--r--debuggerd/backtrace.c41
-rw-r--r--debuggerd/backtrace.h8
-rw-r--r--debuggerd/machine.h8
-rw-r--r--debuggerd/mips/machine.c47
-rw-r--r--debuggerd/tombstone.c207
-rw-r--r--debuggerd/x86/machine.c18
-rw-r--r--fastboot/Android.mk5
-rw-r--r--fastboot/engine.c31
-rw-r--r--fastboot/fastboot.c21
-rw-r--r--fastboot/fastboot.h3
-rw-r--r--fastboot/usb.h2
-rw-r--r--fastboot/usb_linux.c226
-rw-r--r--fastboot/usb_osx.c5
-rw-r--r--fastboot/usb_windows.c5
-rw-r--r--fastboot/util.c69
-rw-r--r--fs_mgr/fs_mgr.c94
-rw-r--r--gpttool/gpttool.c2
-rw-r--r--include/backtrace/Backtrace.h86
-rw-r--r--include/backtrace/backtrace.h114
-rw-r--r--include/cutils/list.h5
-rw-r--r--include/mincrypt/dsa_sig.h43
-rw-r--r--include/mincrypt/hash-internal.h35
-rw-r--r--include/mincrypt/p256.h162
-rw-r--r--include/mincrypt/p256_ecdsa.h53
-rw-r--r--include/mincrypt/rsa.h6
-rw-r--r--include/mincrypt/sha.h34
-rw-r--r--include/mincrypt/sha256.h35
-rw-r--r--init/Android.mk1
-rw-r--r--init/builtins.c16
-rw-r--r--init/devices.c11
-rw-r--r--init/init.c48
-rw-r--r--init/init.h5
-rw-r--r--init/init_parser.c11
-rw-r--r--init/keywords.h2
-rw-r--r--init/logo.c163
-rw-r--r--init/property_service.c25
-rw-r--r--init/readme.txt13
-rw-r--r--init/util.c59
-rw-r--r--init/util.h2
-rw-r--r--libbacktrace/Android.mk265
-rw-r--r--libbacktrace/Backtrace.cpp307
-rw-r--r--libbacktrace/Backtrace.h66
-rw-r--r--libbacktrace/BacktraceThread.cpp228
-rw-r--r--libbacktrace/BacktraceThread.h92
-rw-r--r--libbacktrace/Corkscrew.cpp200
-rw-r--r--libbacktrace/Corkscrew.h74
-rw-r--r--libbacktrace/UnwindCurrent.cpp215
-rw-r--r--libbacktrace/UnwindCurrent.h56
-rw-r--r--libbacktrace/UnwindPtrace.cpp136
-rw-r--r--libbacktrace/UnwindPtrace.h40
-rw-r--r--libbacktrace/backtrace_test.cpp660
-rw-r--r--libbacktrace/backtrace_testlib.c55
-rw-r--r--libbacktrace/map_info.c173
-rw-r--r--libbacktrace/thread_utils.c42
-rw-r--r--libbacktrace/thread_utils.h30
-rw-r--r--libcorkscrew/Android.mk4
-rwxr-xr-xlibcorkscrew/arch-x86/backtrace-x86.c29
-rw-r--r--libcutils/Android.mk27
-rw-r--r--libcutils/arch-x86/android_memset16.S7
-rw-r--r--libcutils/arch-x86/android_memset32.S8
-rwxr-xr-x[-rw-r--r--]libcutils/arch-x86/sse2-memset16-atom.S8
-rwxr-xr-x[-rw-r--r--]libcutils/arch-x86/sse2-memset32-atom.S8
-rw-r--r--libcutils/ashmem-dev.c2
-rw-r--r--libcutils/dir_hash.c1
-rw-r--r--libmincrypt/Android.mk10
-rw-r--r--libmincrypt/dsa_sig.c125
-rw-r--r--libmincrypt/p256.c375
-rw-r--r--libmincrypt/p256_ec.c1279
-rw-r--r--libmincrypt/p256_ecdsa.c56
-rw-r--r--libmincrypt/test/Android.mk9
-rw-r--r--libmincrypt/test/ecdsa_test.c278
-rw-r--r--libmincrypt/tools/Android.mk3
-rw-r--r--libmincrypt/tools/DumpPublicKey.java111
-rw-r--r--libsparse/backed_block.c2
-rw-r--r--libsparse/output_file.c11
-rw-r--r--mkbootimg/bootimg.h7
-rw-r--r--mkbootimg/mkbootimg.c13
-rw-r--r--rootdir/init.rc15
-rw-r--r--rootdir/ueventd.rc2
88 files changed, 6074 insertions, 760 deletions
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 8340738..f7823a8 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -278,7 +278,9 @@ int adb_connect(const char *service)
return 0;
fd = _adb_connect(service);
- if(fd == -2) {
+ if(fd == -1) {
+ fprintf(stderr,"error: %s\n", __adb_error);
+ } else if(fd == -2) {
fprintf(stderr,"** daemon still not running\n");
}
D("adb_connect: return fd %d\n", fd);
diff --git a/adb/commandline.c b/adb/commandline.c
index 27a1754..c9bb437 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -767,7 +767,7 @@ static int restore(int argc, char** argv) {
fd = adb_connect("restore:");
if (fd < 0) {
- fprintf(stderr, "adb: unable to connect for backup\n");
+ fprintf(stderr, "adb: unable to connect for restore\n");
adb_close(tarFd);
return -1;
}
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 354d0fb..9fec081 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -642,8 +642,8 @@ static int local_build_list(copyinfo **filelist,
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+ free(ci);
closedir(d);
-
return -1;
}
if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index d3e841b..f24f14c 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -110,6 +110,7 @@ static int do_list(int s, const char *path)
if(writex(s, &msg.dent, sizeof(msg.dent)) ||
writex(s, de->d_name, len)) {
+ closedir(d);
return -1;
}
}
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 @@ struct fbinfo {
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 @@ void framebuffer_service(int fd, void *cookie)
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 @@ int builtInVendorIds[] = {
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/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 3569e27..7d3740c 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -220,6 +220,8 @@ static void _archive_dir(char *in, char *out, int ilen, int olen)
free(names[i]);
}
free(names);
+
+ closedir(d);
}
static void _archive(char *in, char *out, int ilen, int olen)
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 @@ LOCAL_CFLAGS += -DWITH_VFP_D32
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 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
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 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
* 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, &regs)) {
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 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
continue;
}
- _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+ _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_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 @@ void dump_registers(const ptrace_context_t* context __attribute((unused)),
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..aa7a3c2 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 @@ static void dump_process_footer(log_t* log, pid_t pid) {
_LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
}
-static void dump_thread(log_t* log, pid_t tid, 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 @@ static void dump_thread(log_t* log, pid_t tid, ptrace_context_t* context, bool a
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_context_t context;
+ if (!backtrace_create_context(&context, tid, -1, 0)) {
+ _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(&context, log, SCOPE_AT_FAULT, " ");
+ backtrace_destroy_context(&context);
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
@@ -120,9 +110,8 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
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 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
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_context_t* context, log_t* log,
+ int scope_flags, const char* prefix) {
+ char buf[512];
+ for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+ backtrace_format_frame_data(context, i, buf, sizeof(buf));
+ _LOG(log, scope_flags, "%s%s\n", prefix, buf);
+ }
}
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index c5c786a..54a60b2 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_context_t* context, 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 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
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 @@ static void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scopeFlags) {
* 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 @@ void dump_memory_and_code(const ptrace_context_t* context __attribute((unused)),
continue;
}
- _LOG(log, scopeFlags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scopeFlags | SCOPE_SENSITIVE);
+ _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", &REG_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..aa63547 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_fault_addr(log_t* log, pid_t tid, int sig)
}
}
-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 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
}
}
- if (at_fault) {
+ if (IS_AT_FAULT(scope_flags)) {
char procnamebuf[1024];
char* procname = NULL;
@@ -230,64 +228,46 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, bool at_fault) {
}
}
-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_context_t* context, log_t* log,
+ int scope_flags, uintptr_t *sp, size_t words, int label) {
for (size_t i = 0; i < words; i++) {
uint32_t stack_content;
- if (!try_get_word_ptrace(tid, *sp, &stack_content)) {
+ if (!backtrace_read_word(context, *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_name(context, stack_content, NULL);
+ if (!map_name) {
+ map_name = "";
+ }
+ uintptr_t offset = 0;
+ char* func_name = backtrace_get_func_name(context, stack_content, &offset);
+ if (func_name) {
if (!i && label >= 0) {
if (offset) {
- _LOG(log, 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, func_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, func_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, func_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, func_name);
}
}
- free(demangled_name);
+ free(func_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,43 @@ static void dump_stack_segment(const ptrace_context_t* context, log_t* log, pid_
}
}
-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_context_t* context, log_t* log, int scope_flags) {
+ const backtrace_t* backtrace = context->backtrace;
+ size_t first = 0, last;
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ if (backtrace->frames[i].sp) {
+ if (!first) {
+ first = i+1;
}
last = i;
}
}
- if (!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(context, log, scope_flags, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
- const backtrace_frame_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(context, log, scope_flags, &sp, STACK_WORDS, i);
+ if (sp < frame->sp + frame->stack_size) {
+ _LOG(log, scope_flags, " ........ ........\n");
}
} else {
size_t words = frame->stack_size / sizeof(uint32_t);
@@ -342,39 +320,40 @@ static void dump_stack(const ptrace_context_t* context, log_t* log, pid_t tid, b
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(context, log, tid, scopeFlags, &sp, words, i);
+ dump_stack_segment(context, 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_context_t* context,
+ log_t* log, int scope_flags) {
+ if (context->backtrace->num_frames) {
+ _LOG(log, scope_flags, "\nbacktrace:\n");
+ dump_backtrace_to_log(context, log, scope_flags, " ");
+
+ _LOG(log, scope_flags, "\nstack:\n");
+ dump_stack(context, log, scope_flags);
}
}
-static void dump_map(log_t* log, 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 +367,15 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
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 +395,32 @@ static void dump_nearby_maps(const ptrace_context_t* context, log_t* log, pid_t
* 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,
- int* total_sleep_time_usec) {
- wait_for_stop(tid, total_sleep_time_usec);
+static void dump_thread(const backtrace_context_t* context, log_t* log,
+ int scope_flags, int* total_sleep_time_usec) {
+ const backtrace_t* backtrace = context->backtrace;
+ wait_for_stop(backtrace->tid, total_sleep_time_usec);
- dump_registers(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(context, log, scope_flags);
+ if (IS_AT_FAULT(scope_flags)) {
+ dump_memory_and_code(log, backtrace->tid, scope_flags);
+ dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags);
}
}
/* Return true if some thread is not detached cleanly */
-static bool dump_sibling_thread_report(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 +447,12 @@ static bool dump_sibling_thread_report(const ptrace_context_t* context,
}
_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_context_t new_context;
+ if (backtrace_create_context(&new_context, pid, new_tid, 0)) {
+ dump_thread(&new_context, log, 0, total_sleep_time_usec);
+ backtrace_destroy_context(&new_context);
+ }
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
@@ -624,7 +608,7 @@ static void dump_logs(log_t* log, pid_t pid, bool tailOnly)
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_context_t* context, log_t* log, uintptr_t address) {
if (address == 0) {
return;
}
@@ -636,7 +620,7 @@ static void dump_abort_message(log_t* log, pid_t tid, uintptr_t address) {
char* p = &msg[0];
while (p < &msg[sizeof(msg)]) {
uint32_t data;
- if (!try_get_word_ptrace(tid, address, &data)) {
+ if (!backtrace_read_word(context, address, &data)) {
break;
}
address += sizeof(uint32_t);
@@ -686,14 +670,17 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\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_context_t context;
+ if (backtrace_create_context(&context, pid, tid, 0)) {
+ dump_abort_message(&context, log, abort_msg_address);
+ dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec);
+ backtrace_destroy_context(&context);
+ }
if (want_logs) {
dump_logs(log, pid, true);
@@ -701,11 +688,9 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
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/Android.mk b/fastboot/Android.mk
index 1189e1f..b9b3c92 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,9 +18,10 @@ include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
$(LOCAL_PATH)/../../extras/ext4_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
+LOCAL_CFLAGS += -std=gnu99
ifeq ($(HOST_OS),linux)
LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -69,7 +70,7 @@ $(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := usbtest.c usb_linux.c
+LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c
LOCAL_MODULE := usbtest
include $(BUILD_HOST_EXECUTABLE)
endif
diff --git a/fastboot/engine.c b/fastboot/engine.c
index b07e742..972c4ed 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -36,7 +36,6 @@
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
@@ -48,34 +47,13 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-double now()
-{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
-}
-
-char *mkmsg(const char *fmt, ...)
-{
- char buf[256];
- char *s;
- va_list ap;
-
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- va_end(ap);
-
- s = strdup(buf);
- if (s == 0) die("out of memory");
- return s;
-}
-
#define OP_DOWNLOAD 1
#define OP_COMMAND 2
#define OP_QUERY 3
#define OP_NOTICE 4
#define OP_FORMAT 5
#define OP_DOWNLOAD_SPARSE 6
+#define OP_WAIT_FOR_DISCONNECT 7
typedef struct Action Action;
@@ -573,6 +551,11 @@ void fb_queue_notice(const char *notice)
a->data = (void*) notice;
}
+void fb_queue_wait_for_disconnect(void)
+{
+ queue_action(OP_WAIT_FOR_DISCONNECT, "");
+}
+
int fb_execute_queue(usb_handle *usb)
{
Action *a;
@@ -614,6 +597,8 @@ int fb_execute_queue(usb_handle *usb)
status = fb_download_data_sparse(usb, a->data);
status = a->func(a, status, status ? fb_get_error() : "");
if (status) break;
+ } else if (a->op == OP_WAIT_FOR_DISCONNECT) {
+ usb_wait_for_disconnect(usb);
} else {
die("bogus action");
}
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index f186c93..73a6e56 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -30,7 +30,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
@@ -106,17 +105,6 @@ static struct {
{"system.img", "system.sig", "system", false},
};
-void die(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- fprintf(stderr,"error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr,"\n");
- va_end(ap);
- exit(1);
-}
-
void get_my_path(char *path);
char *find_item(const char *item, const char *product)
@@ -503,7 +491,13 @@ static int setup_requirement_line(char *name)
for(n = 0; n < count; n++) {
out[n] = strdup(strip(val[n]));
- if (out[n] == 0) return -1;
+ if (out[n] == 0) {
+ for(size_t i = 0; i < n; ++i) {
+ free((char*) out[i]);
+ }
+ free(out);
+ return -1;
+ }
}
fb_queue_require(prod, name, invert, n, out);
@@ -1102,6 +1096,7 @@ int main(int argc, char **argv)
fb_queue_reboot();
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
+ fb_queue_wait_for_disconnect();
}
if (fb_queue_is_empty())
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index c1b2964..976c397 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -58,10 +58,13 @@ void fb_queue_reboot(void);
void fb_queue_command(const char *cmd, const char *msg);
void fb_queue_download(const char *name, void *data, unsigned size);
void fb_queue_notice(const char *notice);
+void fb_queue_wait_for_disconnect(void);
int fb_execute_queue(usb_handle *usb);
int fb_queue_is_empty(void);
/* util stuff */
+double now();
+char *mkmsg(const char *fmt, ...);
void die(const char *fmt, ...);
/* Current product */
diff --git a/fastboot/usb.h b/fastboot/usb.h
index d504ee2..17cf0a9 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -62,6 +62,6 @@ usb_handle *usb_open(ifc_match_func callback);
int usb_close(usb_handle *h);
int usb_read(usb_handle *h, void *_data, int len);
int usb_write(usb_handle *h, const void *_data, int len);
-
+int usb_wait_for_disconnect(usb_handle *h);
#endif
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index b7a9ca3..f2ce226 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -50,10 +50,17 @@
#endif
#include <asm/byteorder.h>
+#include "fastboot.h"
#include "usb.h"
#define MAX_RETRIES 5
+/* Timeout in seconds for usb_wait_for_disconnect.
+ * It doesn't usually take long for a device to disconnect (almost always
+ * under 2 seconds) but we'll time out after 3 seconds just in case.
+ */
+#define WAIT_FOR_DISCONNECT_TIMEOUT 3
+
#ifdef TRACE_USB
#define DBG1(x...) fprintf(stderr, x)
#define DBG(x...) fprintf(stderr, x)
@@ -75,10 +82,18 @@ struct usb_handle
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 +110,8 @@ static int check(void *_desc, int len, unsigned type, int size)
return 0;
}
-static int filter_usb_device(int fd, char *ptr, int len, int writable,
+static int filter_usb_device(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 +147,35 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable,
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];
-
- 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;
- }
- }
+ snprintf(info.device_path, sizeof(info.device_path), "usb:%s", sysfs_name);
- /* 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 +223,73 @@ static int filter_usb_device(int fd, char *ptr, int len, int writable,
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 +300,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
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 +315,7 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
n = read(fd, desc, sizeof(desc));
- if(filter_usb_device(fd, desc, n, writable, callback,
+ if(filter_usb_device(de->d_name, desc, n, writable, callback,
&in, &out, &ifc) == 0) {
usb = calloc(1, sizeof(usb_handle));
strcpy(usb->fname, devname);
@@ -301,7 +334,6 @@ static usb_handle *find_usb_device(const char *base, ifc_match_func callback)
close(fd);
}
}
- closedir(devdir);
}
closedir(busdir);
@@ -315,26 +347,11 @@ int usb_write(usb_handle *h, const void *_data, int len)
struct usbdevfs_bulktransfer bulk;
int n;
- if(h->ep_out == 0) {
+ if(h->ep_out == 0 || h->desc == -1) {
return -1;
}
- if(len == 0) {
- bulk.ep = h->ep_out;
- bulk.len = 0;
- bulk.data = data;
- bulk.timeout = 0;
-
- n = ioctl(h->desc, USBDEVFS_BULK, &bulk);
- if(n != 0) {
- fprintf(stderr,"ERROR: n = %d, errno = %d (%s)\n",
- n, errno, strerror(errno));
- return -1;
- }
- return 0;
- }
-
- while(len > 0) {
+ do {
int xfer;
xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
@@ -353,7 +370,7 @@ int usb_write(usb_handle *h, const void *_data, int len)
count += xfer;
len -= xfer;
data += xfer;
- }
+ } while(len > 0);
return count;
}
@@ -365,7 +382,7 @@ int usb_read(usb_handle *h, void *_data, int len)
struct usbdevfs_bulktransfer bulk;
int n, retry;
- if(h->ep_in == 0) {
+ if(h->ep_in == 0 || h->desc == -1) {
return -1;
}
@@ -431,5 +448,20 @@ int usb_close(usb_handle *h)
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);
+}
+
+/* Wait for the system to notice the device is gone, so that a subsequent
+ * fastboot command won't try to access the device before it's rebooted.
+ * Returns 0 for success, -1 for timeout.
+ */
+int usb_wait_for_disconnect(usb_handle *usb)
+{
+ double deadline = now() + WAIT_FOR_DISCONNECT_TIMEOUT;
+ while (now() < deadline) {
+ if (access(usb->fname, F_OK))
+ return 0;
+ usleep(50000);
+ }
+ return -1;
}
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.c
index 1548ba8..0f55e0d 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.c
@@ -467,6 +467,11 @@ int usb_close(usb_handle *h) {
return 0;
}
+int usb_wait_for_disconnect(usb_handle *usb) {
+ /* TODO: Punt for now */
+ return 0;
+}
+
int usb_read(usb_handle *h, void *data, int len) {
IOReturn result;
UInt32 numBytes = len;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 7aa36b2..07f7be2 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -269,6 +269,11 @@ int usb_close(usb_handle* handle) {
return 0;
}
+int usb_wait_for_disconnect(usb_handle *usb) {
+ /* TODO: Punt for now */
+ return 0;
+}
+
int recognized_device(usb_handle* handle, ifc_match_func callback) {
struct usb_ifc_info info;
USB_DEVICE_DESCRIPTOR device_desc;
diff --git a/fastboot/util.c b/fastboot/util.c
new file mode 100644
index 0000000..f2bbd34
--- /dev/null
+++ b/fastboot/util.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/time.h>
+
+#include "fastboot.h"
+
+double now()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
+}
+
+char *mkmsg(const char *fmt, ...)
+{
+ char buf[256];
+ char *s;
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ va_end(ap);
+
+ s = strdup(buf);
+ if (s == 0) die("out of memory");
+ return s;
+}
+
+void die(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr,"error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr,"\n");
+ va_end(ap);
+ exit(1);
+}
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 @@ out:
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 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
}
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 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
if (!entries) {
ERROR("No entries found in fstab\n");
- return 0;
+ goto err;
}
/* Allocate and init the fstab structure */
@@ -349,9 +290,8 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
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 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
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 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
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 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
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 @@ void fs_mgr_free_fstab(struct fstab *fstab)
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/gpttool/gpttool.c b/gpttool/gpttool.c
index 05d5177..d3f08fe 100644
--- a/gpttool/gpttool.c
+++ b/gpttool/gpttool.c
@@ -161,7 +161,7 @@ void show(struct ptable *ptbl)
{
struct efi_entry *entry = ptbl->entry;
unsigned n, m;
- char name[EFI_NAMELEN];
+ char name[EFI_NAMELEN + 1];
fprintf(stderr,"ptn start block end block name\n");
fprintf(stderr,"---- ------------- ------------- --------------------\n");
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
new file mode 100644
index 0000000..b15678c
--- /dev/null
+++ b/include/backtrace/Backtrace.h
@@ -0,0 +1,86 @@
+/*
+ * 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_BACKTRACE_H
+#define _BACKTRACE_BACKTRACE_H
+
+#include <backtrace/backtrace.h>
+
+#include <string>
+
+class BacktraceImpl;
+
+class Backtrace {
+public:
+ // Create the correct Backtrace object based on what is to be unwound.
+ // If pid < 0 or equals the current pid, then the Backtrace object
+ // corresponds to the current process.
+ // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
+ // object corresponds to a thread in the current process.
+ // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
+ // different process.
+ // Tracing a thread in a different process is not supported.
+ static Backtrace* Create(pid_t pid, pid_t tid);
+
+ virtual ~Backtrace();
+
+ // Get the current stack trace and store in the backtrace_ structure.
+ virtual bool Unwind(size_t num_ignore_frames);
+
+ // Get the function name and offset into the function given the pc.
+ // If the string is empty, then no valid function name was found.
+ virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+
+ // Get the name of the map associated with the given pc. If NULL is returned,
+ // then map_start is not set. Otherwise, map_start is the beginning of this
+ // map.
+ virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start);
+
+ // Finds the memory map associated with the given ptr.
+ virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);
+
+ // Read the data at a specific address.
+ virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
+
+ // Create a string representing the formatted line of backtrace information
+ // for a single frame.
+ virtual std::string FormatFrameData(size_t frame_num);
+
+ pid_t Pid() { return backtrace_.pid; }
+ pid_t Tid() { return backtrace_.tid; }
+ size_t NumFrames() { return backtrace_.num_frames; }
+
+ const backtrace_t* GetBacktrace() { return &backtrace_; }
+
+ const backtrace_frame_data_t* GetFrame(size_t frame_num) {
+ return &backtrace_.frames[frame_num];
+ }
+
+protected:
+ Backtrace(BacktraceImpl* impl);
+
+ virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
+
+ BacktraceImpl* impl_;
+
+ backtrace_map_info_t* map_info_;
+
+ backtrace_t backtrace_;
+
+ friend class BacktraceImpl;
+};
+
+#endif // _BACKTRACE_BACKTRACE_H
diff --git a/include/backtrace/backtrace.h b/include/backtrace/backtrace.h
new file mode 100644
index 0000000..b35a6d5
--- /dev/null
+++ b/include/backtrace/backtrace.h
@@ -0,0 +1,114 @@
+/*
+ * 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>
+
+__BEGIN_DECLS
+
+#define MAX_BACKTRACE_FRAMES 64
+
+typedef struct backtrace_map_info {
+ struct backtrace_map_info* next;
+ uintptr_t start;
+ uintptr_t end;
+ bool is_readable;
+ bool is_writable;
+ bool is_executable;
+ char name[];
+} backtrace_map_info_t;
+
+typedef struct {
+ uintptr_t pc; /* The absolute pc. */
+ uintptr_t sp; /* The top of the stack. */
+ size_t stack_size; /* The size of the stack, zero indicate an unknown stack size. */
+ const char* map_name; /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */
+ uintptr_t map_offset; /* pc relative to the start of the map, only valid if map_name is not NULL. */
+ char* func_name; /* The function name associated with this pc, NULL if not found. */
+ uintptr_t func_offset; /* pc relative to the start of the function, only valid if func_name is not NULL. */
+} backtrace_frame_data_t;
+
+typedef struct {
+ backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
+ size_t num_frames;
+
+ pid_t pid;
+ pid_t tid;
+ backtrace_map_info_t* map_info_list;
+} backtrace_t;
+
+typedef struct {
+ void* data;
+ const backtrace_t* backtrace;
+} backtrace_context_t;
+
+/* Create a context for the backtrace data and gather the backtrace.
+ * If pid < 0, then gather the backtrace for the current process.
+ */
+bool backtrace_create_context(
+ backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);
+
+/* Gather the backtrace data for a pthread instead of a process. */
+bool backtrace_create_thread_context(
+ backtrace_context_t* context, pid_t tid, size_t num_ignore_frames);
+
+/* Free any memory allocated during the context create. */
+void backtrace_destroy_context(backtrace_context_t* context);
+
+/* Read data at a specific address for a process. */
+bool backtrace_read_word(
+ const backtrace_context_t* context, uintptr_t ptr, uint32_t* value);
+
+/* Get information about the map name associated with a pc. If NULL is
+ * returned, then map_start is not set.
+ */
+const char* backtrace_get_map_name(
+ const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);
+
+/* Get the function name and offset given the pc. If NULL is returned,
+ * then func_offset is not set. The returned string is allocated using
+ * malloc and must be freed by the caller.
+ */
+char* backtrace_get_func_name(
+ const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);
+
+/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory
+ * map for the current process.
+ */
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid);
+
+/* Frees memory associated with the map list. */
+void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
+
+/* Finds the memory map that contains the specified pc. */
+const backtrace_map_info_t* backtrace_find_map_info(
+ const backtrace_map_info_t* map_info_list, uintptr_t pc);
+
+/* Create a formatted line of backtrace information for a single frame. */
+void backtrace_format_frame_data(
+ const backtrace_context_t* context, size_t frame_num, char* buf,
+ size_t buf_size);
+
+/* Get the backtrace data structure associated with the context. */
+const backtrace_t* backtrace_get_data(backtrace_context_t* context);
+
+__END_DECLS
+
+#endif /* _BACKTRACE_H */
diff --git a/include/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 @@ struct listnode
#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/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h
new file mode 100644
index 0000000..b0d91cd
--- /dev/null
+++ b/include/mincrypt/dsa_sig.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
+
+#include "mincrypt/p256.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns 0 if input sig is not a valid ASN.1 sequence
+int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
index 96806f7..c813b44 100644
--- a/include/mincrypt/hash-internal.h
+++ b/include/mincrypt/hash-internal.h
@@ -1,8 +1,31 @@
-// Copyright 2007 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
-
-#ifndef SECURITY_UTIL_LITE_HASH_INTERNAL_H__
-#define SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+/*
+ * Copyright 2007 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
#include <stdint.h>
@@ -37,4 +60,4 @@ typedef struct HASH_CTX {
}
#endif // __cplusplus
-#endif // SECURITY_UTIL_LITE_HASH_INTERNAL_H__
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h
new file mode 100644
index 0000000..465a1b9
--- /dev/null
+++ b/include/mincrypt/p256.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
+
+// Collection of routines manipulating 256 bit unsigned integers.
+// Just enough to implement ecdsa-p256 and related algorithms.
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define P256_BITSPERDIGIT 32
+#define P256_NDIGITS 8
+#define P256_NBYTES 32
+
+typedef int p256_err;
+typedef uint32_t p256_digit;
+typedef int32_t p256_sdigit;
+typedef uint64_t p256_ddigit;
+typedef int64_t p256_sddigit;
+
+// Defining p256_int as struct to leverage struct assigment.
+typedef struct {
+ p256_digit a[P256_NDIGITS];
+} p256_int;
+
+extern const p256_int SECP256r1_n; // Curve order
+extern const p256_int SECP256r1_p; // Curve prime
+extern const p256_int SECP256r1_b; // Curve param
+
+// Initialize a p256_int to zero.
+void p256_init(p256_int* a);
+
+// Clear a p256_int to zero.
+void p256_clear(p256_int* a);
+
+// Return bit. Index 0 is least significant.
+int p256_get_bit(const p256_int* a, int index);
+
+// b := a % MOD
+void p256_mod(
+ const p256_int* MOD,
+ const p256_int* a,
+ p256_int* b);
+
+// c := a * (top_b | b) % MOD
+void p256_modmul(
+ const p256_int* MOD,
+ const p256_int* a,
+ const p256_digit top_b,
+ const p256_int* b,
+ p256_int* c);
+
+// b := 1 / a % MOD
+// MOD best be SECP256r1_n
+void p256_modinv(
+ const p256_int* MOD,
+ const p256_int* a,
+ p256_int* b);
+
+// b := 1 / a % MOD
+// MOD best be SECP256r1_n
+// Faster than p256_modinv()
+void p256_modinv_vartime(
+ const p256_int* MOD,
+ const p256_int* a,
+ p256_int* b);
+
+// b := a << (n % P256_BITSPERDIGIT)
+// Returns the bits shifted out of most significant digit.
+p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
+
+// b := a >> (n % P256_BITSPERDIGIT)
+void p256_shr(const p256_int* a, int n, p256_int* b);
+
+int p256_is_zero(const p256_int* a);
+int p256_is_odd(const p256_int* a);
+int p256_is_even(const p256_int* a);
+
+// Returns -1, 0 or 1.
+int p256_cmp(const p256_int* a, const p256_int *b);
+
+// c: = a - b
+// Returns -1 on borrow.
+int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
+
+// c := a + b
+// Returns 1 on carry.
+int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
+
+// c := a + (single digit)b
+// Returns carry 1 on carry.
+int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
+
+// ec routines.
+
+// {out_x,out_y} := nG
+void p256_base_point_mul(const p256_int *n,
+ p256_int *out_x,
+ p256_int *out_y);
+
+// {out_x,out_y} := n{in_x,in_y}
+void p256_point_mul(const p256_int *n,
+ const p256_int *in_x,
+ const p256_int *in_y,
+ p256_int *out_x,
+ p256_int *out_y);
+
+// {out_x,out_y} := n1G + n2{in_x,in_y}
+void p256_points_mul_vartime(
+ const p256_int *n1, const p256_int *n2,
+ const p256_int *in_x, const p256_int *in_y,
+ p256_int *out_x, p256_int *out_y);
+
+// Return whether point {x,y} is on curve.
+int p256_is_valid_point(const p256_int* x, const p256_int* y);
+
+// Outputs big-endian binary form. No leading zero skips.
+void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
+
+// Reads from big-endian binary form,
+// thus pre-pad with leading zeros if short.
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
+
+#define P256_DIGITS(x) ((x)->a)
+#define P256_DIGIT(x,y) ((x)->a[y])
+
+#define P256_ZERO {{0}}
+#define P256_ONE {{1}}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h
new file mode 100644
index 0000000..da339fa
--- /dev/null
+++ b/include/mincrypt/p256_ecdsa.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
+
+// Using current directory as relative include path here since
+// this code typically gets lifted into a variety of build systems
+// and directory structures.
+#include "p256.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns 0 if {r,s} is not a signature on message for
+// public key {key_x,key_y}.
+//
+// Note: message is a p256_int.
+// Convert from a binary string using p256_from_bin().
+int p256_ecdsa_verify(const p256_int* key_x,
+ const p256_int* key_y,
+ const p256_int* message,
+ const p256_int* r, const p256_int* s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
index cc0e800..3d0556b 100644
--- a/include/mincrypt/rsa.h
+++ b/include/mincrypt/rsa.h
@@ -25,8 +25,8 @@
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef _EMBEDDED_RSA_H_
-#define _EMBEDDED_RSA_H_
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
#include <inttypes.h>
@@ -55,4 +55,4 @@ int RSA_verify(const RSAPublicKey *key,
}
#endif
-#endif
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
index 120ddcb..ef60aab 100644
--- a/include/mincrypt/sha.h
+++ b/include/mincrypt/sha.h
@@ -1,8 +1,30 @@
-// Copyright 2005 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
-
-#ifndef SECURITY_UTIL_LITE_SHA1_H__
-#define SECURITY_UTIL_LITE_SHA1_H__
+/*
+ * Copyright 2005 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
#include <stdint.h>
#include "hash-internal.h"
@@ -27,4 +49,4 @@ const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
}
#endif // __cplusplus
-#endif // SECURITY_UTIL_LITE_SHA1_H__
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
index 0f3efb7..3a87c31 100644
--- a/include/mincrypt/sha256.h
+++ b/include/mincrypt/sha256.h
@@ -1,8 +1,31 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
-// Author: mschilder@google.com (Marius Schilder)
-
-#ifndef SECURITY_UTIL_LITE_SHA256_H__
-#define SECURITY_UTIL_LITE_SHA256_H__
+/*
+ * Copyright 2011 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
+#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
#include <stdint.h>
#include "hash-internal.h"
@@ -26,4 +49,4 @@ const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
}
#endif // __cplusplus
-#endif // SECURITY_UTIL_LITE_SHA256_H__
+#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/init/Android.mk b/init/Android.mk
index abfc68a..1f43ba6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -10,7 +10,6 @@ LOCAL_SRC_FILES:= \
property_service.c \
util.c \
parser.c \
- logo.c \
keychords.c \
signal_handler.c \
init_parser.c \
diff --git a/init/builtins.c b/init/builtins.c
index e8c8f91..e2932d5 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -797,12 +797,24 @@ int do_chmod(int nargs, char **args) {
int do_restorecon(int nargs, char **args) {
int i;
+ int ret = 0;
for (i = 1; i < nargs; i++) {
if (restorecon(args[i]) < 0)
- return -errno;
+ ret = -errno;
}
- return 0;
+ return ret;
+}
+
+int do_restorecon_recursive(int nargs, char **args) {
+ int i;
+ int ret = 0;
+
+ for (i = 1; i < nargs; i++) {
+ if (restorecon_recursive(args[i]) < 0)
+ ret = -errno;
+ }
+ return ret;
}
int do_setsebool(int nargs, char **args) {
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 @@ void handle_device_fd()
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 @@ void device_init(void)
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..864fc6c 100644
--- a/init/init.c
+++ b/init/init.c
@@ -250,14 +250,12 @@ void service_start(struct service *svc, const char *dynamic_args)
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 @@ void service_start(struct service *svc, const char *dynamic_args)
freecon(scon);
scon = NULL;
- setsockcreatecon(NULL);
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
@@ -657,29 +654,28 @@ static int console_init_action(int nargs, char **args)
have_console = 1;
close(fd);
- if( load_565rle_image(INIT_IMAGE_FILE) ) {
- fd = open("/dev/tty0", O_WRONLY);
- if (fd >= 0) {
- const char *msg;
- msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);
- }
+ fd = open("/dev/tty0", O_WRONLY);
+ if (fd >= 0) {
+ const char *msg;
+ msg = "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n" // console is 40 cols x 30 lines
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ " A N D R O I D ";
+ write(fd, msg, strlen(msg));
+ close(fd);
}
+
return 0;
}
diff --git a/init/init.h b/init/init.h
index aa6a4ab..736b75b 100644
--- a/init/init.h
+++ b/init/init.h
@@ -55,6 +55,7 @@ struct socketinfo {
uid_t uid;
gid_t gid;
int perm;
+ const char *socketcon;
};
struct svcenvinfo {
@@ -132,10 +133,6 @@ void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
-#define INIT_IMAGE_FILE "/initlogo.rle"
-
-int load_565rle_image( char *file_name );
-
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
extern int selinux_reload_policy(void);
diff --git a/init/init_parser.c b/init/init_parser.c
index 776c699..3f0838f 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -135,6 +135,7 @@ int lookup_keyword(const char *s)
case 'r':
if (!strcmp(s, "estart")) return K_restart;
if (!strcmp(s, "estorecon")) return K_restorecon;
+ if (!strcmp(s, "estorecon_recursive")) return K_restorecon_recursive;
if (!strcmp(s, "mdir")) return K_rmdir;
if (!strcmp(s, "m")) return K_rm;
break;
@@ -552,12 +553,14 @@ void queue_all_property_triggers()
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 +774,7 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
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 +797,8 @@ static void parse_line_service(struct parse_state *state, int nargs, char **args
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/keywords.h b/init/keywords.h
index 5a44df3..97fe50c 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -17,6 +17,7 @@ int do_mount(int nargs, char **args);
int do_powerctl(int nargs, char **args);
int do_restart(int nargs, char **args);
int do_restorecon(int nargs, char **args);
+int do_restorecon_recursive(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(int nargs, char **args);
int do_setcon(int nargs, char **args);
@@ -71,6 +72,7 @@ enum {
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(restorecon, COMMAND, 1, do_restorecon)
+ KEYWORD(restorecon_recursive, COMMAND, 1, do_restorecon_recursive)
KEYWORD(rm, COMMAND, 1, do_rm)
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
KEYWORD(seclabel, OPTION, 0, 0)
diff --git a/init/logo.c b/init/logo.c
deleted file mode 100644
index 614224c..0000000
--- a/init/logo.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <linux/fb.h>
-#include <linux/kd.h>
-
-#include "log.h"
-
-#ifdef ANDROID
-#include <cutils/memory.h>
-#else
-void android_memset16(void *_ptr, unsigned short val, unsigned count)
-{
- unsigned short *ptr = _ptr;
- count >>= 1;
- while(count--)
- *ptr++ = val;
-}
-#endif
-
-struct FB {
- unsigned short *bits;
- unsigned size;
- int fd;
- struct fb_fix_screeninfo fi;
- struct fb_var_screeninfo vi;
-};
-
-#define fb_width(fb) ((fb)->vi.xres)
-#define fb_height(fb) ((fb)->vi.yres)
-#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
-
-static int fb_open(struct FB *fb)
-{
- fb->fd = open("/dev/graphics/fb0", O_RDWR);
- if (fb->fd < 0)
- return -1;
-
- if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
- goto fail;
- if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
- goto fail;
-
- fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE,
- MAP_SHARED, fb->fd, 0);
- if (fb->bits == MAP_FAILED)
- goto fail;
-
- return 0;
-
-fail:
- close(fb->fd);
- return -1;
-}
-
-static void fb_close(struct FB *fb)
-{
- munmap(fb->bits, fb_size(fb));
- close(fb->fd);
-}
-
-/* there's got to be a more portable way to do this ... */
-static void fb_update(struct FB *fb)
-{
- fb->vi.yoffset = 1;
- ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
- fb->vi.yoffset = 0;
- ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
-}
-
-static int vt_set_mode(int graphics)
-{
- int fd, r;
- fd = open("/dev/tty0", O_RDWR | O_SYNC);
- if (fd < 0)
- return -1;
- r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
- close(fd);
- return r;
-}
-
-/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
-
-int load_565rle_image(char *fn)
-{
- struct FB fb;
- struct stat s;
- unsigned short *data, *bits, *ptr;
- unsigned count, max;
- int fd;
-
- if (vt_set_mode(1))
- return -1;
-
- fd = open(fn, O_RDONLY);
- if (fd < 0) {
- ERROR("cannot open '%s'\n", fn);
- goto fail_restore_text;
- }
-
- if (fstat(fd, &s) < 0) {
- goto fail_close_file;
- }
-
- data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED)
- goto fail_close_file;
-
- if (fb_open(&fb))
- goto fail_unmap_data;
-
- max = fb_width(&fb) * fb_height(&fb);
- ptr = data;
- count = s.st_size;
- bits = fb.bits;
- while (count > 3) {
- unsigned n = ptr[0];
- if (n > max)
- break;
- android_memset16(bits, ptr[1], n << 1);
- bits += n;
- max -= n;
- ptr += 2;
- count -= 4;
- }
-
- munmap(data, s.st_size);
- fb_update(&fb);
- fb_close(&fb);
- close(fd);
- unlink(fn);
- return 0;
-
-fail_unmap_data:
- munmap(data, s.st_size);
-fail_close_file:
- close(fd);
-fail_restore_text:
- vt_set_mode(0);
- return -1;
-}
-
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 @@ struct {
{ "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 @@ struct {
{ "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 @@ void get_property_workspace(int *fd, int *sz)
*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 @@ static void load_properties(char *data)
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(char *data)
}
}
-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 @@ static void load_properties_from_file(const char *fn)
data = read_file(fn, &sz);
if(data != 0) {
- load_properties(data);
+ load_properties(data, prefix);
free(data);
}
}
@@ -545,7 +553,7 @@ void property_init(void)
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 @@ static void load_override_properties() {
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 @@ void start_property_service(void)
{
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..42a09cb 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -70,10 +70,13 @@ disabled
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.
@@ -189,12 +192,18 @@ mount <type> <device> <dir> [ <mountoption> ]*
device by name.
<mountoption>s include "ro", "rw", "remount", "noatime", ...
-restorecon <path>
+restorecon <path> [ <path> ]*
Restore the file named by <path> to the security context specified
in the file_contexts configuration.
Not required for directories created by the init.rc as these are
automatically labeled correctly by init.
+restorecon_recursive <path> [ <path> ]*
+ Recursively restore the directory tree named by <path> to the
+ security contexts specified in the file_contexts configuration.
+ Do NOT use this with paths leading to shell-writable or app-writable
+ directories, e.g. /data/local/tmp, /data/data or any prefix thereof.
+
setcon <securitycontext>
Set the current process security context to the specified string.
This is typically only used from early-init to set the init context
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 @@ unsigned int decode_uid(const char *s)
* 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 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
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 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
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 @@ int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
}
setfscreatecon(NULL);
- freecon(secon);
+ freecon(filecon);
chown(addr.sun_path, uid, gid);
chmod(addr.sun_path, perm);
@@ -398,7 +405,9 @@ void open_devnull_stdio(void)
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 @@ void get_hardware_name(char *hardware, unsigned int *revision)
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;
+
+ 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;
- data[n] = 0;
+ 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 @@ void get_hardware_name(char *hardware, unsigned int *revision)
*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 @@ static const char *coldboot_done = "/dev/.coldboot_done";
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..66d7e62
--- /dev/null
+++ b/libbacktrace/Android.mk
@@ -0,0 +1,265 @@
+LOCAL_PATH:= $(call my-dir)
+
+common_src := \
+ Backtrace.cpp \
+ BacktraceThread.cpp \
+ map_info.c \
+ thread_utils.c \
+
+common_cflags := \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+
+common_conlyflags := \
+ -std=gnu99 \
+
+common_cppflags := \
+ -std=gnu++11 \
+
+common_shared_libs := \
+ libcutils \
+ libgccdemangle \
+ liblog \
+
+# To enable using libunwind on each arch, add it to the list below.
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),))
+
+#----------------------------------------------------------------------------
+# The native libbacktrace library with libunwind.
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ $(common_src) \
+ UnwindCurrent.cpp \
+ UnwindPtrace.cpp \
+
+LOCAL_CFLAGS := \
+ $(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+ $(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+ $(common_c_includes) \
+ external/libunwind/include \
+
+LOCAL_SHARED_LIBRARIES := \
+ $(common_shared_libs) \
+ libunwind \
+ libunwind-ptrace \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+else
+
+#----------------------------------------------------------------------------
+# The native libbacktrace library with libcorkscrew.
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ $(common_src) \
+ Corkscrew.cpp \
+
+LOCAL_CFLAGS := \
+ $(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+ $(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+ $(common_c_includes) \
+ system/core/libcorkscrew \
+
+LOCAL_SHARED_LIBRARIES := \
+ $(common_shared_libs) \
+ libcorkscrew \
+ libdl \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+endif
+
+#----------------------------------------------------------------------------
+# 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 \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+include $(BUILD_SHARED_LIBRARY)
+
+#----------------------------------------------------------------------------
+# libbacktrace test executable
+#----------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := backtrace_test
+LOCAL_MODULE_FLAGS := debug
+
+LOCAL_SRC_FILES := \
+ backtrace_test.cpp \
+ thread_utils.c \
+
+LOCAL_CFLAGS += \
+ -fno-builtin \
+ -fstack-protector-all \
+ -O0 \
+ -g \
+ -DGTEST_OS_LINUX_ANDROID \
+ -DGTEST_HAS_STD_STRING \
+
+LOCAL_CONLYFLAGS += \
+ $(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+ -fpermissive \
+
+LOCAL_SHARED_LIBRARIES += \
+ libcutils \
+ libbacktrace_test \
+ libbacktrace \
+
+LOCAL_LDLIBS := \
+ -lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+include $(BUILD_NATIVE_TEST)
+
+#----------------------------------------------------------------------------
+# 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 += \
+ $(common_src) \
+ Corkscrew.cpp \
+
+LOCAL_CFLAGS += \
+ $(common_cflags) \
+
+LOCAL_CONLYFLAGS += \
+ $(common_conlyflags) \
+
+LOCAL_CPPFLAGS += \
+ $(common_cppflags) \
+
+LOCAL_C_INCLUDES := \
+ $(common_c_includes) \
+ system/core/libcorkscrew \
+
+LOCAL_SHARED_LIBRARIES := \
+ libgccdemangle \
+ liblog \
+ libcorkscrew \
+
+LOCAL_LDLIBS += \
+ -ldl \
+ -lrt \
+
+LOCAL_MODULE := libbacktrace
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+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 \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+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.cpp \
+ thread_utils.c \
+
+LOCAL_CFLAGS += \
+ -fno-builtin \
+ -fstack-protector-all \
+ -O0 \
+ -g \
+ -DGTEST_HAS_STD_STRING \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace_test \
+ libbacktrace \
+
+LOCAL_CPPFLAGS += \
+ -fpermissive \
+
+LOCAL_LDLIBS := \
+ -lpthread \
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(LOCAL_PATH)/Android.mk
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+endif # HOST_OS-HOST_ARCH == linux-x86
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
new file mode 100644
index 0000000..17d9e1d
--- /dev/null
+++ b/libbacktrace/Backtrace.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/Backtrace.h>
+#include <cutils/log.h>
+
+#include "Backtrace.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// BacktraceImpl functions.
+//-------------------------------------------------------------------------
+backtrace_t* BacktraceImpl::GetBacktraceData() {
+ return &backtrace_obj_->backtrace_;
+}
+
+//-------------------------------------------------------------------------
+// Backtrace functions.
+//-------------------------------------------------------------------------
+Backtrace::Backtrace(BacktraceImpl* impl) : impl_(impl), map_info_(NULL) {
+ impl_->SetParent(this);
+ backtrace_.num_frames = 0;
+ backtrace_.pid = -1;
+ backtrace_.tid = -1;
+}
+
+Backtrace::~Backtrace() {
+ for (size_t i = 0; i < NumFrames(); i++) {
+ if (backtrace_.frames[i].func_name) {
+ free(backtrace_.frames[i].func_name);
+ backtrace_.frames[i].func_name = NULL;
+ }
+ }
+
+ if (map_info_) {
+ backtrace_destroy_map_info_list(map_info_);
+ map_info_ = NULL;
+ }
+
+ if (impl_) {
+ delete impl_;
+ impl_ = NULL;
+ }
+}
+
+bool Backtrace::Unwind(size_t num_ignore_frames) {
+ return impl_->Unwind(num_ignore_frames);
+}
+
+extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
+ int* status);
+
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+ std::string func_name = impl_->GetFunctionNameRaw(pc, offset);
+ if (!func_name.empty()) {
+#if defined(__APPLE__)
+ // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+ if (symbol_name[0] != '_') {
+ return func_name;
+ }
+#endif
+ char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
+ if (name) {
+ func_name = name;
+ free(name);
+ }
+ }
+ return func_name;
+}
+
+bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
+ if (ptr & 3) {
+ BACK_LOGW("invalid pointer %p", (void*)ptr);
+ *out_value = (uint32_t)-1;
+ return false;
+ }
+ return true;
+}
+
+const char* Backtrace::GetMapName(uintptr_t pc, uintptr_t* map_start) {
+ const backtrace_map_info_t* map_info = FindMapInfo(pc);
+ if (map_info) {
+ if (map_start) {
+ *map_start = map_info->start;
+ }
+ return map_info->name;
+ }
+ return NULL;
+}
+
+const backtrace_map_info_t* Backtrace::FindMapInfo(uintptr_t ptr) {
+ return backtrace_find_map_info(map_info_, ptr);
+}
+
+std::string Backtrace::FormatFrameData(size_t frame_num) {
+ backtrace_frame_data_t* frame = &backtrace_.frames[frame_num];
+ const char* map_name;
+ if (frame->map_name) {
+ map_name = frame->map_name;
+ } else {
+ map_name = "<unknown>";
+ }
+ uintptr_t relative_pc;
+ if (frame->map_offset) {
+ relative_pc = frame->map_offset;
+ } else {
+ relative_pc = frame->pc;
+ }
+
+ char buf[512];
+ if (frame->func_name && frame->func_offset) {
+ snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s+%" PRIuPTR ")",
+ frame_num, (int)sizeof(uintptr_t)*2, relative_pc, map_name,
+ frame->func_name, frame->func_offset);
+ } else if (frame->func_name) {
+ snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s (%s)", frame_num,
+ (int)sizeof(uintptr_t)*2, relative_pc, map_name, frame->func_name);
+ } else {
+ snprintf(buf, sizeof(buf), "#%02zu pc %0*" PRIxPTR " %s", frame_num,
+ (int)sizeof(uintptr_t)*2, relative_pc, map_name);
+ }
+
+ return buf;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceCurrent functions.
+//-------------------------------------------------------------------------
+BacktraceCurrent::BacktraceCurrent(BacktraceImpl* impl) : Backtrace(impl) {
+ map_info_ = backtrace_create_map_info_list(-1);
+
+ backtrace_.pid = getpid();
+}
+
+BacktraceCurrent::~BacktraceCurrent() {
+}
+
+bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+ if (!VerifyReadWordArgs(ptr, out_value)) {
+ return false;
+ }
+
+ const backtrace_map_info_t* map_info = FindMapInfo(ptr);
+ if (map_info && map_info->is_readable) {
+ *out_value = *reinterpret_cast<uint32_t*>(ptr);
+ return true;
+ } else {
+ BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
+ *out_value = static_cast<uint32_t>(-1);
+ return false;
+ }
+}
+
+//-------------------------------------------------------------------------
+// BacktracePtrace functions.
+//-------------------------------------------------------------------------
+BacktracePtrace::BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid)
+ : Backtrace(impl) {
+ map_info_ = backtrace_create_map_info_list(tid);
+
+ backtrace_.pid = pid;
+ backtrace_.tid = tid;
+}
+
+BacktracePtrace::~BacktracePtrace() {
+}
+
+bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
+ if (!VerifyReadWordArgs(ptr, out_value)) {
+ return false;
+ }
+
+#if defined(__APPLE__)
+ BACK_LOGW("MacOS does not support reading from another pid.");
+ 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, Tid(), reinterpret_cast<void*>(ptr), NULL);
+ if (*out_value == static_cast<uint32_t>(-1) && errno) {
+ BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
+ reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
+ return false;
+ }
+ return true;
+#endif
+}
+
+Backtrace* Backtrace::Create(pid_t pid, pid_t tid) {
+ if (pid < 0 || pid == getpid()) {
+ if (tid < 0 || tid == gettid()) {
+ return CreateCurrentObj();
+ } else {
+ return CreateThreadObj(tid);
+ }
+ } else if (tid < 0) {
+ return CreatePtraceObj(pid, pid);
+ } else {
+ return CreatePtraceObj(pid, tid);
+ }
+}
+
+//-------------------------------------------------------------------------
+// Common interface functions.
+//-------------------------------------------------------------------------
+bool backtrace_create_context(
+ backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+ Backtrace* backtrace = Backtrace::Create(pid, tid);
+ if (!backtrace) {
+ return false;
+ }
+ if (!backtrace->Unwind(num_ignore_frames)) {
+ delete backtrace;
+ return false;
+ }
+
+ context->data = backtrace;
+ context->backtrace = backtrace->GetBacktrace();
+ return true;
+}
+
+void backtrace_destroy_context(backtrace_context_t* context) {
+ if (context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ delete backtrace;
+ context->data = NULL;
+ }
+ context->backtrace = NULL;
+}
+
+const backtrace_t* backtrace_get_data(backtrace_context_t* context) {
+ if (context && context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ return backtrace->GetBacktrace();
+ }
+ return NULL;
+}
+
+bool backtrace_read_word(const backtrace_context_t* context, uintptr_t ptr, uint32_t* value) {
+ if (context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ return backtrace->ReadWord(ptr, value);
+ }
+ return true;
+}
+
+const char* backtrace_get_map_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start) {
+ if (context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ return backtrace->GetMapName(pc, map_start);
+ }
+ return NULL;
+}
+
+char* backtrace_get_func_name(const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset) {
+ if (context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ std::string func_name = backtrace->GetFunctionName(pc, func_offset);
+ if (!func_name.empty()) {
+ return strdup(func_name.c_str());
+ }
+ }
+ return NULL;
+}
+
+void backtrace_format_frame_data(
+ const backtrace_context_t* context, size_t frame_num, char* buf,
+ size_t buf_size) {
+ if (buf_size == 0 || buf == NULL) {
+ BACK_LOGW("bad call buf %p buf_size %zu", buf, buf_size);
+ } else if (context->data) {
+ Backtrace* backtrace = reinterpret_cast<Backtrace*>(context->data);
+ std::string line = backtrace->FormatFrameData(frame_num);
+ if (line.size() > buf_size) {
+ memcpy(buf, line.c_str(), buf_size-1);
+ buf[buf_size] = '\0';
+ } else {
+ memcpy(buf, line.c_str(), line.size()+1);
+ }
+ }
+}
diff --git a/libbacktrace/Backtrace.h b/libbacktrace/Backtrace.h
new file mode 100644
index 0000000..00f0a10
--- /dev/null
+++ b/libbacktrace/Backtrace.h
@@ -0,0 +1,66 @@
+/*
+ * 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 _LIBBACKTRACE_BACKTRACE_H
+#define _LIBBACKTRACE_BACKTRACE_H
+
+#include <backtrace/Backtrace.h>
+
+#include <sys/types.h>
+
+// Macro to log the function name along with the warning message.
+#define BACK_LOGW(format, ...) \
+ ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+
+class BacktraceImpl {
+public:
+ virtual ~BacktraceImpl() { }
+
+ virtual bool Unwind(size_t num_ignore_frames) = 0;
+
+ // The name returned is not demangled, Backtrace::GetFunctionName()
+ // takes care of demangling the name.
+ virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
+
+ void SetParent(Backtrace* backtrace) { backtrace_obj_ = backtrace; }
+
+protected:
+ backtrace_t* GetBacktraceData();
+
+ Backtrace* backtrace_obj_;
+};
+
+class BacktraceCurrent : public Backtrace {
+public:
+ BacktraceCurrent(BacktraceImpl* impl);
+ virtual ~BacktraceCurrent();
+
+ bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+class BacktracePtrace : public Backtrace {
+public:
+ BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid);
+ virtual ~BacktracePtrace();
+
+ bool ReadWord(uintptr_t ptr, uint32_t* out_value);
+};
+
+Backtrace* CreateCurrentObj();
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid);
+Backtrace* CreateThreadObj(pid_t tid);
+
+#endif // _LIBBACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
new file mode 100644
index 0000000..8e664c4
--- /dev/null
+++ b/libbacktrace/BacktraceThread.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <cutils/atomic.h>
+#include <cutils/log.h>
+
+#include "BacktraceThread.h"
+#include "thread_utils.h"
+
+//-------------------------------------------------------------------------
+// ThreadEntry implementation.
+//-------------------------------------------------------------------------
+static ThreadEntry* g_list = NULL;
+static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+ThreadEntry::ThreadEntry(
+ BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
+ : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
+ state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
+}
+
+ThreadEntry::~ThreadEntry() {
+ pthread_mutex_lock(&g_entry_mutex);
+ if (g_list == this) {
+ g_list = next;
+ } else {
+ if (next) {
+ next->prev = prev;
+ }
+ prev->next = next;
+ }
+ pthread_mutex_unlock(&g_entry_mutex);
+
+ next = NULL;
+ prev = NULL;
+}
+
+ThreadEntry* ThreadEntry::AddThreadToUnwind(
+ BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
+ ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
+
+ pthread_mutex_lock(&g_entry_mutex);
+ ThreadEntry* cur_entry = g_list;
+ while (cur_entry != NULL) {
+ if (cur_entry->Match(pid, tid)) {
+ // There is already an entry for this pid/tid, this is bad.
+ BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
+
+ pthread_mutex_unlock(&g_entry_mutex);
+ return NULL;
+ }
+ cur_entry = cur_entry->next;
+ }
+
+ // Add the entry to the list.
+ entry->next = g_list;
+ if (g_list) {
+ g_list->prev = entry;
+ }
+ g_list = entry;
+ pthread_mutex_unlock(&g_entry_mutex);
+
+ return entry;
+}
+
+//-------------------------------------------------------------------------
+// BacktraceThread functions.
+//-------------------------------------------------------------------------
+static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
+ void* sigcontext) {
+ if (pthread_mutex_lock(&g_entry_mutex) == 0) {
+ pid_t pid = getpid();
+ pid_t tid = gettid();
+ ThreadEntry* cur_entry = g_list;
+ while (cur_entry) {
+ if (cur_entry->Match(pid, tid)) {
+ break;
+ }
+ cur_entry = cur_entry->next;
+ }
+ pthread_mutex_unlock(&g_entry_mutex);
+ if (!cur_entry) {
+ BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
+ return;
+ }
+
+ if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
+ cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
+ cur_entry->num_ignore_frames);
+ }
+ android_atomic_release_store(STATE_DONE, &cur_entry->state);
+ }
+}
+
+BacktraceThread::BacktraceThread(
+ BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid)
+ : BacktraceCurrent(impl), thread_intf_(thread_intf) {
+ backtrace_.tid = tid;
+}
+
+BacktraceThread::~BacktraceThread() {
+}
+
+void BacktraceThread::FinishUnwind() {
+ for (size_t i = 0; i < NumFrames(); i++) {
+ backtrace_frame_data_t* frame = &backtrace_.frames[i];
+
+ frame->map_offset = 0;
+ uintptr_t map_start;
+ frame->map_name = GetMapName(frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ frame->func_offset = 0;
+ std::string func_name = GetFunctionName(frame->pc, &frame->func_offset);
+ if (!func_name.empty()) {
+ frame->func_name = strdup(func_name.c_str());
+ }
+ }
+}
+
+bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
+ entry->state = STATE_WAITING;
+
+ if (tgkill(Pid(), Tid(), SIGURG) != 0) {
+ BACK_LOGW("tgkill failed %s", strerror(errno));
+ return false;
+ }
+
+ // Allow up to ten seconds for the dump to start.
+ int wait_millis = 10000;
+ int32_t state;
+ while (true) {
+ state = android_atomic_acquire_load(&entry->state);
+ if (state != STATE_WAITING) {
+ break;
+ }
+ if (wait_millis--) {
+ usleep(1000);
+ } else {
+ break;
+ }
+ }
+
+ bool cancelled = false;
+ if (state == STATE_WAITING) {
+ if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
+ BACK_LOGW("Cancelled dump of thread %d", entry->tid);
+ state = STATE_CANCEL;
+ cancelled = true;
+ } else {
+ state = android_atomic_acquire_load(&entry->state);
+ }
+ }
+
+ // Wait for at most ten seconds for the cancel or dump to finish.
+ wait_millis = 10000;
+ while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
+ if (wait_millis--) {
+ usleep(1000);
+ } else {
+ BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
+ break;
+ }
+ }
+ return !cancelled;
+}
+
+bool BacktraceThread::Unwind(size_t num_ignore_frames) {
+ if (!thread_intf_->Init()) {
+ return false;
+ }
+
+ ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
+ thread_intf_, Pid(), Tid(), num_ignore_frames);
+ if (!entry) {
+ return false;
+ }
+
+ // Prevent multiple threads trying to set the trigger action on different
+ // threads at the same time.
+ bool retval = false;
+ if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
+ struct sigaction act, oldact;
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = SignalHandler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(SIGURG, &act, &oldact) == 0) {
+ retval = TriggerUnwindOnThread(entry);
+ sigaction(SIGURG, &oldact, NULL);
+ } else {
+ BACK_LOGW("sigaction failed %s", strerror(errno));
+ }
+ pthread_mutex_unlock(&g_sigaction_mutex);
+ } else {
+ BACK_LOGW("unable to acquire sigaction mutex.");
+ }
+
+ if (retval) {
+ FinishUnwind();
+ }
+ delete entry;
+
+ return retval;
+}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
new file mode 100644
index 0000000..8ed1122
--- /dev/null
+++ b/libbacktrace/BacktraceThread.h
@@ -0,0 +1,92 @@
+/*
+ * 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 _LIBBACKTRACE_BACKTRACE_THREAD_H
+#define _LIBBACKTRACE_BACKTRACE_THREAD_H
+
+#include <inttypes.h>
+#include <pthread.h>
+#include <sys/types.h>
+
+#include "Backtrace.h"
+
+typedef enum {
+ STATE_WAITING = 0,
+ STATE_DUMPING,
+ STATE_DONE,
+ STATE_CANCEL,
+} state_e;
+
+class BacktraceThreadInterface;
+
+struct ThreadEntry {
+ ThreadEntry(
+ BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
+ size_t num_ignore_frames);
+ ~ThreadEntry();
+
+ bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); }
+
+ static ThreadEntry* AddThreadToUnwind(
+ BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
+ size_t num_ignored_frames);
+
+ BacktraceThreadInterface* thread_intf;
+ pid_t pid;
+ pid_t tid;
+ ThreadEntry* next;
+ ThreadEntry* prev;
+ int32_t state;
+ int num_ignore_frames;
+};
+
+// Interface class that does not contain any local storage, only defines
+// virtual functions to be defined by subclasses.
+class BacktraceThreadInterface {
+public:
+ virtual ~BacktraceThreadInterface() { }
+
+ virtual bool Init() = 0;
+
+ virtual void ThreadUnwind(
+ siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+};
+
+class BacktraceThread : public BacktraceCurrent {
+public:
+ // impl and thread_intf should point to the same object, this allows
+ // the compiler to catch if an implementation does not properly
+ // subclass both.
+ BacktraceThread(
+ BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid);
+ virtual ~BacktraceThread();
+
+ virtual bool Unwind(size_t num_ignore_frames);
+
+ virtual void ThreadUnwind(
+ siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+ thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames);
+ }
+
+private:
+ virtual bool TriggerUnwindOnThread(ThreadEntry* entry);
+
+ virtual void FinishUnwind();
+
+ BacktraceThreadInterface* thread_intf_;
+};
+
+#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
new file mode 100644
index 0000000..9daa752
--- /dev/null
+++ b/libbacktrace/Corkscrew.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 <backtrace/backtrace.h>
+
+#include <string.h>
+
+#include <backtrace-arch.h>
+#include <cutils/log.h>
+#include <corkscrew/backtrace.h>
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#include <dlfcn.h>
+
+#include "Corkscrew.h"
+
+//-------------------------------------------------------------------------
+// CorkscrewCommon functions.
+//-------------------------------------------------------------------------
+bool CorkscrewCommon::GenerateFrameData(
+ backtrace_frame_t* cork_frames, ssize_t num_frames) {
+ if (num_frames < 0) {
+ BACK_LOGW("libcorkscrew unwind failed.");
+ return false;
+ }
+
+ backtrace_t* data = GetBacktraceData();
+ data->num_frames = num_frames;
+ for (size_t i = 0; i < data->num_frames; i++) {
+ backtrace_frame_data_t* frame = &data->frames[i];
+ frame->pc = cork_frames[i].absolute_pc;
+ frame->sp = cork_frames[i].stack_top;
+ frame->stack_size = cork_frames[i].stack_size;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+ frame->func_name = NULL;
+ frame->func_offset = 0;
+
+ uintptr_t map_start;
+ frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+ if (!func_name.empty()) {
+ frame->func_name = strdup(func_name.c_str());
+ }
+ }
+ return true;
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewCurrent functions.
+//-------------------------------------------------------------------------
+CorkscrewCurrent::CorkscrewCurrent() {
+}
+
+CorkscrewCurrent::~CorkscrewCurrent() {
+}
+
+bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
+ backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+ ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
+
+ return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ *offset = 0;
+
+ // Get information about the current thread.
+ Dl_info info;
+ const backtrace_map_info_t* map_info = backtrace_obj_->FindMapInfo(pc);
+ const char* symbol_name = NULL;
+ 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;
+
+ return symbol_name;
+ }
+ return "";
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewThread functions.
+//-------------------------------------------------------------------------
+CorkscrewThread::CorkscrewThread() {
+}
+
+CorkscrewThread::~CorkscrewThread() {
+ if (corkscrew_map_info_) {
+ free_map_info_list(corkscrew_map_info_);
+ corkscrew_map_info_ = NULL;
+ }
+}
+
+bool CorkscrewThread::Init() {
+ corkscrew_map_info_ = load_map_info_list(backtrace_obj_->Pid());
+ return corkscrew_map_info_ != NULL;
+}
+
+void CorkscrewThread::ThreadUnwind(
+ siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
+ backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+ ssize_t num_frames = unwind_backtrace_signal_arch(
+ siginfo, sigcontext, corkscrew_map_info_, frames, num_ignore_frames,
+ MAX_BACKTRACE_FRAMES);
+ if (num_frames > 0) {
+ backtrace_t* data = GetBacktraceData();
+ data->num_frames = num_frames;
+ for (size_t i = 0; i < data->num_frames; i++) {
+ backtrace_frame_data_t* frame = &data->frames[i];
+ frame->pc = frames[i].absolute_pc;
+ frame->sp = frames[i].stack_top;
+ frame->stack_size = frames[i].stack_size;
+
+ frame->map_offset = 0;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+
+ frame->func_offset = 0;
+ frame->func_name = NULL;
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+// CorkscrewPtrace functions.
+//-------------------------------------------------------------------------
+CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
+}
+
+CorkscrewPtrace::~CorkscrewPtrace() {
+ if (ptrace_context_) {
+ free_ptrace_context(ptrace_context_);
+ ptrace_context_ = NULL;
+ }
+}
+
+bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
+ ptrace_context_ = load_ptrace_context(backtrace_obj_->Tid());
+
+ backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
+ ssize_t num_frames = unwind_backtrace_ptrace(
+ backtrace_obj_->Tid(), ptrace_context_, frames, num_ignore_frames,
+ MAX_BACKTRACE_FRAMES);
+
+ return GenerateFrameData(frames, num_frames);
+}
+
+std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ // Get information about a different process.
+ const map_info_t* map_info;
+ const symbol_t* symbol;
+ find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
+ char* symbol_name = NULL;
+ if (symbol) {
+ if (map_info) {
+ *offset = pc - map_info->start - symbol->start;
+ }
+ symbol_name = symbol->name;
+ return symbol_name;
+ }
+
+ return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation functions.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+ return new BacktraceCurrent(new CorkscrewCurrent());
+}
+
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+ return new BacktracePtrace(new CorkscrewPtrace(), pid, tid);
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+ CorkscrewThread* thread_obj = new CorkscrewThread();
+ return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
new file mode 100644
index 0000000..7cb125c
--- /dev/null
+++ b/libbacktrace/Corkscrew.h
@@ -0,0 +1,74 @@
+/*
+ * 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 _LIBBACKTRACE_CORKSCREW_H
+#define _LIBBACKTRACE_CORKSCREW_H
+
+#include <inttypes.h>
+
+#include <string>
+
+#include <backtrace/backtrace.h>
+#include <backtrace/Backtrace.h>
+
+#include <corkscrew/backtrace.h>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+class CorkscrewCommon : public BacktraceImpl {
+public:
+ bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
+};
+
+class CorkscrewCurrent : public CorkscrewCommon {
+public:
+ CorkscrewCurrent();
+ virtual ~CorkscrewCurrent();
+
+ virtual bool Unwind(size_t num_ignore_threads);
+
+ virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+};
+
+class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
+public:
+ CorkscrewThread();
+ virtual ~CorkscrewThread();
+
+ virtual bool Init();
+
+ virtual void ThreadUnwind(
+ siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+
+private:
+ map_info_t* corkscrew_map_info_;
+};
+
+class CorkscrewPtrace : public CorkscrewCommon {
+public:
+ CorkscrewPtrace();
+ virtual ~CorkscrewPtrace();
+
+ virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+ virtual bool Unwind(size_t num_ignore_threads);
+
+private:
+ ptrace_context_t* ptrace_context_;
+};
+
+#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
new file mode 100644
index 0000000..d4ba68f
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -0,0 +1,215 @@
+/*
+ * 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/types.h>
+
+#include <cutils/log.h>
+
+#include <backtrace/backtrace.h>
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+#include "UnwindCurrent.h"
+
+// Define the ucontext_t structures needed for each supported arch.
+#if defined(__arm__)
+ // The current version of the <signal.h> doesn't define ucontext_t.
+ #include <asm/sigcontext.h> // Ensure 'struct sigcontext' is defined.
+
+ // Machine context at the time a signal was raised.
+ typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ uint32_t uc_sigmask;
+ } ucontext_t;
+#elif defined(__mips__)
+ typedef struct ucontext {
+ uint32_t sp;
+ uint32_t ra;
+ uint32_t pc;
+ } ucontext_t;
+#elif defined(__i386__)
+ #include <asm/sigcontext.h>
+ #include <asm/ucontext.h>
+ typedef struct ucontext ucontext_t;
+#else
+ #error Unsupported architecture.
+#endif
+
+//-------------------------------------------------------------------------
+// UnwindCurrent functions.
+//-------------------------------------------------------------------------
+UnwindCurrent::UnwindCurrent() {
+}
+
+UnwindCurrent::~UnwindCurrent() {
+}
+
+bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
+ int ret = unw_getcontext(&context_);
+ if (ret < 0) {
+ BACK_LOGW("unw_getcontext failed %d", ret);
+ return false;
+ }
+ return UnwindFromContext(num_ignore_frames, true);
+}
+
+std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ *offset = 0;
+ char buf[512];
+ 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 = static_cast<uintptr_t>(value);
+ return buf;
+ }
+ return "";
+}
+
+bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, bool resolve) {
+ backtrace_t* backtrace = GetBacktraceData();
+ backtrace->num_frames = 0;
+
+ // The cursor structure is pretty large, do not put it on the stack.
+ unw_cursor_t* cursor = new unw_cursor_t;
+ int ret = unw_init_local(cursor, &context_);
+ if (ret < 0) {
+ BACK_LOGW("unw_init_local failed %d", ret);
+ return false;
+ }
+
+ do {
+ unw_word_t pc;
+ ret = unw_get_reg(cursor, UNW_REG_IP, &pc);
+ if (ret < 0) {
+ BACK_LOGW("Failed to read IP %d", ret);
+ break;
+ }
+ unw_word_t sp;
+ ret = unw_get_reg(cursor, UNW_REG_SP, &sp);
+ if (ret < 0) {
+ BACK_LOGW("Failed to read SP %d", ret);
+ break;
+ }
+
+ if (num_ignore_frames == 0) {
+ size_t num_frames = backtrace->num_frames;
+ backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+ frame->pc = static_cast<uintptr_t>(pc);
+ frame->sp = static_cast<uintptr_t>(sp);
+ frame->stack_size = 0;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+ frame->func_name = NULL;
+ frame->func_offset = 0;
+
+ if (num_frames > 0) {
+ // Set the stack size for the previous frame.
+ backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+ prev->stack_size = frame->sp - prev->sp;
+ }
+
+ if (resolve) {
+ std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+ if (!func_name.empty()) {
+ frame->func_name = strdup(func_name.c_str());
+ }
+
+ uintptr_t map_start;
+ frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+ }
+
+ backtrace->num_frames++;
+ } else {
+ num_ignore_frames--;
+ }
+ ret = unw_step (cursor);
+ } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+ delete cursor;
+ return true;
+}
+
+void UnwindCurrent::ExtractContext(void* sigcontext) {
+ unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+ const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
+
+#if defined(__arm__)
+ context->regs[0] = uc->uc_mcontext.arm_r0;
+ context->regs[1] = uc->uc_mcontext.arm_r1;
+ context->regs[2] = uc->uc_mcontext.arm_r2;
+ context->regs[3] = uc->uc_mcontext.arm_r3;
+ context->regs[4] = uc->uc_mcontext.arm_r4;
+ context->regs[5] = uc->uc_mcontext.arm_r5;
+ context->regs[6] = uc->uc_mcontext.arm_r6;
+ context->regs[7] = uc->uc_mcontext.arm_r7;
+ context->regs[8] = uc->uc_mcontext.arm_r8;
+ context->regs[9] = uc->uc_mcontext.arm_r9;
+ context->regs[10] = uc->uc_mcontext.arm_r10;
+ context->regs[11] = uc->uc_mcontext.arm_fp;
+ context->regs[12] = uc->uc_mcontext.arm_ip;
+ context->regs[13] = uc->uc_mcontext.arm_sp;
+ context->regs[14] = uc->uc_mcontext.arm_lr;
+ context->regs[15] = uc->uc_mcontext.arm_pc;
+#elif defined(__mips__)
+ context->uc_mcontext.sp = uc->sp;
+ context->uc_mcontext.pc = uc->pc;
+ context->uc_mcontext.ra = uc->ra;
+#elif defined(__i386__)
+ context->uc_mcontext.gregs[REG_EBP] = uc->uc_mcontext.gregs[REG_EBP];
+ context->uc_mcontext.gregs[REG_ESP] = uc->uc_mcontext.gregs[REG_ESP];
+ context->uc_mcontext.gregs[REG_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
+}
+
+//-------------------------------------------------------------------------
+// UnwindThread functions.
+//-------------------------------------------------------------------------
+UnwindThread::UnwindThread() {
+}
+
+UnwindThread::~UnwindThread() {
+}
+
+bool UnwindThread::Init() {
+ return true;
+}
+
+void UnwindThread::ThreadUnwind(
+ siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
+ ExtractContext(sigcontext);
+ UnwindFromContext(num_ignore_frames, false);
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreateCurrentObj() {
+ return new BacktraceCurrent(new UnwindCurrent());
+}
+
+Backtrace* CreateThreadObj(pid_t tid) {
+ UnwindThread* thread_obj = new UnwindThread();
+ return new BacktraceThread(thread_obj, thread_obj, tid);
+}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
new file mode 100644
index 0000000..7dc977d
--- /dev/null
+++ b/libbacktrace/UnwindCurrent.h
@@ -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.
+ */
+
+#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
+#define _LIBBACKTRACE_UNWIND_CURRENT_H
+
+#include <string>
+
+#include "Backtrace.h"
+#include "BacktraceThread.h"
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+
+class UnwindCurrent : public BacktraceImpl {
+public:
+ UnwindCurrent();
+ virtual ~UnwindCurrent();
+
+ virtual bool Unwind(size_t num_ignore_frames);
+
+ virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+ bool UnwindFromContext(size_t num_ignore_frames, bool resolve);
+
+ void ExtractContext(void* sigcontext);
+
+protected:
+ unw_context_t context_;
+};
+
+class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
+public:
+ UnwindThread();
+ virtual ~UnwindThread();
+
+ virtual bool Init();
+
+ virtual void ThreadUnwind(
+ siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
+};
+
+#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
new file mode 100644
index 0000000..a734a24
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 <backtrace/backtrace.h>
+
+#include <sys/types.h>
+#include <string.h>
+
+#include <cutils/log.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "UnwindPtrace.h"
+
+UnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) {
+}
+
+UnwindPtrace::~UnwindPtrace() {
+ if (upt_info_) {
+ _UPT_destroy(upt_info_);
+ upt_info_ = NULL;
+ }
+ if (addr_space_) {
+ unw_destroy_addr_space(addr_space_);
+ addr_space_ = NULL;
+ }
+}
+
+bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+ addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
+ if (!addr_space_) {
+ BACK_LOGW("unw_create_addr_space failed.");
+ return false;
+ }
+
+ upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(backtrace_obj_->Tid()));
+ if (!upt_info_) {
+ BACK_LOGW("Failed to create upt info.");
+ return false;
+ }
+
+ backtrace_t* backtrace = GetBacktraceData();
+ backtrace->num_frames = 0;
+
+ unw_cursor_t cursor;
+ int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
+ if (ret < 0) {
+ BACK_LOGW("unw_init_remote failed %d", ret);
+ return false;
+ }
+
+ do {
+ unw_word_t pc;
+ ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+ if (ret < 0) {
+ BACK_LOGW("Failed to read IP %d", ret);
+ break;
+ }
+ unw_word_t sp;
+ ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
+ if (ret < 0) {
+ BACK_LOGW("Failed to read SP %d", ret);
+ break;
+ }
+
+ if (num_ignore_frames == 0) {
+ size_t num_frames = backtrace->num_frames;
+ backtrace_frame_data_t* frame = &backtrace->frames[num_frames];
+ frame->pc = static_cast<uintptr_t>(pc);
+ frame->sp = static_cast<uintptr_t>(sp);
+ frame->stack_size = 0;
+ frame->map_name = NULL;
+ frame->map_offset = 0;
+ frame->func_name = NULL;
+ frame->func_offset = 0;
+
+ if (num_frames > 0) {
+ backtrace_frame_data_t* prev = &backtrace->frames[num_frames-1];
+ prev->stack_size = frame->sp - prev->sp;
+ }
+
+ std::string func_name = backtrace_obj_->GetFunctionName(frame->pc, &frame->func_offset);
+ if (!func_name.empty()) {
+ frame->func_name = strdup(func_name.c_str());
+ }
+
+ uintptr_t map_start;
+ frame->map_name = backtrace_obj_->GetMapName(frame->pc, &map_start);
+ if (frame->map_name) {
+ frame->map_offset = frame->pc - map_start;
+ }
+
+ backtrace->num_frames++;
+ } else {
+ num_ignore_frames--;
+ }
+ ret = unw_step (&cursor);
+ } while (ret > 0 && backtrace->num_frames < MAX_BACKTRACE_FRAMES);
+
+ return true;
+}
+
+std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+ *offset = 0;
+ char buf[512];
+ unw_word_t value;
+ if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
+ upt_info_) >= 0 && buf[0] != '\0') {
+ *offset = static_cast<uintptr_t>(value);
+ return buf;
+ }
+ return "";
+}
+
+//-------------------------------------------------------------------------
+// C++ object creation function.
+//-------------------------------------------------------------------------
+Backtrace* CreatePtraceObj(pid_t pid, pid_t tid) {
+ return new BacktracePtrace(new UnwindPtrace(), pid, tid);
+}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
new file mode 100644
index 0000000..781405b
--- /dev/null
+++ b/libbacktrace/UnwindPtrace.h
@@ -0,0 +1,40 @@
+/*
+ * 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 _LIBBACKTRACE_UNWIND_PTRACE_H
+#define _LIBBACKTRACE_UNWIND_PTRACE_H
+
+#include <string>
+
+#include "Backtrace.h"
+
+#include <libunwind.h>
+
+class UnwindPtrace : public BacktraceImpl {
+public:
+ UnwindPtrace();
+ virtual ~UnwindPtrace();
+
+ virtual bool Unwind(size_t num_ignore_frames);
+
+ virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+
+private:
+ unw_addr_space_t addr_space_;
+ struct UPT_info* upt_info_;
+};
+
+#endif // _LIBBACKTRACE_UNWIND_PTRACE_H
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
new file mode 100644
index 0000000..48e2bdc
--- /dev/null
+++ b/libbacktrace/backtrace_test.cpp
@@ -0,0 +1,660 @@
+/*
+ * 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 <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <backtrace/backtrace.h>
+
+#include <cutils/atomic.h>
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include "thread_utils.h"
+
+// Number of microseconds per milliseconds.
+#define US_PER_MSEC 1000
+
+// Number of nanoseconds in a second.
+#define NS_PER_SEC 1000000000ULL
+
+// Number of simultaneous dumping operations to perform.
+#define NUM_THREADS 20
+
+// Number of simultaneous threads running in our forked process.
+#define NUM_PTRACE_THREADS 5
+
+typedef struct {
+ pid_t tid;
+ int32_t state;
+ pthread_t threadId;
+} thread_t;
+
+typedef struct {
+ thread_t thread;
+ backtrace_context_t context;
+ int32_t* now;
+ int32_t done;
+} dump_thread_t;
+
+extern "C" {
+// Prototypes for functions in the test library.
+int test_level_one(int, int, int, int, void (*)(void*), void*);
+
+int test_recursive_call(int, void (*)(void*), void*);
+}
+
+uint64_t NanoTime() {
+ struct timespec t = { 0, 0 };
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
+}
+
+void DumpFrames(const backtrace_context_t* context) {
+ if (context->backtrace->num_frames == 0) {
+ printf(" No frames to dump\n");
+ } else {
+ char line[512];
+ for (size_t i = 0; i < context->backtrace->num_frames; i++) {
+ backtrace_format_frame_data(context, i, line, sizeof(line));
+ printf(" %s\n", line);
+ }
+ }
+}
+
+void WaitForStop(pid_t pid) {
+ uint64_t start = NanoTime();
+
+ siginfo_t si;
+ while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
+ if ((NanoTime() - start) > NS_PER_SEC) {
+ printf("The process did not get to a stopping point in 1 second.\n");
+ break;
+ }
+ usleep(US_PER_MSEC);
+ }
+}
+
+bool ReadyLevelBacktrace(const backtrace_t* backtrace) {
+ // See if test_level_four is in the backtrace.
+ bool found = false;
+ for (size_t i = 0; i < backtrace->num_frames; i++) {
+ if (backtrace->frames[i].func_name != NULL &&
+ strcmp(backtrace->frames[i].func_name, "test_level_four") == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+void VerifyLevelDump(const backtrace_t* backtrace) {
+ ASSERT_GT(backtrace->num_frames, static_cast<size_t>(0));
+ ASSERT_LT(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+
+ // Look through the frames starting at the highest to find the
+ // frame we want.
+ size_t frame_num = 0;
+ for (size_t i = backtrace->num_frames-1; i > 2; i--) {
+ if (backtrace->frames[i].func_name != NULL &&
+ strcmp(backtrace->frames[i].func_name, "test_level_one") == 0) {
+ frame_num = i;
+ break;
+ }
+ }
+ ASSERT_GT(frame_num, static_cast<size_t>(0));
+
+ ASSERT_TRUE(NULL != backtrace->frames[frame_num].func_name);
+ ASSERT_STREQ(backtrace->frames[frame_num].func_name, "test_level_one");
+ ASSERT_TRUE(NULL != backtrace->frames[frame_num-1].func_name);
+ ASSERT_STREQ(backtrace->frames[frame_num-1].func_name, "test_level_two");
+ ASSERT_TRUE(NULL != backtrace->frames[frame_num-2].func_name);
+ ASSERT_STREQ(backtrace->frames[frame_num-2].func_name, "test_level_three");
+ ASSERT_TRUE(NULL != backtrace->frames[frame_num-3].func_name);
+ ASSERT_STREQ(backtrace->frames[frame_num-3].func_name, "test_level_four");
+}
+
+void VerifyLevelBacktrace(void*) {
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+ VerifyLevelDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+}
+
+bool ReadyMaxBacktrace(const backtrace_t* backtrace) {
+ return (backtrace->num_frames == MAX_BACKTRACE_FRAMES);
+}
+
+void VerifyMaxDump(const backtrace_t* backtrace) {
+ ASSERT_EQ(backtrace->num_frames, static_cast<size_t>(MAX_BACKTRACE_FRAMES));
+ // Verify that the last frame is our recursive call.
+ ASSERT_TRUE(NULL != backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name);
+ ASSERT_STREQ(backtrace->frames[MAX_BACKTRACE_FRAMES-1].func_name,
+ "test_recursive_call");
+}
+
+void VerifyMaxBacktrace(void*) {
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+
+ VerifyMaxDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+}
+
+void ThreadSetState(void* data) {
+ thread_t* thread = reinterpret_cast<thread_t*>(data);
+ android_atomic_acquire_store(1, &thread->state);
+ volatile int i = 0;
+ while (thread->state) {
+ i++;
+ }
+}
+
+void VerifyThreadTest(pid_t tid, void (*VerifyFunc)(const backtrace_t*)) {
+ backtrace_context_t context;
+
+ backtrace_create_context(&context, getpid(), tid, 0);
+
+ VerifyFunc(context.backtrace);
+
+ backtrace_destroy_context(&context);
+}
+
+bool WaitForNonZero(int32_t* value, uint64_t seconds) {
+ uint64_t start = NanoTime();
+ do {
+ if (android_atomic_acquire_load(value)) {
+ return true;
+ }
+ } while ((NanoTime() - start) < seconds * NS_PER_SEC);
+ return false;
+}
+
+TEST(libbacktrace, local_trace) {
+ ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelBacktrace, NULL), 0);
+}
+
+void VerifyIgnoreFrames(
+ const backtrace_t* bt_all, const backtrace_t* bt_ign1,
+ const backtrace_t* bt_ign2, const char* cur_proc) {
+ EXPECT_EQ(bt_all->num_frames, bt_ign1->num_frames + 1);
+ EXPECT_EQ(bt_all->num_frames, bt_ign2->num_frames + 2);
+
+ // Check all of the frames are the same > the current frame.
+ bool check = (cur_proc == NULL);
+ for (size_t i = 0; i < bt_ign2->num_frames; i++) {
+ if (check) {
+ EXPECT_EQ(bt_ign2->frames[i].pc, bt_ign1->frames[i+1].pc);
+ EXPECT_EQ(bt_ign2->frames[i].sp, bt_ign1->frames[i+1].sp);
+ EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_ign1->frames[i+1].stack_size);
+
+ EXPECT_EQ(bt_ign2->frames[i].pc, bt_all->frames[i+2].pc);
+ EXPECT_EQ(bt_ign2->frames[i].sp, bt_all->frames[i+2].sp);
+ EXPECT_EQ(bt_ign2->frames[i].stack_size, bt_all->frames[i+2].stack_size);
+ }
+ if (!check && bt_ign2->frames[i].func_name &&
+ strcmp(bt_ign2->frames[i].func_name, cur_proc) == 0) {
+ check = true;
+ }
+ }
+}
+
+void VerifyLevelIgnoreFrames(void*) {
+ backtrace_context_t all;
+ ASSERT_TRUE(backtrace_create_context(&all, -1, -1, 0));
+ ASSERT_TRUE(all.backtrace != NULL);
+
+ backtrace_context_t ign1;
+ ASSERT_TRUE(backtrace_create_context(&ign1, -1, -1, 1));
+ ASSERT_TRUE(ign1.backtrace != NULL);
+
+ backtrace_context_t ign2;
+ ASSERT_TRUE(backtrace_create_context(&ign2, -1, -1, 2));
+ ASSERT_TRUE(ign2.backtrace != NULL);
+
+ VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace,
+ "VerifyLevelIgnoreFrames");
+
+ backtrace_destroy_context(&all);
+ backtrace_destroy_context(&ign1);
+ backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, local_trace_ignore_frames) {
+ ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelIgnoreFrames, NULL), 0);
+}
+
+TEST(libbacktrace, local_max_trace) {
+ ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxBacktrace, NULL), 0);
+}
+
+void VerifyProcTest(pid_t pid, pid_t tid,
+ bool (*ReadyFunc)(const backtrace_t*),
+ void (*VerifyFunc)(const backtrace_t*)) {
+ pid_t ptrace_tid;
+ if (tid < 0) {
+ ptrace_tid = pid;
+ } else {
+ ptrace_tid = tid;
+ }
+ uint64_t start = NanoTime();
+ bool verified = false;
+ do {
+ usleep(US_PER_MSEC);
+ if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
+ // Wait for the process to get to a stopping point.
+ WaitForStop(ptrace_tid);
+
+ backtrace_context_t context;
+ ASSERT_TRUE(backtrace_create_context(&context, pid, tid, 0));
+ if (ReadyFunc(context.backtrace)) {
+ VerifyFunc(context.backtrace);
+ verified = true;
+ }
+ backtrace_destroy_context(&context);
+ ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
+ }
+ // If 5 seconds have passed, then we are done.
+ } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
+ ASSERT_TRUE(verified);
+}
+
+TEST(libbacktrace, ptrace_trace) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+ exit(1);
+ }
+ VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyLevelDump);
+
+ kill(pid, SIGKILL);
+ int status;
+ ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+TEST(libbacktrace, ptrace_max_trace) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, NULL, NULL), 0);
+ exit(1);
+ }
+ VerifyProcTest(pid, -1, ReadyMaxBacktrace, VerifyMaxDump);
+
+ kill(pid, SIGKILL);
+ int status;
+ ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyProcessIgnoreFrames(const backtrace_t* bt_all) {
+ pid_t pid = bt_all->pid;
+
+ backtrace_context_t ign1;
+ ASSERT_TRUE(backtrace_create_context(&ign1, pid, -1, 1));
+ ASSERT_TRUE(ign1.backtrace != NULL);
+
+ backtrace_context_t ign2;
+ ASSERT_TRUE(backtrace_create_context(&ign2, pid, -1, 2));
+ ASSERT_TRUE(ign2.backtrace != NULL);
+
+ VerifyIgnoreFrames(bt_all, ign1.backtrace, ign2.backtrace, NULL);
+
+ backtrace_destroy_context(&ign1);
+ backtrace_destroy_context(&ign2);
+}
+
+TEST(libbacktrace, ptrace_ignore_frames) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+ exit(1);
+ }
+ VerifyProcTest(pid, -1, ReadyLevelBacktrace, VerifyProcessIgnoreFrames);
+
+ kill(pid, SIGKILL);
+ int status;
+ ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+// Create a process with multiple threads and dump all of the threads.
+void* PtraceThreadLevelRun(void*) {
+ EXPECT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+ return NULL;
+}
+
+void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
+ // Get the list of tasks.
+ char task_path[128];
+ snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
+
+ DIR* tasks_dir = opendir(task_path);
+ ASSERT_TRUE(tasks_dir != NULL);
+ struct dirent* entry;
+ while ((entry = readdir(tasks_dir)) != NULL) {
+ char* end;
+ pid_t tid = strtoul(entry->d_name, &end, 10);
+ if (*end == '\0') {
+ threads->push_back(tid);
+ }
+ }
+ closedir(tasks_dir);
+}
+
+TEST(libbacktrace, ptrace_threads) {
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ pthread_t thread;
+ ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, NULL) == 0);
+ }
+ ASSERT_NE(test_level_one(1, 2, 3, 4, NULL, NULL), 0);
+ exit(1);
+ }
+
+ // Check to see that all of the threads are running before unwinding.
+ std::vector<pid_t> threads;
+ uint64_t start = NanoTime();
+ do {
+ usleep(US_PER_MSEC);
+ threads.clear();
+ GetThreads(pid, &threads);
+ } while ((threads.size() != NUM_PTRACE_THREADS + 1) &&
+ ((NanoTime() - start) <= 5 * NS_PER_SEC));
+ ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
+
+ ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+ WaitForStop(pid);
+ for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
+ // Skip the current forked process, we only care about the threads.
+ if (pid == *it) {
+ continue;
+ }
+ VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump);
+ }
+ ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+ kill(pid, SIGKILL);
+ int status;
+ ASSERT_EQ(waitpid(pid, &status, 0), pid);
+}
+
+void VerifyLevelThread(void*) {
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+ VerifyLevelDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_level) {
+ ASSERT_NE(test_level_one(1, 2, 3, 4, VerifyLevelThread, NULL), 0);
+}
+
+void VerifyMaxThread(void*) {
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, getpid(), gettid(), 0));
+
+ VerifyMaxDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+}
+
+TEST(libbacktrace, thread_current_max) {
+ ASSERT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, VerifyMaxThread, NULL), 0);
+}
+
+void* ThreadLevelRun(void* data) {
+ thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+ thread->tid = gettid();
+ EXPECT_NE(test_level_one(1, 2, 3, 4, ThreadSetState, data), 0);
+ return NULL;
+}
+
+TEST(libbacktrace, thread_level_trace) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ thread_t thread_data = { 0, 0, 0 };
+ pthread_t thread;
+ ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+ // Wait up to 2 seconds for the tid to be set.
+ ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+ // Save the current signal action and make sure it is restored afterwards.
+ struct sigaction cur_action;
+ ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid,0));
+
+ VerifyLevelDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+
+ // Tell the thread to exit its infinite loop.
+ android_atomic_acquire_store(0, &thread_data.state);
+
+ // Verify that the old action was restored.
+ struct sigaction new_action;
+ ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+ EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
+ EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
+}
+
+TEST(libbacktrace, thread_ignore_frames) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ thread_t thread_data = { 0, 0, 0 };
+ pthread_t thread;
+ ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
+
+ // Wait up to 2 seconds for the tid to be set.
+ ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+ backtrace_context_t all;
+ ASSERT_TRUE(backtrace_create_context(&all, getpid(), thread_data.tid, 0));
+
+ backtrace_context_t ign1;
+ ASSERT_TRUE(backtrace_create_context(&ign1, getpid(), thread_data.tid, 1));
+
+ backtrace_context_t ign2;
+ ASSERT_TRUE(backtrace_create_context(&ign2, getpid(), thread_data.tid, 2));
+
+ VerifyIgnoreFrames(all.backtrace, ign1.backtrace, ign2.backtrace, NULL);
+
+ backtrace_destroy_context(&all);
+ backtrace_destroy_context(&ign1);
+ backtrace_destroy_context(&ign2);
+
+ // Tell the thread to exit its infinite loop.
+ android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadMaxRun(void* data) {
+ thread_t* thread = reinterpret_cast<thread_t*>(data);
+
+ thread->tid = gettid();
+ EXPECT_NE(test_recursive_call(MAX_BACKTRACE_FRAMES+10, ThreadSetState, data), 0);
+ return NULL;
+}
+
+TEST(libbacktrace, thread_max_trace) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+ thread_t thread_data = { 0, 0, 0 };
+ pthread_t thread;
+ ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
+
+ // Wait for the tid to be set.
+ ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, getpid(), thread_data.tid, 0));
+
+ VerifyMaxDump(context.backtrace);
+
+ backtrace_destroy_context(&context);
+
+ // Tell the thread to exit its infinite loop.
+ android_atomic_acquire_store(0, &thread_data.state);
+}
+
+void* ThreadDump(void* data) {
+ dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
+ while (true) {
+ if (android_atomic_acquire_load(dump->now)) {
+ break;
+ }
+ }
+
+ dump->context.data = NULL;
+ dump->context.backtrace = NULL;
+
+ // The status of the actual unwind will be checked elsewhere.
+ backtrace_create_context(&dump->context, getpid(), dump->thread.tid, 0);
+
+ android_atomic_acquire_store(1, &dump->done);
+
+ return NULL;
+}
+
+TEST(libbacktrace, thread_multiple_dump) {
+ // Dump NUM_THREADS simultaneously.
+ std::vector<thread_t> runners(NUM_THREADS);
+ std::vector<dump_thread_t> dumpers(NUM_THREADS);
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ for (size_t i = 0; i < NUM_THREADS; i++) {
+ // Launch the runners, they will spin in hard loops doing nothing.
+ runners[i].tid = 0;
+ runners[i].state = 0;
+ ASSERT_TRUE(pthread_create(&runners[i].threadId, &attr, ThreadMaxRun, &runners[i]) == 0);
+ }
+
+ // Wait for tids to be set.
+ for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
+ ASSERT_TRUE(WaitForNonZero(&it->state, 10));
+ }
+
+ // Start all of the dumpers at once, they will spin until they are signalled
+ // to begin their dump run.
+ int32_t dump_now = 0;
+ for (size_t i = 0; i < NUM_THREADS; i++) {
+ dumpers[i].thread.tid = runners[i].tid;
+ dumpers[i].thread.state = 0;
+ dumpers[i].done = 0;
+ dumpers[i].now = &dump_now;
+
+ ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
+ }
+
+ // Start all of the dumpers going at once.
+ android_atomic_acquire_store(1, &dump_now);
+
+ for (size_t i = 0; i < NUM_THREADS; i++) {
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10));
+
+ // Tell the runner thread to exit its infinite loop.
+ android_atomic_acquire_store(0, &runners[i].state);
+
+ ASSERT_TRUE(dumpers[i].context.backtrace != NULL);
+ VerifyMaxDump(dumpers[i].context.backtrace);
+ backtrace_destroy_context(&dumpers[i].context);
+ }
+}
+
+TEST(libbacktrace, format_test) {
+ backtrace_context_t context;
+
+ ASSERT_TRUE(backtrace_create_context(&context, -1, -1, 0));
+ ASSERT_TRUE(context.backtrace != NULL);
+
+ backtrace_frame_data_t* frame = &context.backtrace->frames[1];
+ backtrace_frame_data_t save_frame = *frame;
+
+ memset(frame, 0, sizeof(backtrace_frame_data_t));
+ char buf[512];
+ backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+ EXPECT_STREQ(buf, "#01 pc 0000000000000000 <unknown>");
+#else
+ EXPECT_STREQ(buf, "#01 pc 00000000 <unknown>");
+#endif
+
+ frame->pc = 0x12345678;
+ frame->map_name = "MapFake";
+ backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+ EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake");
+#else
+ EXPECT_STREQ(buf, "#01 pc 12345678 MapFake");
+#endif
+
+ frame->func_name = "ProcFake";
+ backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+ EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake)");
+#else
+ EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake)");
+#endif
+
+ frame->func_offset = 645;
+ backtrace_format_frame_data(&context, 1, buf, sizeof(buf));
+#if defined(__LP64__)
+ EXPECT_STREQ(buf, "#01 pc 0000000012345678 MapFake (ProcFake+645)");
+#else
+ EXPECT_STREQ(buf, "#01 pc 12345678 MapFake (ProcFake+645)");
+#endif
+
+ *frame = save_frame;
+
+ backtrace_destroy_context(&context);
+}
diff --git a/libbacktrace/backtrace_testlib.c b/libbacktrace/backtrace_testlib.c
new file mode 100644
index 0000000..d4d15db
--- /dev/null
+++ b/libbacktrace/backtrace_testlib.c
@@ -0,0 +1,55 @@
+/*
+ * 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>
+
+int test_level_four(int one, int two, int three, int four,
+ void (*callback_func)(void*), void* data) {
+ if (callback_func != NULL) {
+ callback_func(data);
+ } else {
+ while (1) {
+ }
+ }
+ return one + two + three + four;
+}
+
+int test_level_three(int one, int two, int three, int four,
+ void (*callback_func)(void*), void* data) {
+ return test_level_four(one+3, two+6, three+9, four+12, callback_func, data) + 3;
+}
+
+int test_level_two(int one, int two, int three, int four,
+ void (*callback_func)(void*), void* data) {
+ return test_level_three(one+2, two+4, three+6, four+8, callback_func, data) + 2;
+}
+
+int test_level_one(int one, int two, int three, int four,
+ void (*callback_func)(void*), void* data) {
+ return test_level_two(one+1, two+2, three+3, four+4, callback_func, data) + 1;
+}
+
+int test_recursive_call(int level, void (*callback_func)(void*), void* data) {
+ if (level > 0) {
+ return test_recursive_call(level - 1, callback_func, data) + level;
+ } else if (callback_func != NULL) {
+ callback_func(data);
+ } else {
+ while (1) {
+ }
+ }
+ return 0;
+}
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/thread_utils.c b/libbacktrace/thread_utils.c
new file mode 100644
index 0000000..6f4cd3c
--- /dev/null
+++ b/libbacktrace/thread_utils.c
@@ -0,0 +1,42 @@
+/*
+ * 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 "thread_utils.h"
+
+#if defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+pid_t gettid() {
+ return syscall(SYS_thread_selfid);
+}
+
+#elif !defined(__BIONIC__)
+
+// glibc doesn't implement or export either gettid or tgkill.
+#include <unistd.h>
+#include <sys/syscall.h>
+
+pid_t gettid() {
+ return syscall(__NR_gettid);
+}
+
+int tgkill(int tgid, int tid, int sig) {
+ return syscall(__NR_tgkill, tgid, tid, sig);
+}
+
+#endif
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
new file mode 100644
index 0000000..ae4c929
--- /dev/null
+++ b/libbacktrace/thread_utils.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _LIBBACKTRACE_THREAD_UTILS_H
+#define _LIBBACKTRACE_THREAD_UTILS_H
+
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+int tgkill(int tgid, int tid, int sig);
+
+pid_t gettid();
+
+__END_DECLS
+
+#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
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 @@ endif
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 @@ ifeq ($(HOST_OS),linux)
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 @@ static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie
case DW_CFA_offset_extended: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, &reg, 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 @@ static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie
break;
case DW_CFA_restore_extended: // probably we don't have it on x86.
if (!try_get_uleb128(memory, ptr, &reg, 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, &reg, 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, &reg, 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, &reg, 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 @@ static bool get_old_register_value(const memory_t* memory, uint32_t cfa,
/* 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 @@ static bool update_state(const memory_t* memory, unwind_state_t* state,
/* 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 @@ static bool execute_fde(const memory_t* memory,
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 @@ static ssize_t unwind_backtrace_common(const memory_t* memory,
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..f8dda36 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -96,11 +96,6 @@ include $(BUILD_HOST_STATIC_LIBRARY)
# Shared and static library for target
# ========================================================
-# This is needed in LOCAL_C_INCLUDES to access the C library's private
-# header named <bionic_time.h>
-#
-libcutils_c_includes := bionic/libc/private
-
include $(CLEAR_VARS)
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) \
@@ -115,18 +110,18 @@ LOCAL_SRC_FILES := $(commonSources) \
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)
+ LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+ LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
+ 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/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
index b1f09cb..f8b79bd 100644
--- a/libcutils/arch-x86/android_memset16.S
+++ b/libcutils/arch-x86/android_memset16.S
@@ -17,16 +17,9 @@
* Contributed by: Intel Corporation
*/
-#if defined(USE_SSE2)
-
# include "cache_wrapper.S"
# undef __i686
# define USE_AS_ANDROID
# define sse2_memset16_atom android_memset16
# include "sse2-memset16-atom.S"
-#else
-
-# include "memset16.S"
-
-#endif
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
index 1fb2ffe..6249fce 100644
--- a/libcutils/arch-x86/android_memset32.S
+++ b/libcutils/arch-x86/android_memset32.S
@@ -17,17 +17,9 @@
* Contributed by: Intel Corporation
*/
-#if defined(USE_SSE2)
-
# include "cache_wrapper.S"
# undef __i686
# define USE_AS_ANDROID
# define sse2_memset32_atom android_memset32
# include "sse2-memset32-atom.S"
-#else
-
-# include "memset32.S"
-
-#endif
-
diff --git a/libcutils/arch-x86/sse2-memset16-atom.S b/libcutils/arch-x86/sse2-memset16-atom.S
index cafec82..c2a762b 100644..100755
--- a/libcutils/arch-x86/sse2-memset16-atom.S
+++ b/libcutils/arch-x86/sse2-memset16-atom.S
@@ -86,7 +86,7 @@ name: \
# define SETRTNVAL movl DEST(%esp), %eax
#endif
-#ifdef SHARED
+#if (defined SHARED || defined __PIC__)
# define ENTRANCE PUSH (%ebx);
# define RETURN_END POP (%ebx); ret
# define RETURN RETURN_END; CFI_PUSH (%ebx)
@@ -344,7 +344,7 @@ L(128bytesormore):
PUSH (%ebx)
mov $SHARED_CACHE_SIZE, %ebx
#else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
call __i686.get_pc_thunk.bx
add $_GLOBAL_OFFSET_TABLE_, %ebx
mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx
@@ -362,7 +362,7 @@ L(128bytesormore):
# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
cmp $DATA_CACHE_SIZE, %ecx
#else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
# define RESTORE_EBX_STATE
call __i686.get_pc_thunk.bx
add $_GLOBAL_OFFSET_TABLE_, %ebx
@@ -471,7 +471,7 @@ L(128bytesormore_nt):
jae L(128bytesormore_nt)
sfence
L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !defined SHARED
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
POP (%ebx)
#endif
add %ecx, %edx
diff --git a/libcutils/arch-x86/sse2-memset32-atom.S b/libcutils/arch-x86/sse2-memset32-atom.S
index 4a52484..05eb64f 100644..100755
--- a/libcutils/arch-x86/sse2-memset32-atom.S
+++ b/libcutils/arch-x86/sse2-memset32-atom.S
@@ -86,7 +86,7 @@ name: \
# define SETRTNVAL
#endif
-#ifdef SHARED
+#if (defined SHARED || defined __PIC__)
# define ENTRANCE PUSH (%ebx);
# define RETURN_END POP (%ebx); ret
# define RETURN RETURN_END; CFI_PUSH (%ebx)
@@ -259,7 +259,7 @@ L(128bytesormore):
PUSH (%ebx)
mov $SHARED_CACHE_SIZE, %ebx
#else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
call __i686.get_pc_thunk.bx
add $_GLOBAL_OFFSET_TABLE_, %ebx
mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx
@@ -276,7 +276,7 @@ L(128bytesormore):
# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
cmp $DATA_CACHE_SIZE, %ecx
#else
-# ifdef SHARED
+# if (defined SHARED || defined __PIC__)
# define RESTORE_EBX_STATE
call __i686.get_pc_thunk.bx
add $_GLOBAL_OFFSET_TABLE_, %ebx
@@ -386,7 +386,7 @@ L(128bytesormore_nt):
jae L(128bytesormore_nt)
sfence
L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !defined SHARED
+#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
POP (%ebx)
#endif
add %ecx, %edx
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 @@ int ashmem_create_region(const char *name, size_t size)
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/libcutils/dir_hash.c b/libcutils/dir_hash.c
index be14af6..098b5db 100644
--- a/libcutils/dir_hash.c
+++ b/libcutils/dir_hash.c
@@ -159,6 +159,7 @@ static int recurse(HashAlgorithm algorithm, const char *directory_path,
free(name);
free(node);
+ closedir(d);
return -1;
}
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 090d0e5..7906986 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -1,18 +1,18 @@
# Copyright 2008 The Android Open Source Project
#
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+include $(CLEAR_VARS)
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-
LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := rsa.c sha.c sha256.c
+LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
-
include $(LOCAL_PATH)/tools/Android.mk \
$(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
new file mode 100644
index 0000000..8df6cf7
--- /dev/null
+++ b/libmincrypt/dsa_sig.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "mincrypt/p256.h"
+
+/**
+ * Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
+ */
+static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
+ int src_len) {
+ int dst_offset;
+ while (*src == '\0' && src_len > 0) {
+ src++;
+ src_len--;
+ }
+ if (src_len > P256_NBYTES || src_len < 1) {
+ return 0;
+ }
+ dst_offset = P256_NBYTES - src_len;
+ memset(dst, 0, dst_offset);
+ memcpy(dst + dst_offset, src, src_len);
+ return 1;
+}
+
+/**
+ * Unpacks the ASN.1 DSA signature sequence.
+ */
+int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
+ /*
+ * Structure is:
+ * 0x30 0xNN SEQUENCE + s_length
+ * 0x02 0xNN INTEGER + r_length
+ * 0xAA 0xBB .. r_length bytes of "r" (offset 4)
+ * 0x02 0xNN INTEGER + s_length
+ * 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len)
+ */
+ int seq_len;
+ unsigned char r_bytes[P256_NBYTES];
+ unsigned char s_bytes[P256_NBYTES];
+ int r_len;
+ int s_len;
+
+ memset(r_bytes, 0, sizeof(r_bytes));
+ memset(s_bytes, 0, sizeof(s_bytes));
+
+ /*
+ * Must have at least:
+ * 2 bytes sequence header and length
+ * 2 bytes R integer header and length
+ * 1 byte of R
+ * 2 bytes S integer header and length
+ * 1 byte of S
+ *
+ * 8 bytes total
+ */
+ if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
+ return 0;
+ }
+
+ seq_len = sig[1];
+ if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
+ return 0;
+ }
+
+ r_len = sig[3];
+ /*
+ * Must have at least:
+ * 2 bytes for R header and length
+ * 2 bytes S integer header and length
+ * 1 byte of S
+ */
+ if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
+ return 0;
+ }
+ s_len = sig[5 + r_len];
+
+ /**
+ * Must have:
+ * 2 bytes for R header and length
+ * r_len bytes for R
+ * 2 bytes S integer header and length
+ */
+ if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
+ return 0;
+ }
+
+ /*
+ * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
+ * a correctly-sized buffer and that the resulting integer isn't too large.
+ */
+ if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
+ || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
+ return 0;
+ }
+
+ p256_from_bin(r_bytes, r_int);
+ p256_from_bin(s_bytes, s_int);
+
+ return 1;
+}
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
new file mode 100644
index 0000000..1608d37
--- /dev/null
+++ b/libmincrypt/p256.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This is an implementation of the P256 elliptic curve group. It's written to
+// be portable 32-bit, although it's still constant-time.
+//
+// WARNING: Implementing these functions in a constant-time manner is far from
+// obvious. Be careful when touching this code.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "mincrypt/p256.h"
+
+const p256_int SECP256r1_n = // curve order
+ {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
+
+const p256_int SECP256r1_p = // curve field size
+ {{-1, -1, -1, 0, 0, 0, 1, -1 }};
+
+const p256_int SECP256r1_b = // curve b
+ {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
+ 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
+
+static const p256_int p256_one = P256_ONE;
+
+void p256_init(p256_int* a) {
+ memset(a, 0, sizeof(*a));
+}
+
+void p256_clear(p256_int* a) { p256_init(a); }
+
+int p256_get_bit(const p256_int* scalar, int bit) {
+ return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
+ >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
+}
+
+int p256_is_zero(const p256_int* a) {
+ int i, result = 0;
+ for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
+ return !result;
+}
+
+// top, c[] += a[] * b
+// Returns new top
+static p256_digit mulAdd(const p256_int* a,
+ p256_digit b,
+ p256_digit top,
+ p256_digit* c) {
+ int i;
+ p256_ddigit carry = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += *c;
+ carry += (p256_ddigit)P256_DIGIT(a, i) * b;
+ *c++ = (p256_digit)carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit)carry;
+}
+
+// top, c[] -= top_a, a[]
+static p256_digit subTop(p256_digit top_a,
+ const p256_digit* a,
+ p256_digit top_c,
+ p256_digit* c) {
+ int i;
+ p256_sddigit borrow = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += *c;
+ borrow -= *a++;
+ *c++ = (p256_digit)borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ borrow += top_c;
+ borrow -= top_a;
+ top_c = (p256_digit)borrow;
+ assert((borrow >> P256_BITSPERDIGIT) == 0);
+ return top_c;
+}
+
+// top, c[] -= MOD[] & mask (0 or -1)
+// returns new top.
+static p256_digit subM(const p256_int* MOD,
+ p256_digit top,
+ p256_digit* c,
+ p256_digit mask) {
+ int i;
+ p256_sddigit borrow = 0;
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += *c;
+ borrow -= P256_DIGIT(MOD, i) & mask;
+ *c++ = (p256_digit)borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit)borrow;
+}
+
+// top, c[] += MOD[] & mask (0 or -1)
+// returns new top.
+static p256_digit addM(const p256_int* MOD,
+ p256_digit top,
+ p256_digit* c,
+ p256_digit mask) {
+ int i;
+ p256_ddigit carry = 0;
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += *c;
+ carry += P256_DIGIT(MOD, i) & mask;
+ *c++ = (p256_digit)carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return top + (p256_digit)carry;
+}
+
+// c = a * b mod MOD. c can be a and/or b.
+void p256_modmul(const p256_int* MOD,
+ const p256_int* a,
+ const p256_digit top_b,
+ const p256_int* b,
+ p256_int* c) {
+ p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
+ p256_digit top = 0;
+ int i;
+
+ // Multiply/add into tmp.
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ if (i) tmp[i + P256_NDIGITS - 1] = top;
+ top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
+ }
+
+ // Multiply/add top digit
+ tmp[i + P256_NDIGITS - 1] = top;
+ top = mulAdd(a, top_b, 0, tmp + i);
+
+ // Reduce tmp, digit by digit.
+ for (; i >= 0; --i) {
+ p256_digit reducer[P256_NDIGITS] = { 0 };
+ p256_digit top_reducer;
+
+ // top can be any value at this point.
+ // Guestimate reducer as top * MOD, since msw of MOD is -1.
+ top_reducer = mulAdd(MOD, top, 0, reducer);
+
+ // Subtract reducer from top | tmp.
+ top = subTop(top_reducer, reducer, top, tmp + i);
+
+ // top is now either 0 or 1. Make it 0, fixed-timing.
+ assert(top <= 1);
+
+ top = subM(MOD, top, tmp + i, ~(top - 1));
+
+ assert(top == 0);
+
+ // We have now reduced the top digit off tmp. Fetch new top digit.
+ top = tmp[i + P256_NDIGITS - 1];
+ }
+
+ // tmp might still be larger than MOD, yet same bit length.
+ // Make sure it is less, fixed-timing.
+ addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
+
+ memcpy(c, tmp, P256_NBYTES);
+}
+int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
+int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
+
+p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
+ int i;
+ p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
+
+ n %= P256_BITSPERDIGIT;
+ for (i = P256_NDIGITS - 1; i > 0; --i) {
+ p256_digit accu = (P256_DIGIT(a, i) << n);
+ accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
+
+ top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
+
+ return top;
+}
+
+void p256_shr(const p256_int* a, int n, p256_int* b) {
+ int i;
+
+ n %= P256_BITSPERDIGIT;
+ for (i = 0; i < P256_NDIGITS - 1; ++i) {
+ p256_digit accu = (P256_DIGIT(a, i) >> n);
+ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
+}
+
+static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
+ int i;
+
+ for (i = 0; i < P256_NDIGITS - 1; ++i) {
+ p256_digit accu = (P256_DIGIT(a, i) >> 1);
+ accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
+ P256_DIGIT(b, i) = accu;
+ }
+ P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
+ (highbit << (P256_BITSPERDIGIT - 1));
+}
+
+// Return -1, 0, 1 for a < b, a == b or a > b respectively.
+int p256_cmp(const p256_int* a, const p256_int* b) {
+ int i;
+ p256_sddigit borrow = 0;
+ p256_digit notzero = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
+ // Track whether any result digit is ever not zero.
+ // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
+ notzero |= !!((p256_digit)borrow);
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int)borrow | notzero;
+}
+
+// c = a - b. Returns borrow: 0 or -1.
+int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
+ int i;
+ p256_sddigit borrow = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
+ if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
+ borrow >>= P256_BITSPERDIGIT;
+ }
+ return (int)borrow;
+}
+
+// c = a + b. Returns carry: 0 or 1.
+int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
+ int i;
+ p256_ddigit carry = 0;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
+ if (c) P256_DIGIT(c, i) = (p256_digit)carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return (int)carry;
+}
+
+// b = a + d. Returns carry, 0 or 1.
+int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
+ int i;
+ p256_ddigit carry = d;
+
+ for (i = 0; i < P256_NDIGITS; ++i) {
+ carry += (p256_ddigit)P256_DIGIT(a, i);
+ if (b) P256_DIGIT(b, i) = (p256_digit)carry;
+ carry >>= P256_BITSPERDIGIT;
+ }
+ return (int)carry;
+}
+
+// b = 1/a mod MOD, binary euclid.
+void p256_modinv_vartime(const p256_int* MOD,
+ const p256_int* a,
+ p256_int* b) {
+ p256_int R = P256_ZERO;
+ p256_int S = P256_ONE;
+ p256_int U = *MOD;
+ p256_int V = *a;
+
+ for (;;) {
+ if (p256_is_even(&U)) {
+ p256_shr1(&U, 0, &U);
+ if (p256_is_even(&R)) {
+ p256_shr1(&R, 0, &R);
+ } else {
+ // R = (R+MOD)/2
+ p256_shr1(&R, p256_add(&R, MOD, &R), &R);
+ }
+ } else if (p256_is_even(&V)) {
+ p256_shr1(&V, 0, &V);
+ if (p256_is_even(&S)) {
+ p256_shr1(&S, 0, &S);
+ } else {
+ // S = (S+MOD)/2
+ p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
+ }
+ } else { // U,V both odd.
+ if (!p256_sub(&V, &U, NULL)) {
+ p256_sub(&V, &U, &V);
+ if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
+ if (p256_is_zero(&V)) break; // done.
+ } else {
+ p256_sub(&U, &V, &U);
+ if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
+ }
+ }
+ }
+
+ p256_mod(MOD, &R, b);
+}
+
+void p256_mod(const p256_int* MOD,
+ const p256_int* in,
+ p256_int* out) {
+ if (out != in) *out = *in;
+ addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
+}
+
+// Verify y^2 == x^3 - 3x + b mod p
+// and 0 < x < p and 0 < y < p
+int p256_is_valid_point(const p256_int* x, const p256_int* y) {
+ p256_int y2, x3;
+
+ if (p256_cmp(&SECP256r1_p, x) <= 0 ||
+ p256_cmp(&SECP256r1_p, y) <= 0 ||
+ p256_is_zero(x) ||
+ p256_is_zero(y)) return 0;
+
+ p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2
+
+ p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2
+ p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3
+ if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x
+ if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x
+ if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x
+ if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b
+ p256_sub(&x3, &SECP256r1_p, &x3);
+
+ return p256_cmp(&y2, &x3) == 0;
+}
+
+void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
+ int i;
+ const uint8_t* p = &src[0];
+
+ for (i = P256_NDIGITS - 1; i >= 0; --i) {
+ P256_DIGIT(dst, i) =
+ (p[0] << 24) |
+ (p[1] << 16) |
+ (p[2] << 8) |
+ p[3];
+ p += 4;
+ }
+}
diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c
new file mode 100644
index 0000000..90262cc
--- /dev/null
+++ b/libmincrypt/p256_ec.c
@@ -0,0 +1,1279 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This is an implementation of the P256 elliptic curve group. It's written to
+// be portable 32-bit, although it's still constant-time.
+//
+// WARNING: Implementing these functions in a constant-time manner is far from
+// obvious. Be careful when touching this code.
+//
+// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mincrypt/p256.h"
+
+typedef uint8_t u8;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+
+/* Our field elements are represented as nine 32-bit limbs.
+ *
+ * The value of an felem (field element) is:
+ * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
+ *
+ * That is, each limb is alternately 29 or 28-bits wide in little-endian
+ * order.
+ *
+ * This means that an felem hits 2**257, rather than 2**256 as we would like. A
+ * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
+ * when multiplying as terms end up one bit short of a limb which would require
+ * much bit-shifting to correct.
+ *
+ * Finally, the values stored in an felem are in Montgomery form. So the value
+ * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
+ */
+typedef u32 limb;
+#define NLIMBS 9
+typedef limb felem[NLIMBS];
+
+static const limb kBottom28Bits = 0xfffffff;
+static const limb kBottom29Bits = 0x1fffffff;
+
+/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
+ * 28-bit words. */
+static const felem kOne = {
+ 2, 0, 0, 0xffff800,
+ 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
+ 0
+};
+static const felem kZero = {0};
+static const felem kP = {
+ 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
+ 0, 0, 0x200000, 0xf000000,
+ 0xfffffff
+};
+static const felem k2P = {
+ 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
+ 0, 0, 0x400000, 0xe000000,
+ 0x1fffffff
+};
+/* kPrecomputed contains precomputed values to aid the calculation of scalar
+ * multiples of the base point, G. It's actually two, equal length, tables
+ * concatenated.
+ *
+ * The first table contains (x,y) felem pairs for 16 multiples of the base
+ * point, G.
+ *
+ * Index | Index (binary) | Value
+ * 0 | 0000 | 0G (all zeros, omitted)
+ * 1 | 0001 | G
+ * 2 | 0010 | 2**64G
+ * 3 | 0011 | 2**64G + G
+ * 4 | 0100 | 2**128G
+ * 5 | 0101 | 2**128G + G
+ * 6 | 0110 | 2**128G + 2**64G
+ * 7 | 0111 | 2**128G + 2**64G + G
+ * 8 | 1000 | 2**192G
+ * 9 | 1001 | 2**192G + G
+ * 10 | 1010 | 2**192G + 2**64G
+ * 11 | 1011 | 2**192G + 2**64G + G
+ * 12 | 1100 | 2**192G + 2**128G
+ * 13 | 1101 | 2**192G + 2**128G + G
+ * 14 | 1110 | 2**192G + 2**128G + 2**64G
+ * 15 | 1111 | 2**192G + 2**128G + 2**64G + G
+ *
+ * The second table follows the same style, but the terms are 2**32G,
+ * 2**96G, 2**160G, 2**224G.
+ *
+ * This is ~2KB of data. */
+static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
+ 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
+ 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
+ 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
+ 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
+ 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
+ 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
+ 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
+ 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
+ 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
+ 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
+ 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
+ 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
+ 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
+ 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
+ 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
+ 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
+ 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
+ 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
+ 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
+ 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
+ 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
+ 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
+ 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
+ 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
+ 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
+ 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
+ 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
+ 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
+ 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
+ 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
+ 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
+ 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
+ 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
+ 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
+ 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
+ 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
+ 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
+ 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
+ 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
+ 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
+ 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
+ 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
+ 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
+ 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
+ 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
+ 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
+ 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
+ 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
+ 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
+ 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
+ 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
+ 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
+ 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
+ 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
+ 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
+ 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
+ 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
+ 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
+ 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
+ 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
+};
+
+
+/* Field element operations: */
+
+/* NON_ZERO_TO_ALL_ONES returns:
+ * 0xffffffff for 0 < x <= 2**31
+ * 0 for x == 0 or x > 2**31.
+ *
+ * x must be a u32 or an equivalent type such as limb. */
+#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
+
+/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
+ * which is a term at 2**257.
+ *
+ * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
+ * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
+static void felem_reduce_carry(felem inout, limb carry) {
+ const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
+
+ inout[0] += carry << 1;
+ inout[3] += 0x10000000 & carry_mask;
+ /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
+ * previous line therefore this doesn't underflow. */
+ inout[3] -= carry << 11;
+ inout[4] += (0x20000000 - 1) & carry_mask;
+ inout[5] += (0x10000000 - 1) & carry_mask;
+ inout[6] += (0x20000000 - 1) & carry_mask;
+ inout[6] -= carry << 22;
+ /* This may underflow if carry is non-zero but, if so, we'll fix it in the
+ * next line. */
+ inout[7] -= 1 & carry_mask;
+ inout[7] += carry << 25;
+}
+
+/* felem_sum sets out = in+in2.
+ *
+ * On entry, in[i]+in2[i] must not overflow a 32-bit word.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_sum(felem out, const felem in, const felem in2) {
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] = in[i] + in2[i];
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] = in[i] + in2[i];
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+#define two31m3 (((limb)1) << 31) - (((limb)1) << 3)
+#define two30m2 (((limb)1) << 30) - (((limb)1) << 2)
+#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2)
+#define two31m2 (((limb)1) << 31) - (((limb)1) << 2)
+#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2)
+#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2)
+
+/* zero31 is 0 mod p. */
+static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 };
+
+/* felem_diff sets out = in-in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_diff(felem out, const felem in, const felem in2) {
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] = in[i] - in2[i];
+ out[i] += zero31[i];
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] = in[i] - in2[i];
+ out[i] += zero31[i];
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
+ * with the same 29,28,... bit positions as an felem.
+ *
+ * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
+ * Since we just multiplied two Montgomery values together, the result is
+ * x*y*R*R mod p. We wish to divide by R in order for the result also to be
+ * in Montgomery form.
+ *
+ * On entry: tmp[i] < 2**64
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
+static void felem_reduce_degree(felem out, u64 tmp[17]) {
+ /* The following table may be helpful when reading this code:
+ *
+ * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
+ * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
+ * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285
+ * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
+ limb tmp2[18], carry, x, xMask;
+ unsigned i;
+
+ /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
+ * felem. So the top of an element of tmp might overlap with another
+ * element two positions down. The following loop eliminates this
+ * overlap. */
+ tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
+
+ /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try
+ * and hint to the compiler that it can do a single-word shift by selecting
+ * the right register rather than doing a double-word shift and truncating
+ * afterwards. */
+ tmp2[1] = ((limb) tmp[0]) >> 29;
+ tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
+ tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
+ carry = tmp2[1] >> 28;
+ tmp2[1] &= kBottom28Bits;
+
+ for (i = 2; i < 17; i++) {
+ tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+ tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
+ tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
+ tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
+ tmp2[i] += carry;
+ carry = tmp2[i] >> 29;
+ tmp2[i] &= kBottom29Bits;
+
+ i++;
+ if (i == 17)
+ break;
+ tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
+ tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
+ tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
+ tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
+ tmp2[i] += carry;
+ carry = tmp2[i] >> 28;
+ tmp2[i] &= kBottom28Bits;
+ }
+
+ tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
+ tmp2[17] += ((limb)(tmp[16])) >> 29;
+ tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
+ tmp2[17] += carry;
+
+ /* Montgomery elimination of terms.
+ *
+ * Since R is 2**257, we can divide by R with a bitwise shift if we can
+ * ensure that the right-most 257 bits are all zero. We can make that true by
+ * adding multiplies of p without affecting the value.
+ *
+ * So we eliminate limbs from right to left. Since the bottom 29 bits of p
+ * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
+ * We can do that for 8 further limbs and then right shift to eliminate the
+ * extra factor of R. */
+ for (i = 0;; i += 2) {
+ tmp2[i + 1] += tmp2[i] >> 29;
+ x = tmp2[i] & kBottom29Bits;
+ xMask = NON_ZERO_TO_ALL_ONES(x);
+ tmp2[i] = 0;
+
+ /* The bounds calculations for this loop are tricky. Each iteration of
+ * the loop eliminates two words by adding values to words to their
+ * right.
+ *
+ * The following table contains the amounts added to each word (as an
+ * offset from the value of i at the top of the loop). The amounts are
+ * accounted for from the first and second half of the loop separately
+ * and are written as, for example, 28 to mean a value <2**28.
+ *
+ * Word: 3 4 5 6 7 8 9 10
+ * Added in top half: 28 11 29 21 29 28
+ * 28 29
+ * 29
+ * Added in bottom half: 29 10 28 21 28 28
+ * 29
+ *
+ * The value that is currently offset 7 will be offset 5 for the next
+ * iteration and then offset 3 for the iteration after that. Therefore
+ * the total value added will be the values added at 7, 5 and 3.
+ *
+ * The following table accumulates these values. The sums at the bottom
+ * are written as, for example, 29+28, to mean a value < 2**29+2**28.
+ *
+ * Word: 3 4 5 6 7 8 9 10 11 12 13
+ * 28 11 10 29 21 29 28 28 28 28 28
+ * 29 28 11 28 29 28 29 28 29 28
+ * 29 28 21 21 29 21 29 21
+ * 10 29 28 21 28 21 28
+ * 28 29 28 29 28 29 28
+ * 11 10 29 10 29 10
+ * 29 28 11 28 11
+ * 29 29
+ * --------------------------------------------
+ * 30+ 31+ 30+ 31+ 30+
+ * 28+ 29+ 28+ 29+ 21+
+ * 21+ 28+ 21+ 28+ 10
+ * 10 21+ 10 21+
+ * 11 11
+ *
+ * So the greatest amount is added to tmp2[10] and tmp2[12]. If
+ * tmp2[10/12] has an initial value of <2**29, then the maximum value
+ * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
+ * as required. */
+ tmp2[i + 3] += (x << 10) & kBottom28Bits;
+ tmp2[i + 4] += (x >> 18);
+
+ tmp2[i + 6] += (x << 21) & kBottom29Bits;
+ tmp2[i + 7] += x >> 8;
+
+ /* At position 200, which is the starting bit position for word 7, we
+ * have a factor of 0xf000000 = 2**28 - 2**24. */
+ tmp2[i + 7] += 0x10000000 & xMask;
+ /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */
+ tmp2[i + 8] += (x - 1) & xMask;
+ tmp2[i + 7] -= (x << 24) & kBottom28Bits;
+ tmp2[i + 8] -= x >> 4;
+
+ tmp2[i + 8] += 0x20000000 & xMask;
+ tmp2[i + 8] -= x;
+ tmp2[i + 8] += (x << 28) & kBottom29Bits;
+ tmp2[i + 9] += ((x >> 1) - 1) & xMask;
+
+ if (i+1 == NLIMBS)
+ break;
+ tmp2[i + 2] += tmp2[i + 1] >> 28;
+ x = tmp2[i + 1] & kBottom28Bits;
+ xMask = NON_ZERO_TO_ALL_ONES(x);
+ tmp2[i + 1] = 0;
+
+ tmp2[i + 4] += (x << 11) & kBottom29Bits;
+ tmp2[i + 5] += (x >> 18);
+
+ tmp2[i + 7] += (x << 21) & kBottom28Bits;
+ tmp2[i + 8] += x >> 7;
+
+ /* At position 199, which is the starting bit of the 8th word when
+ * dealing with a context starting on an odd word, we have a factor of
+ * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
+ * word from i+1 is i+8. */
+ tmp2[i + 8] += 0x20000000 & xMask;
+ tmp2[i + 9] += (x - 1) & xMask;
+ tmp2[i + 8] -= (x << 25) & kBottom29Bits;
+ tmp2[i + 9] -= x >> 4;
+
+ tmp2[i + 9] += 0x10000000 & xMask;
+ tmp2[i + 9] -= x;
+ tmp2[i + 10] += (x - 1) & xMask;
+ }
+
+ /* We merge the right shift with a carry chain. The words above 2**257 have
+ * widths of 28,29,... which we need to correct when copying them down. */
+ carry = 0;
+ for (i = 0; i < 8; i++) {
+ /* The maximum value of tmp2[i + 9] occurs on the first iteration and
+ * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
+ * therefore safe. */
+ out[i] = tmp2[i + 9];
+ out[i] += carry;
+ out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ out[i] = tmp2[i + 9] >> 1;
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ out[8] = tmp2[17];
+ out[8] += carry;
+ carry = out[8] >> 29;
+ out[8] &= kBottom29Bits;
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_square sets out=in*in.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_square(felem out, const felem in) {
+ u64 tmp[17];
+
+ tmp[0] = ((u64) in[0]) * in[0];
+ tmp[1] = ((u64) in[0]) * (in[1] << 1);
+ tmp[2] = ((u64) in[0]) * (in[2] << 1) +
+ ((u64) in[1]) * (in[1] << 1);
+ tmp[3] = ((u64) in[0]) * (in[3] << 1) +
+ ((u64) in[1]) * (in[2] << 1);
+ tmp[4] = ((u64) in[0]) * (in[4] << 1) +
+ ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
+ tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
+ (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
+ tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
+ (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
+ ((u64) in[3]) * (in[3] << 1);
+ tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
+ (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
+ ((u64) in[3]) * (in[4] << 1);
+ /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
+ * which is < 2**64 as required. */
+ tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
+ (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
+ ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
+ tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
+ (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
+ ((u64) in[4]) * (in[5] << 1);
+ tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
+ (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
+ ((u64) in[5]) * (in[5] << 1);
+ tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
+ (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
+ tmp[12] = ((u64) in[4]) * (in[8] << 1) +
+ ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
+ tmp[13] = ((u64) in[5]) * (in[8] << 1) +
+ ((u64) in[6]) * (in[7] << 1);
+ tmp[14] = ((u64) in[6]) * (in[8] << 1) +
+ ((u64) in[7]) * (in[7] << 1);
+ tmp[15] = ((u64) in[7]) * (in[8] << 1);
+ tmp[16] = ((u64) in[8]) * in[8];
+
+ felem_reduce_degree(out, tmp);
+}
+
+/* felem_mul sets out=in*in2.
+ *
+ * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
+ * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_mul(felem out, const felem in, const felem in2) {
+ u64 tmp[17];
+
+ tmp[0] = ((u64) in[0]) * in2[0];
+ tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
+ ((u64) in[1]) * (in2[0] << 0);
+ tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
+ (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
+ tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
+ (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
+ ((u64) in[3]) * (in2[0] << 0);
+ tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
+ (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
+ ((u64) in[3]) * (in2[1] << 1) +
+ ((u64) in[4]) * (in2[0] << 0);
+ tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
+ (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
+ ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
+ (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
+ tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
+ (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
+ ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
+ (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
+ ((u64) in[6]) * (in2[0] << 0);
+ tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
+ (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
+ ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
+ (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
+ ((u64) in[6]) * (in2[1] << 0) +
+ ((u64) in[7]) * (in2[0] << 0);
+ /* tmp[8] has the greatest value but doesn't overflow. See logic in
+ * felem_square. */
+ tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
+ (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
+ ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
+ (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
+ ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
+ (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
+ tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
+ (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
+ ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
+ (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
+ ((u64) in[7]) * (in2[2] << 0) +
+ ((u64) in[8]) * (in2[1] << 0);
+ tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
+ (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
+ ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
+ (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
+ ((u64) in[8]) * (in2[2] << 0);
+ tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
+ (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
+ ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
+ (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
+ tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
+ (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
+ ((u64) in[7]) * (in2[5] << 1) +
+ ((u64) in[8]) * (in2[4] << 0);
+ tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
+ (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
+ ((u64) in[8]) * (in2[5] << 0);
+ tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
+ (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
+ tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
+ ((u64) in[8]) * (in2[7] << 0);
+ tmp[16] = ((u64) in[8]) * (in2[8] << 0);
+
+ felem_reduce_degree(out, tmp);
+}
+
+static void felem_assign(felem out, const felem in) {
+ memcpy(out, in, sizeof(felem));
+}
+
+/* felem_inv calculates |out| = |in|^{-1}
+ *
+ * Based on Fermat's Little Theorem:
+ * a^p = a (mod p)
+ * a^{p-1} = 1 (mod p)
+ * a^{p-2} = a^{-1} (mod p)
+ */
+static void felem_inv(felem out, const felem in) {
+ felem ftmp, ftmp2;
+ /* each e_I will hold |in|^{2^I - 1} */
+ felem e2, e4, e8, e16, e32, e64;
+ unsigned i;
+
+ felem_square(ftmp, in); /* 2^1 */
+ felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
+ felem_assign(e2, ftmp);
+ felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
+ felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
+ felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
+ felem_assign(e4, ftmp);
+ felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
+ felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
+ felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
+ felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
+ felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
+ felem_assign(e8, ftmp);
+ for (i = 0; i < 8; i++) {
+ felem_square(ftmp, ftmp);
+ } /* 2^16 - 2^8 */
+ felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
+ felem_assign(e16, ftmp);
+ for (i = 0; i < 16; i++) {
+ felem_square(ftmp, ftmp);
+ } /* 2^32 - 2^16 */
+ felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
+ felem_assign(e32, ftmp);
+ for (i = 0; i < 32; i++) {
+ felem_square(ftmp, ftmp);
+ } /* 2^64 - 2^32 */
+ felem_assign(e64, ftmp);
+ felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
+ for (i = 0; i < 192; i++) {
+ felem_square(ftmp, ftmp);
+ } /* 2^256 - 2^224 + 2^192 */
+
+ felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
+ for (i = 0; i < 16; i++) {
+ felem_square(ftmp2, ftmp2);
+ } /* 2^80 - 2^16 */
+ felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
+ for (i = 0; i < 8; i++) {
+ felem_square(ftmp2, ftmp2);
+ } /* 2^88 - 2^8 */
+ felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
+ for (i = 0; i < 4; i++) {
+ felem_square(ftmp2, ftmp2);
+ } /* 2^92 - 2^4 */
+ felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
+ felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
+ felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
+ felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
+ felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
+ felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
+ felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
+
+ felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
+}
+
+/* felem_scalar_3 sets out=3*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_3(felem out) {
+ limb carry = 0;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ out[i] *= 3;
+ out[i] += carry;
+ carry = out[i] >> 29;
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ out[i] *= 3;
+ out[i] += carry;
+ carry = out[i] >> 28;
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_4 sets out=4*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_4(felem out) {
+ limb carry = 0, next_carry;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ next_carry = out[i] >> 27;
+ out[i] <<= 2;
+ out[i] &= kBottom29Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 29);
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ next_carry = out[i] >> 26;
+ out[i] <<= 2;
+ out[i] &= kBottom28Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 28);
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_scalar_8 sets out=8*out.
+ *
+ * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
+ * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
+static void felem_scalar_8(felem out) {
+ limb carry = 0, next_carry;
+ unsigned i;
+
+ for (i = 0;; i++) {
+ next_carry = out[i] >> 26;
+ out[i] <<= 3;
+ out[i] &= kBottom29Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 29);
+ out[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ next_carry = out[i] >> 25;
+ out[i] <<= 3;
+ out[i] &= kBottom28Bits;
+ out[i] += carry;
+ carry = next_carry + (out[i] >> 28);
+ out[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(out, carry);
+}
+
+/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
+ * time depending on the value of |in|. */
+static char felem_is_zero_vartime(const felem in) {
+ limb carry;
+ int i;
+ limb tmp[NLIMBS];
+
+ felem_assign(tmp, in);
+
+ /* First, reduce tmp to a minimal form. */
+ do {
+ carry = 0;
+ for (i = 0;; i++) {
+ tmp[i] += carry;
+ carry = tmp[i] >> 29;
+ tmp[i] &= kBottom29Bits;
+
+ i++;
+ if (i == NLIMBS)
+ break;
+
+ tmp[i] += carry;
+ carry = tmp[i] >> 28;
+ tmp[i] &= kBottom28Bits;
+ }
+
+ felem_reduce_carry(tmp, carry);
+ } while (carry);
+
+ /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
+ return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
+ memcmp(tmp, kP, sizeof(tmp)) == 0 ||
+ memcmp(tmp, k2P, sizeof(tmp)) == 0;
+}
+
+
+/* Group operations:
+ *
+ * Elements of the elliptic curve group are represented in Jacobian
+ * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
+ * Jacobian form. */
+
+/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
+static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
+ const felem y, const felem z) {
+ felem delta, gamma, alpha, beta, tmp, tmp2;
+
+ felem_square(delta, z);
+ felem_square(gamma, y);
+ felem_mul(beta, x, gamma);
+
+ felem_sum(tmp, x, delta);
+ felem_diff(tmp2, x, delta);
+ felem_mul(alpha, tmp, tmp2);
+ felem_scalar_3(alpha);
+
+ felem_sum(tmp, y, z);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, gamma);
+ felem_diff(z_out, tmp, delta);
+
+ felem_scalar_4(beta);
+ felem_square(x_out, alpha);
+ felem_diff(x_out, x_out, beta);
+ felem_diff(x_out, x_out, beta);
+
+ felem_diff(tmp, beta, x_out);
+ felem_mul(tmp, alpha, tmp);
+ felem_square(tmp2, gamma);
+ felem_scalar_8(tmp2);
+ felem_diff(y_out, tmp, tmp2);
+}
+
+/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
+ * (i.e. the second point is affine.)
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add_mixed(felem x_out, felem y_out, felem z_out,
+ const felem x1, const felem y1, const felem z1,
+ const felem x2, const felem y2) {
+ felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
+
+ felem_square(z1z1, z1);
+ felem_sum(tmp, z1, z1);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, x1);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, y1);
+ felem_sum(r, r, r);
+ felem_mul(v, x1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, y1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * Note that this function does not handle P+P, infinity+P nor P+infinity
+ * correctly. */
+static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
+ const felem y1, const felem z1, const felem x2,
+ const felem y2, const felem z2) {
+ felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
+
+ felem_square(z1z1, z1);
+ felem_square(z2z2, z2);
+ felem_mul(u1, x1, z2z2);
+
+ felem_sum(tmp, z1, z2);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, z1z1);
+ felem_diff(tmp, tmp, z2z2);
+
+ felem_mul(z2z2z2, z2, z2z2);
+ felem_mul(s1, y1, z2z2z2);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, u1);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, s1);
+ felem_sum(r, r, r);
+ felem_mul(v, u1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, s1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
+ * {x2,y2,z2}.
+ *
+ * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
+ *
+ * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
+static void point_add_or_double_vartime(
+ felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
+ const felem z1, const felem x2, const felem y2, const felem z2) {
+ felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
+ char x_equal, y_equal;
+
+ felem_square(z1z1, z1);
+ felem_square(z2z2, z2);
+ felem_mul(u1, x1, z2z2);
+
+ felem_sum(tmp, z1, z2);
+ felem_square(tmp, tmp);
+ felem_diff(tmp, tmp, z1z1);
+ felem_diff(tmp, tmp, z2z2);
+
+ felem_mul(z2z2z2, z2, z2z2);
+ felem_mul(s1, y1, z2z2z2);
+
+ felem_mul(u2, x2, z1z1);
+ felem_mul(z1z1z1, z1, z1z1);
+ felem_mul(s2, y2, z1z1z1);
+ felem_diff(h, u2, u1);
+ x_equal = felem_is_zero_vartime(h);
+ felem_sum(i, h, h);
+ felem_square(i, i);
+ felem_mul(j, h, i);
+ felem_diff(r, s2, s1);
+ y_equal = felem_is_zero_vartime(r);
+ if (x_equal && y_equal) {
+ point_double(x_out, y_out, z_out, x1, y1, z1);
+ return;
+ }
+ felem_sum(r, r, r);
+ felem_mul(v, u1, i);
+
+ felem_mul(z_out, tmp, h);
+ felem_square(rr, r);
+ felem_diff(x_out, rr, j);
+ felem_diff(x_out, x_out, v);
+ felem_diff(x_out, x_out, v);
+
+ felem_diff(tmp, v, x_out);
+ felem_mul(y_out, tmp, r);
+ felem_mul(tmp, s1, j);
+ felem_diff(y_out, y_out, tmp);
+ felem_diff(y_out, y_out, tmp);
+}
+
+/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
+ *
+ * On entry: mask is either 0 or 0xffffffff. */
+static void copy_conditional(felem out, const felem in, limb mask) {
+ int i;
+
+ for (i = 0; i < NLIMBS; i++) {
+ const limb tmp = mask & (in[i] ^ out[i]);
+ out[i] ^= tmp;
+ }
+}
+
+/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
+ * On entry: index < 16, table[0] must be zero. */
+static void select_affine_point(felem out_x, felem out_y, const limb* table,
+ limb index) {
+ limb i, j;
+
+ memset(out_x, 0, sizeof(felem));
+ memset(out_y, 0, sizeof(felem));
+
+ for (i = 1; i < 16; i++) {
+ limb mask = i ^ index;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS; j++, table++) {
+ out_x[j] |= *table & mask;
+ }
+ for (j = 0; j < NLIMBS; j++, table++) {
+ out_y[j] |= *table & mask;
+ }
+ }
+}
+
+/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
+ * table. On entry: index < 16, table[0] must be zero. */
+static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
+ const limb* table, limb index) {
+ limb i, j;
+
+ memset(out_x, 0, sizeof(felem));
+ memset(out_y, 0, sizeof(felem));
+ memset(out_z, 0, sizeof(felem));
+
+ /* The implicit value at index 0 is all zero. We don't need to perform that
+ * iteration of the loop because we already set out_* to zero. */
+ table += 3 * NLIMBS;
+
+ // Hit all entries to obscure cache profiling.
+ for (i = 1; i < 16; i++) {
+ limb mask = i ^ index;
+ mask |= mask >> 2;
+ mask |= mask >> 1;
+ mask &= 1;
+ mask--;
+ for (j = 0; j < NLIMBS; j++, table++) {
+ out_x[j] |= *table & mask;
+ }
+ for (j = 0; j < NLIMBS; j++, table++) {
+ out_y[j] |= *table & mask;
+ }
+ for (j = 0; j < NLIMBS; j++, table++) {
+ out_z[j] |= *table & mask;
+ }
+ }
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
+ * number. Note that the value of scalar must be less than the order of the
+ * group. */
+static void scalar_base_mult(felem nx, felem ny, felem nz,
+ const p256_int* scalar) {
+ int i, j;
+ limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
+ u32 table_offset;
+
+ felem px, py;
+ felem tx, ty, tz;
+
+ memset(nx, 0, sizeof(felem));
+ memset(ny, 0, sizeof(felem));
+ memset(nz, 0, sizeof(felem));
+
+ /* The loop adds bits at positions 0, 64, 128 and 192, followed by
+ * positions 32,96,160 and 224 and does this 32 times. */
+ for (i = 0; i < 32; i++) {
+ if (i) {
+ point_double(nx, ny, nz, nx, ny, nz);
+ }
+ table_offset = 0;
+ for (j = 0; j <= 32; j += 32) {
+ char bit0 = p256_get_bit(scalar, 31 - i + j);
+ char bit1 = p256_get_bit(scalar, 95 - i + j);
+ char bit2 = p256_get_bit(scalar, 159 - i + j);
+ char bit3 = p256_get_bit(scalar, 223 - i + j);
+ limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
+
+ select_affine_point(px, py, kPrecomputed + table_offset, index);
+ table_offset += 30 * NLIMBS;
+
+ /* Since scalar is less than the order of the group, we know that
+ * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle
+ * below. */
+ point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
+ /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero
+ * (a.k.a. the point at infinity). We handle that situation by
+ * copying the point from the table. */
+ copy_conditional(nx, px, n_is_infinity_mask);
+ copy_conditional(ny, py, n_is_infinity_mask);
+ copy_conditional(nz, kOne, n_is_infinity_mask);
+
+ /* Equally, the result is also wrong if the point from the table is
+ * zero, which happens when the index is zero. We handle that by
+ * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */
+ p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+ mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+ copy_conditional(nx, tx, mask);
+ copy_conditional(ny, ty, mask);
+ copy_conditional(nz, tz, mask);
+ /* If p was not zero, then n is now non-zero. */
+ n_is_infinity_mask &= ~p_is_noninfinite_mask;
+ }
+ }
+}
+
+/* point_to_affine converts a Jacobian point to an affine point. If the input
+ * is the point at infinity then it returns (0, 0) in constant time. */
+static void point_to_affine(felem x_out, felem y_out, const felem nx,
+ const felem ny, const felem nz) {
+ felem z_inv, z_inv_sq;
+ felem_inv(z_inv, nz);
+ felem_square(z_inv_sq, z_inv);
+ felem_mul(x_out, nx, z_inv_sq);
+ felem_mul(z_inv, z_inv, z_inv_sq);
+ felem_mul(y_out, ny, z_inv);
+}
+
+/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
+static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
+ const felem y, const p256_int* scalar) {
+ int i;
+ felem px, py, pz, tx, ty, tz;
+ felem precomp[16][3];
+ limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
+
+ /* We precompute 0,1,2,... times {x,y}. */
+ memset(precomp, 0, sizeof(felem) * 3);
+ memcpy(&precomp[1][0], x, sizeof(felem));
+ memcpy(&precomp[1][1], y, sizeof(felem));
+ memcpy(&precomp[1][2], kOne, sizeof(felem));
+
+ for (i = 2; i < 16; i += 2) {
+ point_double(precomp[i][0], precomp[i][1], precomp[i][2],
+ precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);
+
+ point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
+ precomp[i][0], precomp[i][1], precomp[i][2], x, y);
+ }
+
+ memset(nx, 0, sizeof(felem));
+ memset(ny, 0, sizeof(felem));
+ memset(nz, 0, sizeof(felem));
+ n_is_infinity_mask = -1;
+
+ /* We add in a window of four bits each iteration and do this 64 times. */
+ for (i = 0; i < 256; i += 4) {
+ if (i) {
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ point_double(nx, ny, nz, nx, ny, nz);
+ }
+
+ index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
+ (p256_get_bit(scalar, 255 - i - 1) << 2) |
+ (p256_get_bit(scalar, 255 - i - 2) << 1) |
+ p256_get_bit(scalar, 255 - i - 3);
+
+ /* See the comments in scalar_base_mult about handling infinities. */
+ select_jacobian_point(px, py, pz, precomp[0][0], index);
+ point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
+ copy_conditional(nx, px, n_is_infinity_mask);
+ copy_conditional(ny, py, n_is_infinity_mask);
+ copy_conditional(nz, pz, n_is_infinity_mask);
+
+ p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
+ mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
+
+ copy_conditional(nx, tx, mask);
+ copy_conditional(ny, ty, mask);
+ copy_conditional(nz, tz, mask);
+ n_is_infinity_mask &= ~p_is_noninfinite_mask;
+ }
+}
+
+#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p
+
+#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff} // 1 / 2^257 mod p256.p
+
+static const p256_int kR = { kRDigits };
+static const p256_int kRInv = { kRInvDigits };
+
+/* to_montgomery sets out = R*in. */
+static void to_montgomery(felem out, const p256_int* in) {
+ p256_int in_shifted;
+ int i;
+
+ p256_init(&in_shifted);
+ p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
+
+ for (i = 0; i < NLIMBS; i++) {
+ if ((i & 1) == 0) {
+ out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
+ p256_shr(&in_shifted, 29, &in_shifted);
+ } else {
+ out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
+ p256_shr(&in_shifted, 28, &in_shifted);
+ }
+ }
+
+ p256_clear(&in_shifted);
+}
+
+/* from_montgomery sets out=in/R. */
+static void from_montgomery(p256_int* out, const felem in) {
+ p256_int result, tmp;
+ int i, top;
+
+ p256_init(&result);
+ p256_init(&tmp);
+
+ p256_add_d(&tmp, in[NLIMBS - 1], &result);
+ for (i = NLIMBS - 2; i >= 0; i--) {
+ if ((i & 1) == 0) {
+ top = p256_shl(&result, 29, &tmp);
+ } else {
+ top = p256_shl(&result, 28, &tmp);
+ }
+ top |= p256_add_d(&tmp, in[i], &result);
+ }
+
+ p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
+
+ p256_clear(&result);
+ p256_clear(&tmp);
+}
+
+/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
+ * order of the group. */
+void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) {
+ felem x, y, z;
+
+ scalar_base_mult(x, y, z, n);
+
+ {
+ felem x_affine, y_affine;
+
+ point_to_affine(x_affine, y_affine, x, y, z);
+ from_montgomery(out_x, x_affine);
+ from_montgomery(out_y, y_affine);
+ }
+}
+
+/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
+ * n1 and n2 are < the order of the group.
+ *
+ * As indicated by the name, this function operates in variable time. This
+ * is safe because it's used for signature validation which doesn't deal
+ * with secrets. */
+void p256_points_mul_vartime(
+ const p256_int* n1, const p256_int* n2, const p256_int* in_x,
+ const p256_int* in_y, p256_int* out_x, p256_int* out_y) {
+ felem x1, y1, z1, x2, y2, z2, px, py;
+
+ /* If both scalars are zero, then the result is the point at infinity. */
+ if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
+ p256_clear(out_x);
+ p256_clear(out_y);
+ return;
+ }
+
+ to_montgomery(px, in_x);
+ to_montgomery(py, in_y);
+ scalar_base_mult(x1, y1, z1, n1);
+ scalar_mult(x2, y2, z2, px, py, n2);
+
+ if (p256_is_zero(n2) != 0) {
+ /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
+ * {x1,y1,z1}. */
+ } else if (p256_is_zero(n1) != 0) {
+ /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
+ * {x2,y2,z2}. */
+ memcpy(x1, x2, sizeof(x2));
+ memcpy(y1, y2, sizeof(y2));
+ memcpy(z1, z2, sizeof(z2));
+ } else {
+ /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */
+ point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
+ }
+
+ point_to_affine(px, py, x1, y1, z1);
+ from_montgomery(out_x, px);
+ from_montgomery(out_y, py);
+}
diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c
new file mode 100644
index 0000000..f2264b0
--- /dev/null
+++ b/libmincrypt/p256_ecdsa.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "mincrypt/p256_ecdsa.h"
+#include "mincrypt/p256.h"
+
+int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
+ const p256_int* message,
+ const p256_int* r, const p256_int* s) {
+ p256_int u, v;
+
+ // Check public key.
+ if (!p256_is_valid_point(key_x, key_y)) return 0;
+
+ // Check r and s are != 0 % n.
+ p256_mod(&SECP256r1_n, r, &u);
+ p256_mod(&SECP256r1_n, s, &v);
+ if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
+
+ p256_modinv_vartime(&SECP256r1_n, s, &v);
+ p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n
+ p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n
+
+ p256_points_mul_vartime(&u, &v,
+ key_x, key_y,
+ &u, &v);
+
+ p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n
+ return p256_cmp(r, &u) == 0;
+}
+
diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk
index a28ccd8..73ff7d0 100644
--- a/libmincrypt/test/Android.mk
+++ b/libmincrypt/test/Android.mk
@@ -1,10 +1,15 @@
# Copyright 2013 The Android Open Source Project
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+include $(CLEAR_VARS)
LOCAL_MODULE := rsa_test
LOCAL_SRC_FILES := rsa_test.c
LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_EXECUTABLE)
+include $(BUILD_HOST_NATIVE_TEST)
+include $(CLEAR_VARS)
+LOCAL_MODULE := ecdsa_test
+LOCAL_SRC_FILES := ecdsa_test.c
+LOCAL_STATIC_LIBRARIES := libmincrypt
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
new file mode 100644
index 0000000..b5a7b3a
--- /dev/null
+++ b/libmincrypt/test/ecdsa_test.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Google Inc. nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mincrypt/p256.h"
+#include "mincrypt/p256_ecdsa.h"
+#include "mincrypt/sha256.h"
+
+/**
+ * Messages signed using:
+ *
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49
+AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24
+6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g==
+-----END EC PRIVATE KEY-----
+ */
+
+p256_int key_x = {
+ .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu,
+ 0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u}
+};
+p256_int key_y = {
+ .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au,
+ 0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u}
+};
+
+char* message_1 =
+ "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+ "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+ "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+ "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+ "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+ "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+ "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+ "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+ "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+ "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+ "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+ "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+ "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+ "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+ "d5 9d 73 be 12";
+
+char* signature_1 =
+ "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+ "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+ "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51"
+ "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+ "ea 57 7e 88 46 12";
+
+// Same as signature 1, but with leading zeroes.
+char* message_2 =
+ "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+ "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+ "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+ "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+ "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+ "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+ "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+ "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+ "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+ "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+ "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+ "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+ "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+ "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+ "d5 9d 73 be 12";
+
+char* signature_2 =
+ "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+ "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+ "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51"
+ "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+ "ea 57 7e 88 46 12";
+
+// Excessive zeroes on the signature
+char* message_3 =
+ "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
+ "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
+ "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
+ "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
+ "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
+ "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
+ "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
+ "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
+ "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
+ "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
+ "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
+ "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
+ "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
+ "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
+ "d5 9d 73 be 12";
+
+char* signature_3 =
+ "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
+ "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
+ "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51"
+ "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
+ "ea 57 7e 88 46 12";
+
+
+char* good_dsa_signature_1 =
+ "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01";
+p256_int good_dsa_signature_1_r = {
+ .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
+ 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
+};
+p256_int good_dsa_signature_1_s = {
+ .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U,
+ 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
+};
+
+
+char* bad_dsa_signature_1 =
+ "a0 06 02 01 01 02 01 01";
+
+char* bad_dsa_signature_2 =
+ "30 07 02 01 01 02 01 01";
+
+char* bad_dsa_signature_3 =
+ "30 06 82 01 01 02 01 01";
+
+char* bad_dsa_signature_4 =
+ "30 06 02 00 01 02 01 01";
+
+char* bad_dsa_signature_5 =
+ "30 06 02 01 01 82 01 01";
+
+char* bad_dsa_signature_6 =
+ "30 05 02 01 01 02 00";
+
+char* bad_dsa_signature_7 =
+ "30 06 02 01 01 02 00 01";
+
+unsigned char* parsehex(char* str, int* len) {
+ // result can't be longer than input
+ unsigned char* result = malloc(strlen(str));
+
+ unsigned char* p = result;
+ *len = 0;
+
+ while (*str) {
+ int b;
+
+ while (isspace(*str)) str++;
+
+ switch (*str) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ b = (*str - '0') << 4; break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ b = (*str - 'a' + 10) << 4; break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ b = (*str - 'A' + 10) << 4; break;
+ case '\0':
+ return result;
+ default:
+ return NULL;
+ }
+ str++;
+
+ while (isspace(*str)) str++;
+
+ switch (*str) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ b |= *str - '0'; break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ b |= *str - 'a' + 10; break;
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ b |= *str - 'A' + 10; break;
+ default:
+ return NULL;
+ }
+ str++;
+
+ *p++ = b;
+ ++*len;
+ }
+
+ return result;
+}
+
+int main(int arg, char** argv) {
+
+ unsigned char hash_buf[SHA256_DIGEST_SIZE];
+
+ unsigned char* message;
+ int mlen;
+ unsigned char* signature;
+ int slen;
+
+ p256_int hash;
+ p256_int r;
+ p256_int s;
+
+ int success = 1;
+
+#define CHECK_DSA_SIG(sig, good) do {\
+ message = parsehex(sig, &mlen); \
+ int result = dsa_sig_unpack(message, mlen, &r, &s); \
+ printf(#sig ": %s\n", result ? "good" : "bad"); \
+ success = success && !(good ^ result); \
+ free(message); \
+ } while(0)
+#define CHECK_GOOD_DSA_SIG(n) do {\
+ CHECK_DSA_SIG(good_dsa_signature_##n, 1); \
+ int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \
+ P256_NBYTES); \
+ success = success && result; \
+ printf(" R value %s\n", result ? "good" : "bad"); \
+ result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \
+ P256_NBYTES); \
+ success = success && result; \
+ printf(" S value %s\n", result ? "good" : "bad"); \
+ } while (0)
+#define CHECK_BAD_DSA_SIG(n) \
+ CHECK_DSA_SIG(bad_dsa_signature_##n, 0)
+
+ CHECK_GOOD_DSA_SIG(1);
+
+ CHECK_BAD_DSA_SIG(1);
+ CHECK_BAD_DSA_SIG(2);
+ CHECK_BAD_DSA_SIG(3);
+ CHECK_BAD_DSA_SIG(4);
+ CHECK_BAD_DSA_SIG(5);
+ CHECK_BAD_DSA_SIG(6);
+ CHECK_BAD_DSA_SIG(7);
+
+
+#define TEST_MESSAGE(n) do {\
+ message = parsehex(message_##n, &mlen); \
+ SHA256_hash(message, mlen, hash_buf); \
+ p256_from_bin(hash_buf, &hash); \
+ signature = parsehex(signature_##n, &slen); \
+ int result = dsa_sig_unpack(signature, slen, &r, &s); \
+ if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \
+ printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
+ success = success && result; \
+ free(signature); \
+ } while(0)
+
+ TEST_MESSAGE(1);
+ TEST_MESSAGE(2);
+ TEST_MESSAGE(3);
+
+ printf("\n%s\n\n", success ? "PASS" : "FAIL");
+
+ return !success;
+}
diff --git a/libmincrypt/tools/Android.mk b/libmincrypt/tools/Android.mk
index b61234a..3154914 100644
--- a/libmincrypt/tools/Android.mk
+++ b/libmincrypt/tools/Android.mk
@@ -13,9 +13,10 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
+include $(CLEAR_VARS)
LOCAL_MODULE := dumpkey
LOCAL_SRC_FILES := DumpPublicKey.java
LOCAL_JAR_MANIFEST := DumpPublicKey.mf
+LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
index 7189116..3eb1398 100644
--- a/libmincrypt/tools/DumpPublicKey.java
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -16,6 +16,8 @@
package com.android.dumpkey;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.cert.CertificateFactory;
@@ -23,7 +25,10 @@ import java.security.cert.X509Certificate;
import java.security.KeyStore;
import java.security.Key;
import java.security.PublicKey;
+import java.security.Security;
+import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECPoint;
/**
* Command line tool to extract RSA public keys from X.509 certificates
@@ -39,9 +44,8 @@ class DumpPublicKey {
* 3: 2048-bit RSA key with e=3 and SHA-256 hash
* 4: 2048-bit RSA key with e=65537 and SHA-256 hash
* @throws Exception if the key has the wrong size or public exponent
-
*/
- static int check(RSAPublicKey key, boolean useSHA256) throws Exception {
+ static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
BigInteger pubexp = key.getPublicExponent();
BigInteger modulus = key.getModulus();
int version;
@@ -64,12 +68,42 @@ class DumpPublicKey {
}
/**
+ * @param key to perform sanity checks on
+ * @return version number of key. Supported versions are:
+ * 5: 256-bit EC key with curve NIST P-256
+ * @throws Exception if the key has the wrong size or public exponent
+ */
+ static int checkEC(ECPublicKey key) throws Exception {
+ if (key.getParams().getCurve().getField().getFieldSize() != 256) {
+ throw new Exception("Curve must be NIST P-256");
+ }
+
+ return 5;
+ }
+
+ /**
+ * Perform sanity check on public key.
+ */
+ static int check(PublicKey key, boolean useSHA256) throws Exception {
+ if (key instanceof RSAPublicKey) {
+ return checkRSA((RSAPublicKey) key, useSHA256);
+ } else if (key instanceof ECPublicKey) {
+ if (!useSHA256) {
+ throw new Exception("Must use SHA-256 with EC keys!");
+ }
+ return checkEC((ECPublicKey) key);
+ } else {
+ throw new Exception("Unsupported key class: " + key.getClass().getName());
+ }
+ }
+
+ /**
* @param key to output
* @return a String representing this public key. If the key is a
* version 1 key, the string will be a C initializer; this is
* not true for newer key versions.
*/
- static String print(RSAPublicKey key, boolean useSHA256) throws Exception {
+ static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
int version = check(key, useSHA256);
BigInteger N = key.getModulus();
@@ -128,11 +162,78 @@ class DumpPublicKey {
return result.toString();
}
+ /**
+ * @param key to output
+ * @return a String representing this public key. If the key is a
+ * version 1 key, the string will be a C initializer; this is
+ * not true for newer key versions.
+ */
+ static String printEC(ECPublicKey key) throws Exception {
+ int version = checkEC(key);
+
+ StringBuilder result = new StringBuilder();
+
+ result.append("v");
+ result.append(Integer.toString(version));
+ result.append(" ");
+
+ BigInteger X = key.getW().getAffineX();
+ BigInteger Y = key.getW().getAffineY();
+ int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate
+
+ result.append("{");
+ result.append(nbytes);
+
+ BigInteger B = BigInteger.valueOf(0x100L); // 2^8
+
+ // Write out Y coordinate as array of characters.
+ result.append(",{");
+ for (int i = 0; i < nbytes; ++i) {
+ long n = X.mod(B).longValue();
+ result.append(n);
+
+ if (i != nbytes - 1) {
+ result.append(",");
+ }
+
+ X = X.divide(B);
+ }
+ result.append("}");
+
+ // Write out Y coordinate as array of characters.
+ result.append(",{");
+ for (int i = 0; i < nbytes; ++i) {
+ long n = Y.mod(B).longValue();
+ result.append(n);
+
+ if (i != nbytes - 1) {
+ result.append(",");
+ }
+
+ Y = Y.divide(B);
+ }
+ result.append("}");
+
+ result.append("}");
+ return result.toString();
+ }
+
+ static String print(PublicKey key, boolean useSHA256) throws Exception {
+ if (key instanceof RSAPublicKey) {
+ return printRSA((RSAPublicKey) key, useSHA256);
+ } else if (key instanceof ECPublicKey) {
+ return printEC((ECPublicKey) key);
+ } else {
+ throw new Exception("Unsupported key class: " + key.getClass().getName());
+ }
+ }
+
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("Usage: DumpPublicKey certfile ... > source.c");
System.exit(1);
}
+ Security.addProvider(new BouncyCastleProvider());
try {
for (int i = 0; i < args.length; i++) {
FileInputStream input = new FileInputStream(args[i]);
@@ -147,7 +248,7 @@ class DumpPublicKey {
// anyway. Continue to do so for backwards
// compatibility.
useSHA256 = false;
- } else if ("SHA256withRSA".equals(sigAlg)) {
+ } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
useSHA256 = true;
} else {
System.err.println(args[i] + ": unsupported signature algorithm \"" +
@@ -155,7 +256,7 @@ class DumpPublicKey {
System.exit(1);
}
- RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
+ PublicKey key = cert.getPublicKey();
check(key, useSHA256);
System.out.print(print(key, useSHA256));
System.out.println(i < args.length - 1 ? "," : "");
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
index dfb217b..3e72b57 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -370,7 +370,7 @@ int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb,
}
new_bb = malloc(sizeof(struct backed_block));
- if (bb == NULL) {
+ if (new_bb == NULL) {
return -ENOMEM;
}
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 5014e4a..a28b0a5 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; })
@@ -731,10 +722,12 @@ int write_fd_chunk(struct output_file *out, unsigned int len,
}
pos = lseek64(fd, offset, SEEK_SET);
if (pos < 0) {
+ free(data);
return -errno;
}
ret = read_all(fd, data, len);
if (ret < 0) {
+ free(data);
return ret;
}
ptr = data;
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 @@ typedef struct boot_img_hdr boot_img_hdr;
#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 @@ struct boot_img_hdr
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 @@ int main(int argc, char **argv)
unsigned ramdisk_offset = 0x01000000;
unsigned second_offset = 0x00f00000;
unsigned tags_offset = 0x00000100;
+ size_t cmdlen;
argc--;
argv++;
@@ -192,11 +193,19 @@ int main(int argc, char **argv)
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 a0a9813..400c09e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -17,6 +17,9 @@ on early-init
# 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
@@ -216,6 +219,10 @@ on post-fs-data
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
@@ -253,6 +260,9 @@ on post-fs-data
# 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.
@@ -347,7 +357,6 @@ on boot
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
@@ -417,10 +426,6 @@ service healthd-charger /sbin/healthd -n
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