am eb42170e: Display file sizes larger than 2GB correctly

Merge commit 'eb42170e6c8b70f11dca9965785aa04a80290c72' into gingerbread-plus-aosp

* commit 'eb42170e6c8b70f11dca9965785aa04a80290c72':
  Display file sizes larger than 2GB correctly
diff --git a/adb/sockets.c b/adb/sockets.c
index 9f1b598..43925e4 100644
--- a/adb/sockets.c
+++ b/adb/sockets.c
@@ -65,8 +65,11 @@
     asocket *result = NULL;
 
     adb_mutex_lock(&socket_list_lock);
-    for(s = local_socket_list.next; s != &local_socket_list && !result; s = s->next) {
-        if(s->id == id) result = s;
+    for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+        if (s->id == id) {
+            result = s;
+            break;
+        }
     }
     adb_mutex_unlock(&socket_list_lock);
 
@@ -366,7 +369,7 @@
 asocket *create_local_socket(int fd)
 {
     asocket *s = calloc(1, sizeof(asocket));
-    if(s == 0) fatal("cannot allocate socket");
+    if (s == NULL) fatal("cannot allocate socket");
     install_local_socket(s);
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
@@ -482,7 +485,7 @@
     asocket *s = calloc(1, sizeof(aremotesocket));
     adisconnect*  dis = &((aremotesocket*)s)->disconnect;
 
-    if(s == 0) fatal("cannot allocate socket");
+    if (s == NULL) fatal("cannot allocate socket");
     s->id = id;
     s->enqueue = remote_socket_enqueue;
     s->ready = remote_socket_ready;
@@ -761,8 +764,7 @@
 {
     D("Creating smart socket \n");
     asocket *s = calloc(1, sizeof(asocket));
-    if(s == 0) fatal("cannot allocate socket");
-    s->id = 0;
+    if (s == NULL) fatal("cannot allocate socket");
     s->enqueue = smart_socket_enqueue;
     s->ready = smart_socket_ready;
     s->close = smart_socket_close;
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 9e1600f..993206f 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -69,6 +69,8 @@
 #define VENDOR_ID_PANTECH       0x10A9
 // Qualcomm's USB Vendor ID
 #define VENDOR_ID_QUALCOMM      0x05c6
+// On-The-Go-Video's USB Vendor ID
+#define VENDOR_ID_OTGV          0x2257
 // NEC's USB Vendor ID
 #define VENDOR_ID_NEC           0x0409
 // Panasonic Mobile Communication's USB Vendor ID
@@ -94,6 +96,7 @@
     VENDOR_ID_KYOCERA,
     VENDOR_ID_PANTECH,
     VENDOR_ID_QUALCOMM,
+    VENDOR_ID_OTGV,
     VENDOR_ID_NEC,
     VENDOR_ID_PMC,
 };
@@ -157,7 +160,7 @@
 /* builds the path to the adb vendor id file. returns 0 if success */
 int build_path(char* buff, size_t len, const char* format, const char* home)
 {
-    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= len) {
+    if (snprintf(buff, len, format, home, ANDROID_PATH, ANDROID_ADB_INI) >= (signed)len) {
         return 1;
     }
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 3c1cf02..ccc001b 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c
+LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c symbol_table.c
 LOCAL_CFLAGS := -Wall
 LOCAL_MODULE := debuggerd
 
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index e850a2e..3b2972a 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -63,7 +63,7 @@
 /* Log information onto the tombstone */
 void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...)
 {
-    char buf[128];
+    char buf[512];
 
     va_list ap;
     va_start(ap, fmt);
@@ -106,10 +106,11 @@
 
     mi->start = strtoul(line, 0, 16);
     mi->end = strtoul(line + 9, 0, 16);
-    /* To be filled in parse_exidx_info if the mapped section starts with
+    /* To be filled in parse_elf_info if the mapped section starts with
      * elf_header
      */
     mi->exidx_start = mi->exidx_end = 0;
+    mi->symbols = 0;
     mi->next = 0;
     strcpy(mi->name, line + 49);
 
@@ -353,7 +354,7 @@
     if(sig) dump_fault_addr(tfd, tid, sig);
 }
 
-static void parse_exidx_info(mapinfo *milist, pid_t pid)
+static void parse_elf_info(mapinfo *milist, pid_t pid)
 {
     mapinfo *mi;
     for (mi = milist; mi != NULL; mi = mi->next) {
@@ -383,6 +384,9 @@
                     break;
                 }
             }
+
+            /* Try to load symbols from this file */
+            mi->symbols = symbol_table_create(mi->name);
         }
     }
 }
