Merge "rootdir: goldfish: mount debugfs on boot time"
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 3a8e8fd..604c461 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -131,6 +131,16 @@
 #define VENDOR_ID_KOBO          0x2237
 // Teleepoch's USB Vendor ID
 #define VENDOR_ID_TELEEPOCH     0x2340
+// AnyDATA's USB Vendor ID
+#define VENDOR_ID_ANYDATA       0x16D5
+// Harris's USB Vendor ID
+#define VENDOR_ID_HARRIS        0x19A5
+// OPPO's USB Vendor ID
+#define VENDOR_ID_OPPO          0x22D9
+// Xiaomi's USB Vendor ID
+#define VENDOR_ID_XIAOMI        0x2717
+// BYD's USB Vendor ID
+#define VENDOR_ID_BYD           0x19D1
 
 
 /** built-in vendor list */
@@ -183,6 +193,11 @@
     VENDOR_ID_YULONG_COOLPAD,
     VENDOR_ID_KOBO,
     VENDOR_ID_TELEEPOCH,
+    VENDOR_ID_ANYDATA,
+    VENDOR_ID_HARRIS,
+    VENDOR_ID_OPPO,
+    VENDOR_ID_XIAOMI,
+    VENDOR_ID_BYD,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 134fe80..630d980 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -101,6 +101,21 @@
     return (int) result;
 }
 
+__attribute__((noinline)) int crash3(int a) {
+   *((int*) 0xdead) = a;
+   return a*4;
+}
+
+__attribute__((noinline)) int crash2(int a) {
+   a = crash3(a) + 2;
+   return a*3;
+}
+
+__attribute__((noinline)) int crash(int a) {
+   a = crash2(a) + 1;
+   return a*2;
+}
+
 int do_action(const char* arg)
 {
     if(!strncmp(arg, "thread-", strlen("thread-"))) {
@@ -111,6 +126,7 @@
     if(!strcmp(arg,"nostack")) crashnostack();
     if(!strcmp(arg,"ctest")) return ctest();
     if(!strcmp(arg,"exit")) exit(1);
+    if(!strcmp(arg,"crash")) return crash(42);
     if(!strcmp(arg,"abort")) maybeabort();
 
     pthread_t thr;
diff --git a/init/devices.c b/init/devices.c
index b07a1a6..e25034c 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -83,7 +83,8 @@
 
 struct platform_node {
     char *name;
-    int name_len;
+    char *path;
+    int path_len;
     struct listnode list;
 };
 
@@ -215,61 +216,69 @@
     }
 }
 
-static void add_platform_device(const char *name)
+static void add_platform_device(const char *path)
 {
-    int name_len = strlen(name);
+    int path_len = strlen(path);
     struct listnode *node;
     struct platform_node *bus;
+    const char *name = path;
+
+    if (!strncmp(path, "/devices/", 9)) {
+        name += 9;
+        if (!strncmp(name, "platform/", 9))
+            name += 9;
+    }
 
     list_for_each_reverse(node, &platform_names) {
         bus = node_to_item(node, struct platform_node, list);
-        if ((bus->name_len < name_len) &&
-                (name[bus->name_len] == '/') &&
-                !strncmp(name, bus->name, bus->name_len))
+        if ((bus->path_len < path_len) &&
+                (path[bus->path_len] == '/') &&
+                !strncmp(path, bus->path, bus->path_len))
             /* subdevice of an existing platform, ignore it */
             return;
     }
 
-    INFO("adding platform device %s\n", name);
+    INFO("adding platform device %s (%s)\n", name, path);
 
     bus = calloc(1, sizeof(struct platform_node));
-    bus->name = strdup(name);
-    bus->name_len = name_len;
+    bus->path = strdup(path);
+    bus->path_len = path_len;
+    bus->name = bus->path + (name - path);
     list_add_tail(&platform_names, &bus->list);
 }
 
 /*
- * given a name that may start with a platform device, find the length of the
+ * given a path that may start with a platform device, find the length of the
  * platform device prefix.  If it doesn't start with a platform device, return
  * 0.
  */
-static const char *find_platform_device(const char *name)
+static struct platform_node *find_platform_device(const char *path)
 {
-    int name_len = strlen(name);
+    int path_len = strlen(path);
     struct listnode *node;
     struct platform_node *bus;
 
     list_for_each_reverse(node, &platform_names) {
         bus = node_to_item(node, struct platform_node, list);
-        if ((bus->name_len < name_len) &&
-                (name[bus->name_len] == '/') &&
-                !strncmp(name, bus->name, bus->name_len))
-            return bus->name;
+        if ((bus->path_len < path_len) &&
+                (path[bus->path_len] == '/') &&
+                !strncmp(path, bus->path, bus->path_len))
+            return bus;
     }
 
     return NULL;
 }
 
-static void remove_platform_device(const char *name)
+static void remove_platform_device(const char *path)
 {
     struct listnode *node;
     struct platform_node *bus;
 
     list_for_each_reverse(node, &platform_names) {
         bus = node_to_item(node, struct platform_node, list);
-        if (!strcmp(name, bus->name)) {
-            INFO("removing platform device %s\n", name);
-            free(bus->name);
+        if (!strcmp(path, bus->path)) {
+            INFO("removing platform device %s\n", bus->name);
+            free(bus->path);
             list_remove(node);
             free(bus);
             return;
@@ -355,8 +364,10 @@
     char **links;
     int link_num = 0;
     int width;
+    struct platform_node *pdev;
 
-    if (strncmp(uevent->path, "/devices/platform/", 18))
+    pdev = find_platform_device(uevent->path);
+    if (!pdev)
         return NULL;
 
     links = malloc(sizeof(char *) * 2);
@@ -365,7 +376,7 @@
     memset(links, 0, sizeof(char *) * 2);
 
     /* skip "/devices/platform/<driver>" */
-    parent = strchr(uevent->path + 18, '/');
+    parent = strchr(uevent->path + pdev->path_len, '/');
     if (!*parent)
         goto err;
 
@@ -402,7 +413,7 @@
 static char **parse_platform_block_device(struct uevent *uevent)
 {
     const char *device;
-    const char *path;
+    struct platform_node *pdev;
     char *slash;
     int width;
     char buf[256];
@@ -414,18 +425,16 @@
     unsigned int size;
     struct stat info;
 
+    pdev = find_platform_device(uevent->path);
+    if (!pdev)
+        return NULL;
+    device = pdev->name;
+
     char **links = malloc(sizeof(char *) * 4);
     if (!links)
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
 
-    /* Drop "/devices/platform/" */
-    path = uevent->path;
-    device = path + 18;
-    device = find_platform_device(device);
-    if (!device)
-        goto err;
-
     INFO("found platform device %s\n", device);
 
     snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
@@ -447,17 +456,13 @@
             links[link_num] = NULL;
     }
 
-    slash = strrchr(path, '/');
+    slash = strrchr(uevent->path, '/');
     if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
         link_num++;
     else
         links[link_num] = NULL;
 
     return links;
-
-err:
-    free(links);
-    return NULL;
 }
 
 static void handle_device(const char *action, const char *devpath,
@@ -490,12 +495,12 @@
 
 static void handle_platform_device_event(struct uevent *uevent)
 {
-    const char *name = uevent->path + 18; /* length of /devices/platform/ */
+    const char *path = uevent->path;
 
     if (!strcmp(uevent->action, "add"))
-        add_platform_device(name);
+        add_platform_device(path);
     else if (!strcmp(uevent->action, "remove"))
-        remove_platform_device(name);
+        remove_platform_device(path);
 }
 
 static const char *parse_device_name(struct uevent *uevent, unsigned int len)
@@ -533,7 +538,7 @@
     snprintf(devpath, sizeof(devpath), "%s%s", base, name);
     make_dir(base, 0755);
 
-    if (!strncmp(uevent->path, "/devices/platform/", 18))
+    if (!strncmp(uevent->path, "/devices/", 9))
         links = parse_platform_block_device(uevent);
 
     handle_device(uevent->action, devpath, uevent->path, 1,
diff --git a/init/init.c b/init/init.c
index 48d8559..b28b0ab 100755
--- a/init/init.c
+++ b/init/init.c
@@ -31,7 +31,6 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/personality.h>
 
 #include <selinux/selinux.h>
 #include <selinux/label.h>
@@ -242,21 +241,6 @@
         int fd, sz;
 
         umask(077);
-#ifdef __arm__
-        /*
-         * b/7188322 - Temporarily revert to the compat memory layout
-         * to avoid breaking third party apps.
-         *
-         * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
-         *
-         * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
-         * changes the kernel mapping from bottom up to top-down.
-         * This breaks some programs which improperly embed
-         * an out of date copy of Android's linker.
-         */
-        int current = personality(0xffffFFFF);
-        personality(current | ADDR_COMPAT_LAYOUT);
-#endif
         if (properties_inited()) {
             get_property_workspace(&fd, &sz);
             sprintf(tmp, "%d,%d", dup(fd), sz);
@@ -761,7 +745,7 @@
 #endif
 
 static const struct selinux_opt seopts_prop[] = {
-        { SELABEL_OPT_PATH, "/data/system/property_contexts" },
+        { SELABEL_OPT_PATH, "/data/security/property_contexts" },
         { SELABEL_OPT_PATH, "/property_contexts" },
         { 0, NULL }
 };
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
old mode 100644
new mode 100755
index fb79a0c..29159ed
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -23,13 +23,16 @@
 
 #include "../backtrace-arch.h"
 #include "../backtrace-helper.h"
+#include "../ptrace-arch.h"
 #include <corkscrew/ptrace.h>
+#include "dwarf.h"
 
 #include <stdlib.h>
 #include <signal.h>
 #include <stdbool.h>
 #include <limits.h>
 #include <errno.h>
+#include <string.h>
 #include <sys/ptrace.h>
 #include <cutils/log.h>
 
@@ -82,43 +85,731 @@
 
 /* Unwind state. */
 typedef struct {
-    uint32_t ebp;
-    uint32_t eip;
-    uint32_t esp;
+    uint32_t reg[DWARF_REGISTERS];
 } unwind_state_t;
 
+typedef struct {
+    backtrace_frame_t* backtrace;
+    size_t ignore_depth;
+    size_t max_depth;
+    size_t ignored_frames;
+    size_t returned_frames;
+    memory_t memory;
+} backtrace_state_t;
+
 uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
-    // TODO: Implement for x86.
-    return pc;
+    /* TODO: x86 instructions are 1-16 bytes, to define exact size of previous instruction
+       we have to disassemble from the function entry point up to pc.
+       Returning pc-1 is probably enough for now, the only drawback is that
+       it points somewhere between the first byte of instruction we are looking for and
+       the first byte of the next instruction. */
+
+    return pc-1;
+    /* TODO: We should adjust that for the signal frames and return pc for them instead of pc-1.
+       To recognize signal frames we should read cie_info property. */
 }
 
-static ssize_t unwind_backtrace_common(const memory_t* memory,
-        const map_info_t* map_info_list __attribute__((unused)),
-        unwind_state_t* state, backtrace_frame_t* backtrace,
-        size_t ignore_depth, size_t max_depth) {
-    size_t ignored_frames = 0;
-    size_t returned_frames = 0;
+/* Read byte through 4 byte cache. Usually we read byte by byte and updating cursor. */
+static bool try_get_byte(const memory_t* memory, uintptr_t ptr, uint8_t* out_value, uint32_t* cursor) {
+    static uintptr_t lastptr;
+    static uint32_t buf;
 
-    for (size_t index = 0; state->ebp && returned_frames < max_depth; index++) {
-        backtrace_frame_t* frame = add_backtrace_entry(
-                index ? rewind_pc_arch(memory, state->eip) : state->eip,
-                backtrace, ignore_depth, max_depth,
-                &ignored_frames, &returned_frames);
-        uint32_t next_esp = state->ebp + 8;
-        if (frame) {
-            frame->stack_top = state->esp;
-            if (state->esp < next_esp) {
-                frame->stack_size = next_esp - state->esp;
-            }
+    ptr += *cursor;
+
+    if (ptr < lastptr || lastptr + 3 < ptr) {
+        lastptr = (ptr >> 2) << 2;
+        if (!try_get_word(memory, lastptr, &buf)) {
+            return false;
         }
-        state->esp = next_esp;
-        if (!try_get_word(memory, state->ebp + 4, &state->eip)
-                || !try_get_word(memory, state->ebp, &state->ebp)
-                || !state->eip) {
+    }
+    *out_value = (uint8_t)((buf >> ((ptr & 3) * 8)) & 0xff);
+    ++*cursor;
+    return true;
+}
+
+/* Getting X bytes. 4 is maximum for now. */
+static bool try_get_xbytes(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t bytes, uint32_t* cursor) {
+    uint32_t data = 0;
+    if (bytes > 4) {
+        ALOGE("can't read more than 4 bytes, trying to read %d", bytes);
+        return false;
+    }
+    for (int i = 0; i < bytes; i++) {
+        uint8_t buf;
+        if (!try_get_byte(memory, ptr, &buf, cursor)) {
+            return false;
+        }
+        data |= (uint32_t)buf << (i * 8);
+    }
+    *out_value = data;
+    return true;
+}
+
+/* Reads signed/unsigned LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_leb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor, bool sign_extend) {
+    uint8_t buf = 0;
+    uint32_t val = 0;
+    uint8_t c = 0;
+    do {
+       if (!try_get_byte(memory, ptr, &buf, cursor)) {
+           return false;
+       }
+       val |= ((uint32_t)buf & 0x7f) << (c * 7);
+       c++;
+    } while (buf & 0x80 && (c * 7) <= 32);
+    if (c * 7 > 32) {
+       ALOGE("%s: data exceeds expected 4 bytes maximum", __FUNCTION__);
+       return false;
+    }
+    if (sign_extend) {
+        if (buf & 0x40) {
+            val |= ((uint32_t)-1 << (c * 7));
+        }
+    }
+    *out_value = val;
+    return true;
+}
+
+/* Reads signed LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_sleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
+  return try_get_leb128(memory, ptr, out_value, cursor, true);
+}
+
+/* Reads unsigned LEB128 encoded data. From 1 to 4 bytes. */
+static bool try_get_uleb128(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint32_t* cursor) {
+  return try_get_leb128(memory, ptr, out_value, cursor, false);
+}
+
+/* Getting data encoded by dwarf encodings. */
+static bool read_dwarf(const memory_t* memory, uintptr_t ptr, uint32_t* out_value, uint8_t encoding, uint32_t* cursor) {
+    uint32_t data = 0;
+    bool issigned = true;
+    uintptr_t addr = ptr + *cursor;
+    /* Lower 4 bits is data type/size */
+    /* TODO: add more encodings if it becomes necessary */
+    switch (encoding & 0xf) {
+        case DW_EH_PE_absptr:
+            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
+                return false;
+            }
+            *out_value = data;
+            return true;
+        case DW_EH_PE_udata4:
+            issigned = false;
+        case DW_EH_PE_sdata4:
+            if (!try_get_xbytes(memory, ptr, &data, 4, cursor)) {
+                return false;
+            }
             break;
+        default:
+            ALOGE("unrecognized dwarf lower part encoding: 0x%x", encoding);
+            return false;
+    }
+    /* Higher 4 bits is modifier */
+    /* TODO: add more encodings if it becomes necessary */
+    switch (encoding & 0xf0) {
+        case 0:
+            *out_value = data;
+            break;
+        case DW_EH_PE_pcrel:
+            if (issigned) {
+                *out_value = addr + (int32_t)data;
+            } else {
+                *out_value = addr + data;
+            }
+            break;
+        /* Assuming ptr is correct base to calculate datarel */
+        case DW_EH_PE_datarel:
+            if (issigned) {
+                *out_value = ptr + (int32_t)data;
+            } else {
+                *out_value = ptr + data;
+            }
+            break;
+        default:
+            ALOGE("unrecognized dwarf higher part encoding: 0x%x", encoding);
+            return false;
+    }
+    return true;
+}
+
+/* Having PC find corresponding FDE by reading .eh_frame_hdr section data. */
+static uintptr_t find_fde(const memory_t* memory,
+                          const map_info_t* map_info_list, uintptr_t pc) {
+    if (!pc) {
+        ALOGV("find_fde: pc is zero, no eh_frame");
+        return 0;
+    }
+    const map_info_t* mi = find_map_info(map_info_list, pc);
+    if (!mi) {
+        ALOGV("find_fde: no map info for pc:0x%x", pc);
+        return 0;
+    }
+    const map_info_data_t* midata = mi->data;
+    if (!midata) {
+        ALOGV("find_fde: no eh_frame_hdr for map: start=0x%x, end=0x%x", mi->start, mi->end);
+        return 0;
+    }
+
+    eh_frame_hdr_info_t eh_hdr_info;
+    memset(&eh_hdr_info, 0, sizeof(eh_frame_hdr_info_t));
+
+    /* Getting the first word of eh_frame_hdr:
+        1st byte is version;
+        2nd byte is encoding of pointer to eh_frames;
+        3rd byte is encoding of count of FDEs in lookup table;
+        4th byte is encoding of lookup table entries.
+    */
+    uintptr_t eh_frame_hdr = midata->eh_frame_hdr;
+    uint32_t c = 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.version, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_count_enc, &c)) return 0;
+    if (!try_get_byte(memory, eh_frame_hdr, &eh_hdr_info.fde_table_enc, &c)) return 0;
+
+    /* TODO: 3rd byte can be DW_EH_PE_omit, that means no lookup table available and we should
+       try to parse eh_frame instead. Not sure how often it may occur, skipping now.
+    */
+    if (eh_hdr_info.version != 1) {
+        ALOGV("find_fde: eh_frame_hdr version %d is not supported", eh_hdr_info.version);
+        return 0;
+    }
+    /* Getting the data:
+        2nd word is eh_frame pointer (normally not used, because lookup table has all we need);
+        3rd word is count of FDEs in the lookup table;
+        starting from 4 word there is FDE lookup table (pairs of PC and FDE pointer) sorted by PC;
+    */
+    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.eh_frame_ptr, eh_hdr_info.eh_frame_ptr_enc, &c)) return 0;
+    if (!read_dwarf(memory, eh_frame_hdr, &eh_hdr_info.fde_count, eh_hdr_info.fde_count_enc, &c)) return 0;
+    ALOGV("find_fde: found %d FDEs", eh_hdr_info.fde_count);
+
+    int32_t low = 0;
+    int32_t high = eh_hdr_info.fde_count;
+    uintptr_t start = 0;
+    uintptr_t fde = 0;
+    /* eh_frame_hdr + c points to lookup table at this point. */
+    while (low <= high) {
+        uint32_t mid = (high + low)/2;
+        uint32_t entry = c + mid * 8;
+        if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &entry)) return 0;
+        if (pc <= start) {
+            high = mid - 1;
+        } else {
+            low = mid + 1;
+        }
+    }
+    /* Value found is at high. */
+    if (high < 0) {
+        ALOGV("find_fde: pc %x is out of FDE bounds: %x", pc, start);
+        return 0;
+    }
+    c += high * 8;
+    if (!read_dwarf(memory, eh_frame_hdr, &start, eh_hdr_info.fde_table_enc, &c)) return 0;
+    if (!read_dwarf(memory, eh_frame_hdr, &fde, eh_hdr_info.fde_table_enc, &c)) return 0;
+    ALOGV("pc 0x%x, ENTRY %d: start=0x%x, fde=0x%x", pc, high, start, fde);
+    return fde;
+}
+
+/* Execute single dwarf instruction and update dwarf state accordingly. */
+static bool execute_dwarf(const memory_t* memory, uintptr_t ptr, cie_info_t* cie_info,
+                          dwarf_state_t* dstate, uint32_t* cursor,
+                          dwarf_state_t* stack, uint8_t* stack_ptr) {
+    uint8_t inst;
+    uint8_t op = 0;
+
+    if (!try_get_byte(memory, ptr, &inst, cursor)) {
+        return false;
+    }
+    ALOGV("DW_CFA inst: 0x%x", inst);
+
+    /* For some instructions upper 2 bits is opcode and lower 6 bits is operand. See dwarf-2.0 7.23. */
+    if (inst & 0xc0) {
+        op = inst & 0x3f;
+        inst &= 0xc0;
+    }
+
+    switch ((dwarf_CFA)inst) {
+        uint32_t reg = 0;
+        uint32_t offset = 0;
+        case DW_CFA_advance_loc:
+            dstate->loc += op * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc: %d to 0x%x", op, dstate->loc);
+            break;
+        case DW_CFA_offset:
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            dstate->regs[op].rule = 'o';
+            dstate->regs[op].value = offset * cie_info->data_align;
+            ALOGV("DW_CFA_offset: r%d = o(%d)", op, dstate->regs[op].value);
+            break;
+        case DW_CFA_restore:
+            dstate->regs[op].rule = stack->regs[op].rule;
+            dstate->regs[op].value = stack->regs[op].value;
+            ALOGV("DW_CFA_restore: r%d = %c(%d)", op, dstate->regs[op].rule, dstate->regs[op].value);
+            break;
+        case DW_CFA_nop:
+            break;
+        case DW_CFA_set_loc: // probably we don't have it on x86.
+            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
+            if (offset < dstate->loc) {
+                ALOGE("DW_CFA_set_loc: attempt to move location backward");
+                return false;
+            }
+            dstate->loc = offset * cie_info->code_align;
+            ALOGV("DW_CFA_set_loc: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc1:
+            if (!try_get_byte(memory, ptr, (uint8_t*)&offset, cursor)) return false;
+            dstate->loc += (uint8_t)offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc1: %d to 0x%x", (uint8_t)offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc2:
+            if (!try_get_xbytes(memory, ptr, &offset, 2, cursor)) return false;
+            dstate->loc += (uint16_t)offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc2: %d to 0x%x", (uint16_t)offset * cie_info->code_align, dstate->loc);
+            break;
+        case DW_CFA_advance_loc4:
+            if (!try_get_xbytes(memory, ptr, &offset, 4, cursor)) return false;
+            dstate->loc += offset * cie_info->code_align;
+            ALOGV("DW_CFA_advance_loc4: %d to 0x%x", offset * cie_info->code_align, dstate->loc);
+            break;
+        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) {
+                ALOGE("DW_CFA_offset_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 'o';
+            dstate->regs[reg].value = offset * cie_info->data_align;
+            ALOGV("DW_CFA_offset_extended: r%d = o(%d)", reg, dstate->regs[reg].value);
+            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) {
+                ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            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) {
+                ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            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) {
+                ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
+                return false;
+            }
+            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) {
+                ALOGE("DW_CFA_register: r%d or r%d exceeds supported number of registers (%d)", reg, offset, DWARF_REGISTERS);
+                return false;
+            }
+            dstate->regs[reg].rule = 'r';
+            dstate->regs[reg].value = offset;
+            ALOGV("DW_CFA_register: r%d = r(%d)", reg, dstate->regs[reg].value);
+            break;
+        case DW_CFA_remember_state:
+            if (*stack_ptr == DWARF_STATES_STACK) {
+                ALOGE("DW_CFA_remember_state: states stack overflow %d", *stack_ptr);
+                return false;
+            }
+            stack[(*stack_ptr)++] = *dstate;
+            ALOGV("DW_CFA_remember_state: stacktop moves to %d", *stack_ptr);
+            break;
+        case DW_CFA_restore_state:
+            /* We have CIE state saved at 0 position. It's not supposed to be taken
+               by DW_CFA_restore_state. */
+            if (*stack_ptr == 1) {
+                ALOGE("DW_CFA_restore_state: states stack is empty");
+                return false;
+            }
+            /* Don't touch location on restore. */
+            uintptr_t saveloc = dstate->loc;
+            *dstate = stack[--*stack_ptr];
+            dstate->loc = saveloc;
+            ALOGV("DW_CFA_restore_state: stacktop moves to %d", *stack_ptr);
+            break;
+        case DW_CFA_def_cfa:
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) return false;
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
+            dstate->cfa_reg = reg;
+            dstate->cfa_off = offset;
+            ALOGV("DW_CFA_def_cfa: %x(r%d)", offset, reg);
+            break;
+        case DW_CFA_def_cfa_register:
+            if (!try_get_uleb128(memory, ptr, &reg, cursor)) {
+                return false;
+            }
+            dstate->cfa_reg = reg;
+            ALOGV("DW_CFA_def_cfa_register: r%d", reg);
+            break;
+        case DW_CFA_def_cfa_offset:
+            if (!try_get_uleb128(memory, ptr, &offset, cursor)) {
+                return false;
+            }
+            dstate->cfa_off = offset;
+            ALOGV("DW_CFA_def_cfa_offset: %x", offset);
+            break;
+        default:
+            ALOGE("unrecognized DW_CFA_* instruction: 0x%x", inst);
+            return false;
+    }
+    return true;
+}
+
+/* Restoring particular register value based on dwarf state. */
+static bool get_old_register_value(const memory_t* memory, uint32_t cfa,
+                                   dwarf_state_t* dstate, uint8_t reg,
+                                   unwind_state_t* state, unwind_state_t* newstate) {
+    uint32_t addr;
+    switch (dstate->regs[reg].rule) {
+        case 0:
+            /* We don't have dstate updated for this register, so assuming value kept the same.
+               Normally we should look into state and return current value as the old one
+               but we don't have all registers in state to handle this properly */
+            ALOGV("get_old_register_value: value of r%d is the same", reg);
+            // for ESP if it's not updated by dwarf rule we assume it's equal to CFA
+            if (reg == DWARF_ESP) {
+                ALOGV("get_old_register_value: adjusting esp to CFA: 0x%x", cfa);
+                newstate->reg[reg] = cfa;
+            } else {
+                newstate->reg[reg] = state->reg[reg];
+            }
+            break;
+        case 'o':
+            addr = cfa + (int32_t)dstate->regs[reg].value;
+            if (!try_get_word(memory, addr, &newstate->reg[reg])) {
+                ALOGE("get_old_register_value: can't read from 0x%x", addr);
+                return false;
+            }
+            ALOGV("get_old_register_value: r%d at 0x%x is 0x%x", reg, addr, newstate->reg[reg]);
+            break;
+        case 'r':
+            /* We don't have all registers in state so don't even try to look at 'r' */
+            ALOGE("get_old_register_value: register lookup not implemented yet");
+            break;
+        default:
+            ALOGE("get_old_register_value: unexpected rule:%c value:%d for register %d",
+                   dstate->regs[reg].rule, (int32_t)dstate->regs[reg].value, reg);
+            return false;
+    }
+    return true;
+}
+
+/* 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) {
+    unwind_state_t newstate;
+    /* We can restore more registers here if we need them. Meanwile doing minimal work here. */
+    /* Getting CFA. */
+    uintptr_t cfa = 0;
+    if (dstate->cfa_reg == DWARF_ESP) {
+        cfa = state->reg[DWARF_ESP] + dstate->cfa_off;
+    } else if (dstate->cfa_reg == DWARF_EBP) {
+        cfa = state->reg[DWARF_EBP] + dstate->cfa_off;
+    } else {
+        ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
+        return false;
+    }
+    ALOGV("update_state: new CFA: 0x%x", cfa);
+    /* Getting EIP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_EIP, state, &newstate)) return false;
+    /* Getting EBP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_EBP, state, &newstate)) return false;
+    /* Getting ESP. */
+    if (!get_old_register_value(memory, cfa, dstate, DWARF_ESP, state, &newstate)) return false;
+
+    ALOGV("update_state: IP:  0x%x; restore IP:  0x%x", state->reg[DWARF_EIP], newstate.reg[DWARF_EIP]);
+    ALOGV("update_state: EBP: 0x%x; restore EBP: 0x%x", state->reg[DWARF_EBP], newstate.reg[DWARF_EBP]);
+    ALOGV("update_state: ESP: 0x%x; restore ESP: 0x%x", state->reg[DWARF_ESP], newstate.reg[DWARF_ESP]);
+    *state = newstate;
+    return true;
+}
+
+/* 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;
+    uint32_t cie_length = 0;
+    uintptr_t cie = 0;
+    uintptr_t cie_offset = 0;
+    cie_info_t cie_i;
+    cie_info_t* cie_info = &cie_i;
+    fde_info_t fde_i;
+    fde_info_t* fde_info = &fde_i;
+    dwarf_state_t dwarf_state;
+    dwarf_state_t* dstate = &dwarf_state;
+    dwarf_state_t stack[DWARF_STATES_STACK];
+    uint8_t stack_ptr = 0;
+
+    memset(dstate, 0, sizeof(dwarf_state_t));
+    memset(cie_info, 0, sizeof(cie_info_t));
+    memset(fde_info, 0, sizeof(fde_info_t));
+
+    /* Read common CIE or FDE area:
+        1st word is length;
+        2nd word is ID: 0 for CIE, CIE pointer for FDE.
+    */
+    if (!try_get_word(memory, fde, &fde_length)) {
+        return false;
+    }
+    if ((int32_t)fde_length == -1) {
+        ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
+        return false;
+    }
+    if (!try_get_word(memory, fde + 4, &cie_offset)) {
+        return false;
+    }
+    if (cie_offset == 0) {
+        /* This is CIE. We shouldn't be here normally. */
+        cie = fde;
+        cie_length = fde_length;
+    } else {
+        /* Find CIE. */
+        /* Positive cie_offset goes backward from current field. */
+        cie = fde + 4 - cie_offset;
+        if (!try_get_word(memory, cie, &cie_length)) {
+           return false;
+        }
+        if ((int32_t)cie_length == -1) {
+           ALOGV("execute_fde: 64-bit dwarf detected, not implemented yet");
+           return false;
+        }
+        if (!try_get_word(memory, cie + 4, &cie_offset)) {
+           return false;
+        }
+        if (cie_offset != 0) {
+           ALOGV("execute_fde: can't find CIE");
+           return false;
+        }
+    }
+    ALOGV("execute_fde: FDE length: %d", fde_length);
+    ALOGV("execute_fde: CIE pointer: %x", cie);
+    ALOGV("execute_fde: CIE length: %d", cie_length);
+
+    /* Read CIE:
+       Augmentation independent:
+        1st byte is version;
+        next x bytes is /0 terminated augmentation string;
+        next x bytes is unsigned LEB128 encoded code alignment factor;
+        next x bytes is signed LEB128 encoded data alignment factor;
+        next 1 (CIE version 1) or x (CIE version 3 unsigned LEB128) bytes is return register column;
+       Augmentation dependent:
+        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
+        if 'L' next 1 byte is LSDA encoding;
+        if 'R' next 1 byte is FDE encoding;
+        if 'S' CIE represents signal handler stack frame;
+        if 'P' next 1 byte is personality encoding folowed by personality function pointer;
+       Next x bytes is CIE program.
+    */
+
+    uint32_t c = 8;
+    if (!try_get_byte(memory, cie, &cie_info->version, &c)) {
+       return false;
+    }
+    ALOGV("execute_fde: CIE version: %d", cie_info->version);
+    uint8_t ch;
+    do {
+        if (!try_get_byte(memory, cie, &ch, &c)) {
+           return false;
+        }
+        switch (ch) {
+           case '\0': break;
+           case 'z': cie_info->aug_z = 1; break;
+           case 'L': cie_info->aug_L = 1; break;
+           case 'R': cie_info->aug_R = 1; break;
+           case 'S': cie_info->aug_S = 1; break;
+           case 'P': cie_info->aug_P = 1; break;
+           default:
+              ALOGV("execute_fde: Unrecognized CIE augmentation char: '%c'", ch);
+              return false;
+              break;
+        }
+    } while (ch);
+    if (!try_get_uleb128(memory, cie, &cie_info->code_align, &c)) {
+        return false;
+    }
+    if (!try_get_sleb128(memory, cie, &cie_info->data_align, &c)) {
+        return false;
+    }
+    if (cie_info->version >= 3) {
+        if (!try_get_uleb128(memory, cie, &cie_info->reg, &c)) {
+            return false;
+        }
+    } else {
+        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->reg, &c)) {
+            return false;
+        }
+    }
+    ALOGV("execute_fde: CIE code alignment factor: %d", cie_info->code_align);
+    ALOGV("execute_fde: CIE data alignment factor: %d", cie_info->data_align);
+    if (cie_info->aug_z) {
+        if (!try_get_uleb128(memory, cie, &cie_info->aug_z, &c)) {
+            return false;
+        }
+    }
+    if (cie_info->aug_L) {
+        if (!try_get_byte(memory, cie, &cie_info->aug_L, &c)) {
+            return false;
+        }
+    } else {
+        /* Default encoding. */
+        cie_info->aug_L = DW_EH_PE_absptr;
+    }
+    if (cie_info->aug_R) {
+        if (!try_get_byte(memory, cie, &cie_info->aug_R, &c)) {
+            return false;
+        }
+    } else {
+        /* Default encoding. */
+        cie_info->aug_R = DW_EH_PE_absptr;
+    }
+    if (cie_info->aug_P) {
+        /* Get encoding of personality routine pointer. We don't use it now. */
+        if (!try_get_byte(memory, cie, (uint8_t*)&cie_info->aug_P, &c)) {
+            return false;
+        }
+        /* Get routine pointer. */
+        if (!read_dwarf(memory, cie, &cie_info->aug_P, (uint8_t)cie_info->aug_P, &c)) {
+            return false;
+        }
+    }
+    /* CIE program. */
+    /* Length field itself (4 bytes) is not included into length. */
+    stack[0] = *dstate;
+    stack_ptr = 1;
+    while (c < cie_length + 4) {
+        if (!execute_dwarf(memory, cie, cie_info, dstate, &c, stack, &stack_ptr)) {
+           return false;
         }
     }
 