@@ -420,7 +424,7 @@
         fclose(fp);
     }
 
-    parse_exidx_info(milist, tid);
+    parse_elf_info(milist, tid);
 
     /* If stack unwinder fails, use the default solution to dump the stack
      * content.
@@ -439,6 +443,7 @@
 
     while(milist) {
         mapinfo *next = milist->next;
+        symbol_table_free(milist->symbols);
         free(milist);
         milist = next;
     }
diff --git a/debuggerd/symbol_table.c b/debuggerd/symbol_table.c
new file mode 100644
index 0000000..150c058
--- /dev/null
+++ b/debuggerd/symbol_table.c
@@ -0,0 +1,178 @@
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "symbol_table.h"
+
+#include <linux/elf.h>
+
+// Compare func for qsort
+static int qcompar(const void *a, const void *b)
+{
+    return ((struct symbol*)a)->addr - ((struct symbol*)b)->addr;
+}
+
+// Compare func for bsearch
+static int bcompar(const void *addr, const void *element)
+{
+    struct symbol *symbol = (struct symbol*)element;
+
+    if((unsigned int)addr < symbol->addr) {
+        return -1;
+    }
+
+    if((unsigned int)addr - symbol->addr >= symbol->size) {
+        return 1;
+    }
+
+    return 0;
+}
+
+/*
+ *  Create a symbol table from a given file
+ *
+ *  Parameters:
+ *      filename - Filename to process
+ *
+ *  Returns:
+ *      A newly-allocated SymbolTable structure, or NULL if error.
+ *      Free symbol table with symbol_table_free()
+ */
+struct symbol_table *symbol_table_create(const char *filename)
+{
+    struct symbol_table *table = NULL;
+
+    // Open the file, and map it into memory
+    struct stat sb;
+    int length;
+    char *base;
+
+    int fd = open(filename, O_RDONLY);
+
+    if(fd < 0) {
+        goto out;
+    }
+
+    fstat(fd, &sb);
+    length = sb.st_size;
+
+    base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+
+    if(!base) {
+        goto out_close;
+    }
+
+    // Parse the file header
+    Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
+    Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
+
+    // Search for the dynamic symbols section
+    int dynsym_idx = -1;
+    int i;
+
+    for(i = 0; i < hdr->e_shnum; i++) {
+        if(shdr[i].sh_type == SHT_DYNSYM ) {
+            dynsym_idx = i;
+        }
+    }
+
+    if(dynsym_idx == -1) {
+        goto out_unmap;
+    }
+
+    Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
+    int numsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
+
+    table = malloc(sizeof(struct symbol_table));
+    if(!table) {
+        goto out_unmap;
+    }
+    table->num_symbols = 0;
+
+    // Iterate through the dynamic symbol table, and count how many symbols
+    // are actually defined
+    for(i = 0; i < numsyms; i++) {
+        if(dynsyms[i].st_shndx != SHN_UNDEF) {
+            table->num_symbols++;
+        }
+    }
+
+    int dynstr_idx = shdr[dynsym_idx].sh_link;
+    char *dynstr = base + shdr[dynstr_idx].sh_offset;
+
+    // Now, create an entry in our symbol table structure for each symbol...
+    table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
+    if(!table->symbols) {
+        free(table);
+        table = NULL;
+        goto out_unmap;
+    }
+
+    // ...and populate them
+    int j = 0;
+    for(i = 0; i < numsyms; i++) {
+        if(dynsyms[i].st_shndx != SHN_UNDEF) {
+            table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
+            table->symbols[j].addr = dynsyms[i].st_value;
+            table->symbols[j].size = dynsyms[i].st_size;
+            j++;
+        }
+    }
+
+    // Sort the symbol table entries, so they can be bsearched later
+    qsort(table->symbols, table->num_symbols, sizeof(struct symbol), qcompar);
+
+out_unmap:
+    munmap(base, length);
+
+out_close:
+    close(fd);
+
+out:
+    return table;
+}
+
+/*
+ * Free a symbol table
+ *
+ * Parameters:
+ *     table - Table to free
+ */
+void symbol_table_free(struct symbol_table *table)
+{
+    int i;
+
+    if(!table) {
+        return;
+    }
+
+    for(i=0; i<table->num_symbols; i++) {
+        free(table->symbols[i].name);
+    }
+
+    free(table->symbols);
+    free(table);
+}
+
+/*
+ * Search for an address in the symbol table
+ *
+ * Parameters:
+ *      table - Table to search in
+ *      addr - Address to search for.
+ *
+ * Returns:
+ *      A pointer to the Symbol structure corresponding to the
+ *      symbol which contains this address, or NULL if no symbol
+ *      contains it.
+ */
+const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr)
+{
+    if(!table) {
+        return NULL;
+    }
+
+    return bsearch((void*)addr, table->symbols, table->num_symbols, sizeof(struct symbol), bcompar);
+}
diff --git a/debuggerd/symbol_table.h b/debuggerd/symbol_table.h
new file mode 100644
index 0000000..d9d2520
--- /dev/null
+++ b/debuggerd/symbol_table.h
@@ -0,0 +1,19 @@
+#ifndef SYMBOL_TABLE_H
+#define SYMBOL_TABLE_H
+
+struct symbol {
+    unsigned int addr;
+    unsigned int size;
+    char *name;
+};
+
+struct symbol_table {
+    struct symbol *symbols;
+    int num_symbols;
+};
+
+struct symbol_table *symbol_table_create(const char *filename);
+void symbol_table_free(struct symbol_table *table);
+const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr);
+
+#endif
diff --git a/debuggerd/unwind-arm.c b/debuggerd/unwind-arm.c
index 9642d2e..b081161 100644
--- a/debuggerd/unwind-arm.c
+++ b/debuggerd/unwind-arm.c
@@ -37,6 +37,8 @@
 #include <unwind.h>
 #include "utility.h"
 