+    /* We went directly to CIE. Normally it shouldn't occur. */
+    if (cie == fde) return true;
+
+    /* Go back to FDE. */
+    c = 8;
+    /* Read FDE:
+       Augmentation independent:
+        next x bytes (encoded as specified in CIE) is FDE starting address;
+        next x bytes (encoded as specified in CIE) is FDE number of instructions covered;
+       Augmentation dependent:
+        if 'z' next x bytes is unsigned LEB128 encoded augmentation data size;
+        if 'L' next x bytes is LSDA pointer (encoded as specified in CIE);
+       Next x bytes is FDE program.
+     */
+    if (!read_dwarf(memory, fde, &fde_info->start, (uint8_t)cie_info->aug_R, &c)) {
+        return false;
+    }
+    dstate->loc = fde_info->start;
+    ALOGV("execute_fde: FDE start: %x", dstate->loc);
+    if (!read_dwarf(memory, fde, &fde_info->length, 0, &c)) {
+        return false;
+    }
+    ALOGV("execute_fde: FDE length: %x", fde_info->length);
+    if (cie_info->aug_z) {
+        if (!try_get_uleb128(memory, fde, &fde_info->aug_z, &c)) {
+            return false;
+        }
+    }
+    if (cie_info->aug_L && cie_info->aug_L != DW_EH_PE_omit) {
+        if (!read_dwarf(memory, fde, &fde_info->aug_L, cie_info->aug_L, &c)) {
+            return false;
+        }
+    }
+    /* FDE program. */
+    /* Length field itself (4 bytes) is not included into length. */
+    /* Save CIE state as 0 element of stack. Used by DW_CFA_restore. */
+    stack[0] = *dstate;
+    stack_ptr = 1;
+    while (c < fde_length + 4 && state->reg[DWARF_EIP] >= dstate->loc) {
+        if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
+           return false;
+        }
+        ALOGV("IP: %x, LOC: %x", state->reg[DWARF_EIP], dstate->loc);
+    }
+
+    return update_state(memory, state, dstate, cie_info);
+}
+
+static ssize_t unwind_backtrace_common(const memory_t* memory,
+        const map_info_t* map_info_list,
+        unwind_state_t* state, backtrace_frame_t* backtrace,
+        size_t ignore_depth, size_t max_depth) {
+
+    size_t ignored_frames = 0;
+    size_t returned_frames = 0;
+
+    ALOGV("Unwinding tid: %d", memory->tid);
+    ALOGV("IP: %x", state->reg[DWARF_EIP]);
+    ALOGV("BP: %x", state->reg[DWARF_EBP]);
+    ALOGV("SP: %x", state->reg[DWARF_ESP]);
+
+    for (size_t index = 0; returned_frames < max_depth; index++) {
+        uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_EIP]);
+        /* FDE is not found, it may happen if stack is corrupted or calling wrong adress.
+           Getting return address from stack.
+        */
+        if (!fde) {
+            uint32_t ip;
+            ALOGV("trying to restore registers from stack");
+            if (!try_get_word(memory, state->reg[DWARF_EBP] + 4, &ip) ||
+                ip == state->reg[DWARF_EIP]) {
+                ALOGV("can't get IP from stack");
+                break;
+            }
+            /* We've been able to get IP from stack so recording the frame before continue. */
+            backtrace_frame_t* frame = add_backtrace_entry(
+                    index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
+                    backtrace, ignore_depth, max_depth,
+                    &ignored_frames, &returned_frames);
+            state->reg[DWARF_EIP] = ip;
+            state->reg[DWARF_ESP] = state->reg[DWARF_EBP] + 8;
+            if (!try_get_word(memory, state->reg[DWARF_EBP], &state->reg[DWARF_EBP])) {
+                ALOGV("can't get EBP from stack");
+                break;
+            }
+            ALOGV("restore IP: %x", state->reg[DWARF_EIP]);
+            ALOGV("restore BP: %x", state->reg[DWARF_EBP]);
+            ALOGV("restore SP: %x", state->reg[DWARF_ESP]);
+            continue;
+        }
+        backtrace_frame_t* frame = add_backtrace_entry(
+                index ? rewind_pc_arch(memory, state->reg[DWARF_EIP]) : state->reg[DWARF_EIP],
+                backtrace, ignore_depth, max_depth,
+                &ignored_frames, &returned_frames);
+
+        uint32_t stack_top = state->reg[DWARF_ESP];
+
+        if (!execute_fde(memory, map_info_list, fde, state)) break;
+
+        if (frame) {
+            frame->stack_top = stack_top;
+            if (stack_top < state->reg[DWARF_ESP]) {
+                frame->stack_size = state->reg[DWARF_ESP] - stack_top;
+            }
+        }
+        ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_ESP], frame->stack_size);
+    }
     return returned_frames;
 }
 
@@ -128,9 +819,9 @@
     const ucontext_t* uc = (const ucontext_t*)sigcontext;
 
     unwind_state_t state;
-    state.ebp = uc->uc_mcontext.gregs[REG_EBP];
-    state.esp = uc->uc_mcontext.gregs[REG_ESP];
-    state.eip = uc->uc_mcontext.gregs[REG_EIP];
+    state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
+    state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
+    state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
 
     memory_t memory;
     init_memory(&memory, map_info_list);
@@ -146,9 +837,9 @@
     }
 
     unwind_state_t state;
-    state.ebp = regs.ebp;
-    state.eip = regs.eip;
-    state.esp = regs.esp;
+    state.reg[DWARF_EBP] = regs.ebp;
+    state.reg[DWARF_EIP] = regs.eip;
+    state.reg[DWARF_ESP] = regs.esp;
 
     memory_t memory;
     init_memory_ptrace(&memory, tid);
diff --git a/libcorkscrew/arch-x86/dwarf.h b/libcorkscrew/arch-x86/dwarf.h
new file mode 100755
index 0000000..962fc55
--- /dev/null
+++ b/libcorkscrew/arch-x86/dwarf.h
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dwarf2 data encoding flags.
+ */
+
+#define DW_EH_PE_absptr         0x00
+#define DW_EH_PE_omit           0xff
+#define DW_EH_PE_uleb128        0x01
+#define DW_EH_PE_udata2         0x02
+#define DW_EH_PE_udata4         0x03
+#define DW_EH_PE_udata8         0x04
+#define DW_EH_PE_sleb128        0x09
+#define DW_EH_PE_sdata2         0x0A
+#define DW_EH_PE_sdata4         0x0B
+#define DW_EH_PE_sdata8         0x0C
+#define DW_EH_PE_signed         0x08
+#define DW_EH_PE_pcrel          0x10
+#define DW_EH_PE_textrel        0x20
+#define DW_EH_PE_datarel        0x30
+#define DW_EH_PE_funcrel        0x40
+#define DW_EH_PE_aligned        0x50
+#define DW_EH_PE_indirect       0x80
+
+/*
+ * Dwarf2 call frame instructions.
+ */
+
+typedef enum {
+    DW_CFA_advance_loc = 0x40,
+    DW_CFA_offset = 0x80,
+    DW_CFA_restore = 0xc0,
+    DW_CFA_nop = 0x00,
+    DW_CFA_set_loc = 0x01,
+    DW_CFA_advance_loc1 = 0x02,
+    DW_CFA_advance_loc2 = 0x03,
+    DW_CFA_advance_loc4 = 0x04,
+    DW_CFA_offset_extended = 0x05,
+    DW_CFA_restore_extended = 0x06,
+    DW_CFA_undefined = 0x07,
+    DW_CFA_same_value = 0x08,
+    DW_CFA_register = 0x09,
+    DW_CFA_remember_state = 0x0a,
+    DW_CFA_restore_state = 0x0b,
+    DW_CFA_def_cfa = 0x0c,
+    DW_CFA_def_cfa_register = 0x0d,
+    DW_CFA_def_cfa_offset = 0x0e
+} dwarf_CFA;
+
+/*
+ * eh_frame_hdr information.
+*/
+
+typedef struct {
+      uint8_t version;
+      uint8_t eh_frame_ptr_enc;
+      uint8_t fde_count_enc;
+      uint8_t fde_table_enc;
+      uintptr_t eh_frame_ptr;
+      uint32_t fde_count;
+} eh_frame_hdr_info_t;
+
+/*
+ * CIE information.
+*/
+
+typedef struct {
+      uint8_t version;
+      uint32_t code_align;
+      uint32_t data_align;
+      uint32_t reg;
+      uint32_t aug_z;
+      uint8_t aug_L;
+      uint8_t aug_R;
+      uint8_t aug_S;
+      uint32_t aug_P;
+} cie_info_t;
+
+/*
+ * FDE information.
+*/
+
+typedef struct {
+      uint32_t start;
+      uint32_t length; // number of instructions covered by FDE
+      uint32_t aug_z;
+      uint32_t aug_L;
+} fde_info_t;
+
+/*
+ * Dwarf state.
+*/
+
+/* Stack of states: required for DW_CFA_remember_state/DW_CFA_restore_state
+   30 should be enough */
+#define DWARF_STATES_STACK 30
+
+typedef struct {
+    char rule;         // rule: o - offset(value); r - register(value)
+    uint32_t value;    // value
+} reg_rule_t;
+
+/* Dwarf preserved number of registers for x86. */
+
+#define DWARF_REGISTERS 17
+
+typedef struct {
+    uintptr_t loc;     // location (ip)
+    uint8_t cfa_reg;   // index of register where CFA location stored
+    intptr_t cfa_off;  // offset
+    reg_rule_t regs[DWARF_REGISTERS]; // dwarf preserved registers for x86
+} dwarf_state_t;
+
+/* DWARF registers we are caring about. */
+
+#define DWARF_EAX     0
+#define DWARF_ECX     1
+#define DWARF_EDX     2
+#define DWARF_EBX     3
+#define DWARF_ESP     4
+#define DWARF_EBP     5
+#define DWARF_ESI     6
+#define DWARF_EDI     7
+#define DWARF_EIP     8
+
+
diff --git a/libcorkscrew/arch-x86/ptrace-x86.c b/libcorkscrew/arch-x86/ptrace-x86.c
old mode 100644
new mode 100755
index 07cfd3a..9c49b93
--- a/libcorkscrew/arch-x86/ptrace-x86.c
+++ b/libcorkscrew/arch-x86/ptrace-x86.c
@@ -19,11 +19,44 @@
 
 #include "../ptrace-arch.h"
 