+#include "symbol_table.h"
+
 typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */
 
 void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);
@@ -393,6 +395,7 @@
     phase2_vrs *vrs = (phase2_vrs*) context;
     const mapinfo *mi;
     bool only_in_tombstone = !at_fault;
+    const struct symbol* sym = 0;
 
     if (stack_level < STACK_CONTENT_DEPTH) {
         sp_list[stack_level] = vrs->core.r[R_SP];
@@ -451,9 +454,20 @@
     rel_pc = pc;
     mi = pc_to_mapinfo(map, pc, &rel_pc);
 
-    _LOG(tfd, only_in_tombstone, 
-         "         #%02d  pc %08x  %s\n", stack_level, rel_pc, 
-         mi ? mi->name : "");
+    /* See if we can determine what symbol this stack frame resides in */
+    if (mi != 0 && mi->symbols != 0) {
+        sym = symbol_table_lookup(mi->symbols, rel_pc);
+    }
+
+    if (sym) {
+        _LOG(tfd, only_in_tombstone,
+            "         #%02d  pc %08x  %s (%s)\n", stack_level, rel_pc,
+            mi ? mi->name : "", sym->name);
+    } else {
+        _LOG(tfd, only_in_tombstone,
+            "         #%02d  pc %08x  %s\n", stack_level, rel_pc,
+            mi ? mi->name : "");
+    }
 
     return _URC_NO_REASON;
 }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 49f5951..2ffdf56 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
 #include <stddef.h>
 #include <stdbool.h>
 
+#include "symbol_table.h"
+
 #ifndef PT_ARM_EXIDX
 #define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
 #endif
@@ -33,6 +35,7 @@
     unsigned end;
     unsigned exidx_start;
     unsigned exidx_end;
+    struct symbol_table *symbols;
     char name[];
 } mapinfo;
 
diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h
new file mode 100644
index 0000000..96798c5
--- /dev/null
+++ b/include/netutils/dhcp.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010, 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 _NETUTILS_DHCP_H_
+#define _NETUTILS_DHCP_H_
+
+#include <sys/cdefs.h>
+#include <arpa/inet.h>
+
+__BEGIN_DECLS
+
+extern int do_dhcp(char *iname);
+extern int dhcp_do_request(const char *ifname,
+                          in_addr_t *ipaddr,
+                          in_addr_t *gateway,
+                          in_addr_t *mask,
+                          in_addr_t *dns1,
+                          in_addr_t *dns2,
+                          in_addr_t *server,
+                          uint32_t  *lease);
+extern int dhcp_stop(const char *ifname);
+extern int dhcp_release_lease(const char *ifname);
+extern char *dhcp_get_errmsg();
+
+__END_DECLS
+
+#endif /* _NETUTILS_DHCP_H_ */
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
new file mode 100644
index 0000000..2e502ab
--- /dev/null
+++ b/include/netutils/ifc.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+
+#ifndef _NETUTILS_IFC_H_
+#define _NETUTILS_IFC_H_
+
+#include <sys/cdefs.h>
+#include <arpa/inet.h>
+
+__BEGIN_DECLS
+
+extern int ifc_init(void);
+extern void ifc_close(void);
+
+extern int ifc_get_ifindex(const char *name, int *if_indexp);
+extern int ifc_get_hwaddr(const char *name, void *ptr);
+
+extern int ifc_up(const char *name);
+extern int ifc_down(const char *name);
+
+extern int ifc_enable(const char *ifname);
+extern int ifc_disable(const char *ifname);
+
+extern int ifc_reset_connections(const char *ifname);
+
+extern int ifc_set_addr(const char *name, in_addr_t addr);
+extern int ifc_set_mask(const char *name, in_addr_t mask);
+extern int ifc_set_hwaddr(const char *name, const void *ptr);
+
+extern int ifc_add_host_route(const char *name, in_addr_t addr);
+extern int ifc_remove_host_routes(const char *name);
+extern int ifc_get_default_route(const char *ifname);
+extern int ifc_set_default_route(const char *ifname, in_addr_t gateway);
+extern int ifc_create_default_route(const char *name, in_addr_t addr);
+extern int ifc_remove_default_route(const char *ifname);
+
+extern int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask,
+                        in_addr_t *flags);
+
+extern int ifc_configure(const char *ifname, in_addr_t address,
+                         in_addr_t netmask, in_addr_t gateway,
+                         in_addr_t dns1, in_addr_t dns2);
+
+__END_DECLS
+
+#endif /* _NETUTILS_IFC_H_ */
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index 0f8a6c4..cb0960f 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -115,6 +115,14 @@
     }
 }
 
+static const char *ipaddr_to_string(in_addr_t addr)
+{
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
+}
+
 /*
  * Start the dhcp client daemon, and wait for it to finish
  * configuring the interface.
@@ -165,7 +173,13 @@
         return -1;
     }
     if (strcmp(prop_value, "ok") == 0) {
+        char dns_prop_name[PROPERTY_KEY_MAX];
         fill_ip_info(interface, ipaddr, gateway, mask, dns1, dns2, server, lease);
+        /* copy the dhcp.XXX.dns properties to net.XXX.dns */
+        snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface);
+        property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : "");
+        snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface);
+        property_set(dns_prop_name, *dns2 ? ipaddr_to_string(*dns2) : "");
         return 0;
     } else {
         snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value);
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index 6755ba1..ff00432 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -36,8 +36,8 @@
 
 #include <dirent.h>
 
+#include <netutils/ifc.h>
 #include "dhcpmsg.h"
-#include "ifc_utils.h"
 #include "packet.h"
 
 #define VERBOSE 2
@@ -85,16 +85,12 @@
 //    exit(1);
 }
 
-const char *ipaddr(uint32_t addr)
+const char *ipaddr(in_addr_t addr)
 {
-    static char buf[32];
+    struct in_addr in_addr;
 
-    sprintf(buf,"%d.%d.%d.%d",
-            addr & 255,
-            ((addr >> 8) & 255),
-            ((addr >> 16) & 255),
-            (addr >> 24));
-    return buf;
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
 }
 
 typedef struct dhcp_info dhcp_info;
@@ -128,31 +124,11 @@
     *lease = last_good_info.lease;
 }
 
-static int ifc_configure(const char *ifname, dhcp_info *info)
+static int dhcp_configure(const char *ifname, dhcp_info *info)
 {
-    char dns_prop_name[PROPERTY_KEY_MAX];
-
-    if (ifc_set_addr(ifname, info->ipaddr)) {
-        printerr("failed to set ipaddr %s: %s\n", ipaddr(info->ipaddr), strerror(errno));
-        return -1;
-    }
-    if (ifc_set_mask(ifname, info->netmask)) {
-        printerr("failed to set netmask %s: %s\n", ipaddr(info->netmask), strerror(errno));
-        return -1;
-    }
-    if (ifc_create_default_route(ifname, info->gateway)) {
-        printerr("failed to set default route %s: %s\n", ipaddr(info->gateway), strerror(errno));
-        return -1;
-    }
-
-    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
-    property_set(dns_prop_name, info->dns1 ? ipaddr(info->dns1) : "");
-    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
-    property_set(dns_prop_name, info->dns2 ? ipaddr(info->dns2) : "");
-
     last_good_info = *info;
-
-    return 0;
+    return ifc_configure(ifname, info->ipaddr, info->netmask, info->gateway,
+                         info->dns1, info->dns2);
 }
 
 static const char *dhcp_type_to_name(uint32_t type)