+#include <stddef.h>
+#include <elf.h>
 #include <cutils/log.h>
 
-void load_ptrace_map_info_data_arch(pid_t pid __attribute__((unused)),
-                                    map_info_t* mi __attribute__((unused)),
-                                    map_info_data_t* data __attribute__((unused))) {
+static void load_eh_frame_hdr(pid_t pid, map_info_t* mi, uintptr_t *eh_frame_hdr) {
+    uint32_t elf_phoff;
+    uint32_t elf_phentsize_ehsize;
+    uint32_t elf_shentsize_phnum;
+    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
+                    &elf_phentsize_ehsize)
+            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
+                    &elf_shentsize_phnum)) {
+        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
+        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
+        for (uint32_t i = 0; i < elf_phnum; i++) {
+            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
+            uint32_t elf_phdr_type;
+            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
+                break;
+            }
+            if (elf_phdr_type == PT_GNU_EH_FRAME) {
+                uint32_t elf_phdr_offset;
+                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
+                        &elf_phdr_offset)) {
+                    break;
+                }
+                *eh_frame_hdr = mi->start + elf_phdr_offset;
+                ALOGV("Parsed .eh_frame_hdr info for %s: start=0x%08x", mi->name, *eh_frame_hdr);
+                return;
+            }
+        }
+    }
+    *eh_frame_hdr = 0;
+}
+
+void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
+    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
 }
 
 void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