@@ -449,7 +425,7 @@
                 printerr("timed out\n");
                 if ( info.type == DHCPOFFER ) {
                     printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
-                    return ifc_configure(ifname, &info);
+                    return dhcp_configure(ifname, &info);
                 }
                 errno = ETIME;
                 close(s);
@@ -530,7 +506,7 @@
             if (info.type == DHCPACK) {
                 printerr("configuring %s\n", ifname);
                 close(s);
-                return ifc_configure(ifname, &info);
+                return dhcp_configure(ifname, &info);
             } else if (info.type == DHCPNAK) {
                 printerr("configuration request denied\n");
                 close(s);
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index bde336f..296d617 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -27,6 +27,8 @@
 #include <arpa/inet.h>
 
 #include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_arp.h>
 #include <linux/sockios.h>
 #include <linux/route.h>
 #include <linux/wireless.h>
@@ -45,7 +47,7 @@
 static int ifc_ctl_sock = -1;
 void printerr(char *fmt, ...);
 
-static const char *ipaddr_to_string(uint32_t addr)
+static const char *ipaddr_to_string(in_addr_t addr)
 {
     struct in_addr in_addr;
 
@@ -88,7 +90,7 @@
     r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
     if(r < 0) return -1;
 
-    memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6);
+    memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
     return 0;    
 }
 
@@ -143,6 +145,17 @@
     return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
 }
 
+int ifc_set_hwaddr(const char *name, const void *ptr)
+{
+    int r;
+    struct ifreq ifr;
+    ifc_init_ifr(name, &ifr);
+
+    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+    memcpy(&ifr.ifr_hwaddr.sa_data, ptr, ETH_ALEN);
+    return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr);
+}
+
 int ifc_set_mask(const char *name, in_addr_t mask)
 {
     struct ifreq ifr;
@@ -429,9 +442,9 @@
 
     ifc_close();
 
-    snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname);
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
     property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
-    snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname);
+    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
     property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
 
     return 0;
diff --git a/libnetutils/ifc_utils.h b/libnetutils/ifc_utils.h
deleted file mode 100644
index 49b8747..0000000
--- a/libnetutils/ifc_utils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); 
- * you may not use this file except in compliance with the License. 
- * You may obtain a copy of the License at 
- *
- *     http://www.apache.org/licenses/LICENSE-2.0 
- *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
- * limitations under the License.
- */
-
-#ifndef _IFC_UTILS_H_
-#define _IFC_UTILS_H_
-
-int ifc_init(void);
-
-int ifc_get_ifindex(const char *name, int *if_indexp);
-int ifc_get_hwaddr(const char *name, void *ptr);
-
-int ifc_up(const char *name);
-int ifc_down(const char *name);
-
-int ifc_set_addr(const char *name, unsigned addr);
-int ifc_set_mask(const char *name, unsigned mask);
-
-int ifc_create_default_route(const char *name, unsigned addr);
-
-int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
-
-#endif
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index d3720c3..fa9f1ad 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -433,6 +433,16 @@
 {
     *mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
 }
+#if 0
+#pragma mark -
+#pragma mark Bit manipulation (ARMv7+ only)...
+#endif
+
+// Bit manipulation (ARMv7+ only)...
+void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
+{
+    *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
+}
 
 }; // namespace android
 
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index a667cb5..e7f038a 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -124,6 +124,7 @@
     virtual void SMLAW(int cc, int y,
                 int Rd, int Rm, int Rs, int Rn);
     virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
 
 private:
                 ARMAssembler(const ARMAssembler& rhs);
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
index ff6af2a..796342a 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
@@ -206,6 +206,9 @@
     // byte/half word extract...
     virtual void UXTB16(int cc, int Rd, int Rm, int rotate) = 0;
 
+    // bit manipulation...
+    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width) = 0;
+
     // -----------------------------------------------------------------------
     // convenience...
     // -----------------------------------------------------------------------
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
index 7c422db..c57d7da 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
@@ -199,5 +199,9 @@
     mTarget->UXTB16(cc, Rd, Rm, rotate);
 }
 
+void ARMAssemblerProxy::UBFX(int cc, int Rd, int Rn, int lsb, int width) {
+    mTarget->UBFX(cc, Rd, Rn, lsb, width);
+}
+
 }; // namespace android
 
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
index 9134cce..8c7f270 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -115,6 +115,7 @@
                 int Rd, int Rm, int Rs, int Rn);
 
     virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
+    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
 
 private:
     ARMAssemblerInterface*  mTarget;
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index c17f3ec..aeb8034 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -81,6 +81,8 @@
  * g - 2nd fp operand (register) (bits 16-18)
  * h - 3rd fp operand (register/immediate) (bits 0-4)
  * j - xtb rotate literal (bits 10-11)
+ * i - bfx lsb literal (bits 7-11)
+ * w - bfx width literal (bits 16-20)
  * b - branch address
  * t - thumb branch address (bits 24, 0-23)
  * k - breakpoint comment (bits 0-3, 8-19)
@@ -124,6 +126,7 @@
     { 0x0fe000f0, 0x00a00090, "umlal",	"Sdnms" },
     { 0x0fe000f0, 0x00e00090, "smlal",	"Sdnms" },
     { 0x0fff03f0, 0x06cf0070, "uxtb16", "dmj" },
+    { 0x0fe00070, 0x07e00050, "ubfx",   "dmiw" },
     { 0x0d700000, 0x04200000, "strt",	"daW" },
     { 0x0d700000, 0x04300000, "ldrt",	"daW" },
     { 0x0d700000, 0x04600000, "strbt",	"daW" },
@@ -412,6 +415,14 @@
 		case 'j':
 			di->di_printf("ror #%d", ((insn >> 10) & 3) << 3);
 			break;
+        /* i - bfx lsb literal (bits 7-11) */
+        case 'i':
+            di->di_printf("#%d", (insn >> 7) & 31);
+            break;
+        /* w - bfx width literal (bits 16-20) */
+        case 'w':
+            di->di_printf("#%d", 1 + ((insn >> 16) & 31));
+            break;
 		/* b - branch address */
 		case 'b':
 			branch = ((insn << 2) & 0x03ffffff);
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
index 93c5825..ed20a00 100644
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ b/libpixelflinger/codeflinger/load_store.cpp
@@ -18,9 +18,12 @@
 #include <assert.h>
 #include <stdio.h>
 #include <cutils/log.h>
-
 #include "codeflinger/GGLAssembler.h"
 