diff --git a/libcorkscrew/ptrace-arch.h b/libcorkscrew/ptrace-arch.h
old mode 100644
new mode 100755
index c02df52..4451c29
--- a/libcorkscrew/ptrace-arch.h
+++ b/libcorkscrew/ptrace-arch.h
@@ -33,6 +33,8 @@
 #ifdef __arm__
     uintptr_t exidx_start;
     size_t exidx_size;
+#elif __i386__
+    uintptr_t eh_frame_hdr;
 #endif
     symbol_table_t* symbol_table;
 } map_info_data_t;
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
index 6496d5e..776ef69 100644
--- a/libcorkscrew/ptrace.c
+++ b/libcorkscrew/ptrace.c
@@ -129,6 +129,7 @@
         free_ptrace_map_info_data(mi);
     }
     free_map_info_list(context->map_info_list);
+    free(context);
 }
 
 void find_symbol_ptrace(const ptrace_context_t* context,
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 3485392..17b320f 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -130,7 +130,11 @@
 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
 endif # !arm
 
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
new file mode 100644
index 0000000..bbc99fe
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/memory.h>
+
+/* Use mips-assembler versions supplied by bionic/libc/arch-mips/string/memset.S: */
+void _memset16(uint16_t* dst, uint16_t value, size_t size);
+void _memset32(uint32_t* dst, uint32_t value, size_t size);
+
+void android_memset16(uint16_t* dst, uint16_t value, size_t size)
+{
+    _memset16(dst, value, size);
+}
+
+void android_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+    _memset32(dst, value, size);
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index d812abc..3613d25 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include <cutils/logger.h>
 #include <cutils/logd.h>
@@ -37,7 +39,7 @@
 #define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
 #define log_close(filedes) fakeLogClose(filedes)
 #else
-#define log_open(pathname, flags) open(pathname, flags)
+#define log_open(pathname, flags) open(pathname, (flags) | O_CLOEXEC)
 #define log_writev(filedes, vector, count) writev(filedes, vector, count)
 #define log_close(filedes) close(filedes)
 #endif
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index 2c32ce3..34a879b 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -72,7 +72,7 @@
 
 
 
-static unsigned char padding[4096] = { 0, };
+static unsigned char padding[16384] = { 0, };
 
 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
 {
@@ -152,7 +152,8 @@
             board = val;
         } else if(!strcmp(arg,"--pagesize")) {
             pagesize = strtoul(val, 0, 10);
-            if ((pagesize != 2048) && (pagesize != 4096)) {
+            if ((pagesize != 2048) && (pagesize != 4096)
+                && (pagesize != 8192) && (pagesize != 16384)) {
                 fprintf(stderr,"error: unsupported page size %d\n", pagesize);
                 return -1;
             }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d6182e8..e1b826e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -37,7 +37,7 @@
     export ANDROID_STORAGE /storage
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
-    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
+    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/okhttp.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar
 
 # Backward compatibility
     symlink /system/etc /etc
@@ -242,6 +242,9 @@
     # the following directory.
     mkdir /data/drm 0770 drm drm
 
+    # Separate location for storing security policy files on data
+    mkdir /data/security 0700 system system
+
     # 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.
diff --git a/run-as/package.c b/run-as/package.c
index 143d647..27fc1eb 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -47,15 +47,18 @@
 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
  * This function always zero-terminate the destination buffer unless
  * 'dstlen' is 0, even in case of overflow.
+ * Returns a pointer into the src string, leaving off where the copy
+ * has stopped. The copy will stop when dstlen, srclen or a null
+ * character on src has been reached.
  */
-static void
+static const char*
 string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
 {
     const char* srcend = src + srclen;
     const char* dstend = dst + dstlen;
 
     if (dstlen == 0)
-        return;
+        return src;
 
     dstend--; /* make room for terminating zero */
 
@@ -63,6 +66,7 @@
         *dst++ = *src++;
 
     *dst = '\0'; /* zero-terminate result */
+    return src;
 }
 
 /* Open 'filename' and map it into our address-space.
@@ -76,13 +80,30 @@
     struct stat  st;
     size_t  length = 0;
     void*   address = NULL;
+    gid_t   oldegid;
 
     *filesize = 0;
 
+    /*
+     * Temporarily switch effective GID to allow us to read
+     * the packages file
+     */
+
+    oldegid = getegid();
+    if (setegid(AID_SYSTEM) < 0) {
+        return NULL;
+    }
+
     /* open the file for reading */
     fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
-    if (fd < 0)
+    if (fd < 0) {
         return NULL;
+    }
+
+    /* restore back to our old egid */
+    if (setegid(oldegid) < 0) {
+        goto EXIT;
+    }
 
     /* get its size */
     ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
@@ -411,6 +432,7 @@
     info->uid          = 0;
     info->isDebuggable = 0;
     info->dataDir[0]   = '\0';
+    info->seinfo[0]    = '\0';
 
     buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
     if (buffer == NULL)
@@ -421,13 +443,14 @@
 
     /* expect the following format on each line of the control file:
      *
-     *  <pkgName> <uid> <debugFlag> <dataDir>
+     *  <pkgName> <uid> <debugFlag> <dataDir> <seinfo>
      *
      * where:
      *  <pkgName>    is the package's name
      *  <uid>        is the application-specific user Id (decimal)
      *  <debugFlag>  is 1 if the package is debuggable, or 0 otherwise
      *  <dataDir>    is the path to the package's data directory (e.g. /data/data/com.example.foo)
+     *  <seinfo>     is the seinfo label associated with the package
      *
      * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
      */
@@ -483,7 +506,18 @@
         if (q == p)
             goto BAD_FORMAT;
 
-        string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+        p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
+
+        /* skip spaces */
+        if (parse_spaces(&p, end) < 0)
+            goto BAD_FORMAT;
+
+        /* fifth field is the seinfo string */
+        q = skip_non_spaces(p, end);
+        if (q == p)
+            goto BAD_FORMAT;
+
+        string_copy(info->seinfo, sizeof info->seinfo, p, q - p);
 
         /* Ignore the rest */
         result = 0;
diff --git a/run-as/package.h b/run-as/package.h
index 852af06..34603c0 100644
--- a/run-as/package.h
+++ b/run-as/package.h
@@ -30,6 +30,7 @@
     uid_t  uid;
     char   isDebuggable;
     char   dataDir[PATH_MAX];
+    char   seinfo[PATH_MAX];
 } PackageInfo;
 
 /* see documentation in package.c for these functiosn */
diff --git a/run-as/run-as.c b/run-as/run-as.c
index 9eb09ae..3c0ecc4 100644
--- a/run-as/run-as.c
+++ b/run-as/run-as.c
@@ -163,7 +163,7 @@
         return 1;
     }
 
-    if (selinux_android_setcontext(uid, 0, NULL, pkgname) < 0) {
+    if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
         panic("Could not set SELinux security context:  %s\n", strerror(errno));
         return 1;
     }
diff --git a/toolbox/ls.c b/toolbox/ls.c
index e530521..5324511 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -28,6 +28,7 @@
 #define LIST_LONG_NUMERIC   (1 << 5)
 #define LIST_CLASSIFY       (1 << 6)
 #define LIST_MACLABEL       (1 << 7)
+#define LIST_INODE          (1 << 8)
 
 // fwd
 static int listpath(const char *name, int flags);
@@ -127,22 +128,20 @@
     return 0;
 }
 