+#ifdef __ARM_ARCH__
+#include <machine/cpu-features.h>
+#endif
+
 namespace android {
 
 // ----------------------------------------------------------------------------
@@ -110,6 +113,20 @@
     assert(maskLen<=8);
     assert(h);
     
+#if __ARM_ARCH__ >= 7
+    const int mask = (1<<maskLen)-1;
+    if ((h == bits) && !l && (s != d.reg)) {
+        MOV(AL, 0, d.reg, s);                   // component = packed;
+    } else if ((h == bits) && l) {
+        MOV(AL, 0, d.reg, reg_imm(s, LSR, l));  // component = packed >> l;
+    } else if (!l && isValidImmediate(mask)) {
+        AND(AL, 0, d.reg, s, imm(mask));        // component = packed & mask;
+    } else if (!l && isValidImmediate(~mask)) {
+        BIC(AL, 0, d.reg, s, imm(~mask));       // component = packed & mask;
+    } else {
+        UBFX(AL, d.reg, s, l, maskLen);         // component = (packed & mask) >> l;
+    }
+#else
     if (h != bits) {
         const int mask = ((1<<maskLen)-1) << l;
         if (isValidImmediate(mask)) {
@@ -132,6 +149,7 @@
     if (s != d.reg) {
         MOV(AL, 0, d.reg, s);
     }
+#endif
 
     d.s = maskLen;
 }
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index fc9cf48..9cd883a 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -19,17 +19,13 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <dirent.h>
+#include <netinet/ether.h>
+
+#include <netutils/ifc.h>
+#include <netutils/dhcp.h>
 
 static int verbose = 0;
 
-int ifc_init();
-void ifc_close();
-int ifc_up(char *iname);
-int ifc_down(char *iname);
-int ifc_remove_host_routes(char *iname);
-int ifc_remove_default_route(char *iname);
-int ifc_get_info(const char *name, unsigned *addr, unsigned *mask, unsigned *flags);
-int do_dhcp(char *iname);
 
 void die(const char *reason)
 {
@@ -37,16 +33,12 @@
     exit(1);
 }
 
-const char *ipaddr(unsigned addr)
+const char *ipaddr(in_addr_t addr)
 {
-    static char buf[32];
-    
-    sprintf(buf,"%d.%d.%d.%d", 
-            addr & 255,
-            ((addr >> 8) & 255),
-            ((addr >> 16) & 255), 
-            (addr >> 24));
-    return buf;
+    struct in_addr in_addr;
+
+    in_addr.s_addr = addr;
+    return inet_ntoa(in_addr);
 }
 
 void usage(void)
@@ -86,6 +78,15 @@
     return 0;
 }
 
+int set_hwaddr(const char *name, const char *asc) {
+    struct ether_addr *addr = ether_aton(asc);
+    if (!addr) {
+        printf("Failed to parse '%s'\n", asc);
+        return -1;
+    }
+    return ifc_set_hwaddr(name, addr->ether_addr_octet);
+}
+
 struct 
 {
     const char *name;
@@ -97,6 +98,7 @@
     { "down",   1, ifc_down },
     { "flhosts",  1, ifc_remove_host_routes },
     { "deldefault", 1, ifc_remove_default_route },
+    { "hwaddr", 2, set_hwaddr },
     { 0, 0, 0 },
 };
 
diff --git a/nexus/DhcpClient.cpp b/nexus/DhcpClient.cpp
index a5654d2..713059d 100644
--- a/nexus/DhcpClient.cpp
+++ b/nexus/DhcpClient.cpp
@@ -27,35 +27,15 @@
 
 #include <sysutils/ServiceManager.h>
 
+#include <netutils/ifc.h>
+#include <netutils/dhcp.h>
+
 #include "DhcpClient.h"
 #include "DhcpState.h"
 #include "DhcpListener.h"
 #include "IDhcpEventHandlers.h"
 #include "Controller.h"
 
-extern "C" {
-int ifc_disable(const char *ifname);
-int ifc_add_host_route(const char *ifname, uint32_t addr);
-int ifc_remove_host_routes(const char *ifname);
-int ifc_set_default_route(const char *ifname, uint32_t gateway);
-int ifc_get_default_route(const char *ifname);
-int ifc_remove_default_route(const char *ifname);
-int ifc_reset_connections(const char *ifname);
-int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2);
-
-int dhcp_do_request(const char *ifname,
-                    in_addr_t *ipaddr,
-                    in_addr_t *gateway,
-                    in_addr_t *mask,
-                    in_addr_t *dns1,
-                    in_addr_t *dns2,
-                    in_addr_t *server,
-                    uint32_t  *lease);
-int dhcp_stop(const char *ifname);
-int dhcp_release_lease(const char *ifname);
-char *dhcp_get_errmsg();
-}
-
 DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) :
             mState(DhcpState::INIT), mHandlers(handlers) {
     mServiceManager = new ServiceManager();
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 8799514..962bf47 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -13,6 +13,130 @@
 #include <grp.h>
 
 #include <linux/kdev_t.h>
+#include <limits.h>
+
+// dynamic arrays
+typedef struct {
+    int count;
+    int capacity;
+    void** items;
+} dynarray_t;
+
+#define DYNARRAY_INITIALIZER  { 0, 0, NULL }
+
+static void dynarray_init( dynarray_t *a )
+{
+    a->count = a->capacity = 0;
+    a->items = NULL;
+}
+
+static void dynarray_reserve_more( dynarray_t *a, int count )
+{
+    int old_cap = a->capacity;
+    int new_cap = old_cap;
+    const int max_cap = INT_MAX/sizeof(void*);
+    void** new_items;
+    int new_count = a->count + count;
+
+    if (count <= 0)
+        return;
+
+    if (count > max_cap - a->count)
+        abort();
+
+    new_count = a->count + count;
+
+    while (new_cap < new_count) {
+        old_cap = new_cap;
+        new_cap += (new_cap >> 2) + 4;
+        if (new_cap < old_cap || new_cap > max_cap) {
+            new_cap = max_cap;
+        }
+    }
+    new_items = realloc(a->items, new_cap*sizeof(void*));
+    if (new_items == NULL)
+        abort();
+
+    a->items = new_items;
+    a->capacity = new_cap;
+}
+
+static void dynarray_append( dynarray_t *a, void* item )
+{
+    if (a->count >= a->capacity)
+        dynarray_reserve_more(a, 1);
+
+    a->items[a->count++] = item;
+}
+
+static void dynarray_done( dynarray_t *a )
+{
+    free(a->items);
+    a->items = NULL;
+    a->count = a->capacity = 0;
+}
+
+#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \
+    do { \
+        int _nn_##__LINE__ = 0; \
+        for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \
+            _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \
+            _stmnt; \
+        } \
+    } while (0)
+
+#define DYNARRAY_FOREACH(_array,_item,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt)
+
+// string arrays
+
+typedef dynarray_t  strlist_t;
+
+#define  STRLIST_INITIALIZER  DYNARRAY_INITIALIZER
+
+#define  STRLIST_FOREACH(_list,_string,_stmnt) \
+    DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt)
+
+static void strlist_init( strlist_t *list )
+{
+    dynarray_init(list);
+}
+
+static void strlist_append_b( strlist_t *list, const void* str, size_t  slen )
+{
+    char *copy = malloc(slen+1);
+    memcpy(copy, str, slen);
+    copy[slen] = '\0';
+    dynarray_append(list, copy);
+}
+
+static void strlist_append_dup( strlist_t *list, const char *str)
+{
+    strlist_append_b(list, str, strlen(str));
+}
+
+static void strlist_done( strlist_t *list )
+{
+    STRLIST_FOREACH(list, string, free(string));
+    dynarray_done(list);
+}
+
+static int strlist_compare_strings(const void* a, const void* b)
+{
+    const char *sa = *(const char **)a;
+    const char *sb = *(const char **)b;
+    return strcmp(sa, sb);
+}
+
+static void strlist_sort( strlist_t *list )
+{
+    if (list->count > 0) {
+        qsort(list->items, 
+              (size_t)list->count,
+              sizeof(void*),
+              strlist_compare_strings);
+    }
+}
 
 // bits for flags argument
 #define LIST_LONG           (1 << 0)