-static int listfile_size(const char *path, const char *filename, int flags)
+static int listfile_size(const char *path, const char *filename, struct stat *s,
+                         int flags)
 {
-    struct stat s;
-
-    if (lstat(path, &s) < 0) {
-        fprintf(stderr, "lstat '%s' failed: %s\n", path, strerror(errno));
+    if(!s || !path) {
         return -1;
     }
 
     /* blocks are 512 bytes, we want output to be KB */
     if ((flags & LIST_SIZE) != 0) {
-        printf("%lld ", s.st_blocks / 2);
+        printf("%lld ", s->st_blocks / 2);
     }
 
     if ((flags & LIST_CLASSIFY) != 0) {
-        char filetype = mode2kind(s.st_mode);
+        char filetype = mode2kind(s->st_mode);
         if (filetype != 'l') {
             printf("%c ", filetype);
         } else {
@@ -161,15 +160,18 @@
     return 0;
 }
 
-static int listfile_long(const char *path, int flags)
+static int listfile_long(const char *path, struct stat *s, int flags)
 {
-    struct stat s;
     char date[32];
     char mode[16];
     char user[16];
     char group[16];
     const char *name;
 
+    if(!s || !path) {
+        return -1;
+    }
+
     /* name is anything after the final '/', or the whole path if none*/
     name = strrchr(path, '/');
     if(name == 0) {
@@ -178,36 +180,32 @@
         name++;
     }
 
-    if(lstat(path, &s) < 0) {
-        return -1;
-    }
-
-    mode2str(s.st_mode, mode);
+    mode2str(s->st_mode, mode);
     if (flags & LIST_LONG_NUMERIC) {
-        sprintf(user, "%ld", s.st_uid);
-        sprintf(group, "%ld", s.st_gid);
+        sprintf(user, "%ld", s->st_uid);
+        sprintf(group, "%ld", s->st_gid);
     } else {
-        user2str(s.st_uid, user);
-        group2str(s.st_gid, group);
+        user2str(s->st_uid, user);
+        group2str(s->st_gid, group);
     }
 
-    strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s.st_mtime));
+    strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime));
     date[31] = 0;
 
 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
 // MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK)
 
-    switch(s.st_mode & S_IFMT) {
+    switch(s->st_mode & S_IFMT) {
     case S_IFBLK:
     case S_IFCHR:
         printf("%s %-8s %-8s %3d, %3d %s %s\n",
                mode, user, group,
-               (int) MAJOR(s.st_rdev), (int) MINOR(s.st_rdev),
+               (int) MAJOR(s->st_rdev), (int) MINOR(s->st_rdev),
                date, name);
         break;
     case S_IFREG:
         printf("%s %-8s %-8s %8lld %s %s\n",
-               mode, user, group, s.st_size, date, name);
+               mode, user, group, s->st_size, date, name);
         break;
     case S_IFLNK: {
         char linkto[256];
@@ -237,15 +235,18 @@
     return 0;
 }
 
-static int listfile_maclabel(const char *path, int flags)
+static int listfile_maclabel(const char *path, struct stat *s, int flags)
 {
-    struct stat s;
     char mode[16];
     char user[16];
     char group[16];
     char *maclabel = NULL;
     const char *name;
 
+    if(!s || !path) {
+        return -1;
+    }
+
     /* name is anything after the final '/', or the whole path if none*/
     name = strrchr(path, '/');
     if(name == 0) {
@@ -254,20 +255,16 @@
         name++;
     }
 
-    if(lstat(path, &s) < 0) {
-        return -1;
-    }
-
     lgetfilecon(path, &maclabel);
     if (!maclabel) {
         return -1;
     }
 
-    mode2str(s.st_mode, mode);
-    user2str(s.st_uid, user);
-    group2str(s.st_gid, group);
+    mode2str(s->st_mode, mode);
+    user2str(s->st_uid, user);
+    group2str(s->st_gid, group);
 
-    switch(s.st_mode & S_IFMT) {
+    switch(s->st_mode & S_IFMT) {
     case S_IFLNK: {
         char linkto[256];
         ssize_t len;
@@ -301,7 +298,9 @@
 
 static int listfile(const char *dirname, const char *filename, int flags)
 {
-    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL)) == 0) {
+    struct stat s;
+
+    if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL | LIST_INODE)) == 0) {
         printf("%s\n", filename);
         return 0;
     }
@@ -316,12 +315,20 @@
         pathname = filename;
     }
 
+    if(lstat(pathname, &s) < 0) {
+        return -1;
+    }
+
+    if(flags & LIST_INODE) {
+        printf("%8llu ", s.st_ino);
+    }
+
     if ((flags & LIST_MACLABEL) != 0) {
-        return listfile_maclabel(pathname, flags);
+        return listfile_maclabel(pathname, &s, flags);
     } else if ((flags & LIST_LONG) != 0) {
-        return listfile_long(pathname, flags);
+        return listfile_long(pathname, &s, flags);
     } else /*((flags & LIST_SIZE) != 0)*/ {
-        return listfile_size(pathname, filename, flags);
+        return listfile_size(pathname, filename, &s, flags);
     }
 }
 
@@ -456,6 +463,7 @@
                     case 'Z': flags |= LIST_MACLABEL; break;
                     case 'a': flags |= LIST_ALL; break;
                     case 'F': flags |= LIST_CLASSIFY; break;
+                    case 'i': flags |= LIST_INODE; break;
                     default:
                         fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
                         exit(1);