@@ -233,7 +357,8 @@
     char tmp[4096];
     DIR *d;
     struct dirent *de;
-
+    strlist_t  files = STRLIST_INITIALIZER;
+    
     d = opendir(name);
     if(d == 0) {
         fprintf(stderr, "opendir failed, %s\n", strerror(errno));
@@ -248,10 +373,16 @@
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue;
         if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue;
 
-        listfile(name, de->d_name, flags);
+        strlist_append_dup(&files, de->d_name);
     }
 
+    strlist_sort(&files);
+    STRLIST_FOREACH(&files, filename, listfile(name, filename, flags));
+    strlist_done(&files);
+
     if (flags & LIST_RECURSIVE) {
+        strlist_t subdirs = STRLIST_INITIALIZER;
+
         rewinddir(d);
 
         while ((de = readdir(d)) != 0) {
@@ -284,10 +415,15 @@
             }
 
             if (S_ISDIR(s.st_mode)) {
-                printf("\n%s:\n", tmp);
-                listdir(tmp, flags);
+                strlist_append_dup(&subdirs, tmp);
             }
         }
+        strlist_sort(&subdirs);
+        STRLIST_FOREACH(&subdirs, path, {
+            printf("\n%s:\n", path);
+            listdir(path, flags);
+        });
+        strlist_done(&subdirs);
     }
 
     closedir(d);
@@ -331,27 +467,40 @@
     if(argc > 1) {
         int i;
         int err = 0;
+        strlist_t  files = STRLIST_INITIALIZER;
 
         for (i = 1; i < argc; i++) {
-            if (!strcmp(argv[i], "-l")) {
-                flags |= LIST_LONG;
-            } else if (!strcmp(argv[i], "-s")) {
-                flags |= LIST_SIZE;
-            } else if (!strcmp(argv[i], "-a")) {
-                flags |= LIST_ALL;
-            } else if (!strcmp(argv[i], "-R")) {
-                flags |= LIST_RECURSIVE;
-            } else if (!strcmp(argv[i], "-d")) {
-                flags |= LIST_DIRECTORIES;
-            } else {
-                listed++;
-                if(listpath(argv[i], flags) != 0) {
-                    err = EXIT_FAILURE;
+            if (argv[i][0] == '-') {
+                /* an option ? */
+                const char *arg = argv[i]+1;
+                while (arg[0]) {
+                    switch (arg[0]) {
+                    case 'l': flags |= LIST_LONG; break;
+                    case 's': flags |= LIST_SIZE; break;
+                    case 'R': flags |= LIST_RECURSIVE; break;
+                    case 'd': flags |= LIST_DIRECTORIES; break;
+                    case 'a': flags |= LIST_ALL; break;
+                    default:
+                        fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]);
+                        exit(1);
+                    }
+                    arg++;
                 }
+            } else {
+                /* not an option ? */
+                strlist_append_dup(&files, argv[i]);
             }
         }
 
-        if (listed  > 0) return err;
+        if (files.count > 0) {
+            STRLIST_FOREACH(&files, path, {
+                if (listpath(path, flags) != 0) {
+                    err = EXIT_FAILURE;
+                }
+            });
+            strlist_done(&files);
+            return err;
+        }
     }
     
     // list working directory if no files or directories were specified