Merge "adbd: adb root should terminate adbd only if it's debuggable"
diff --git a/adb/Android.mk b/adb/Android.mk
index 62f012c..50e28a6 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -74,7 +74,7 @@
LOCAL_SRC_FILES += fdevent.c
endif
-LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter -Werror
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE := adb
LOCAL_MODULE_TAGS := debug
@@ -116,7 +116,7 @@
remount_service.c \
usb_linux_client.c
-LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
+LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
@@ -138,8 +138,6 @@
ifneq ($(SDK_ONLY),true)
include $(CLEAR_VARS)
-LOCAL_LDLIBS := -lrt -ldl -lpthread
-
LOCAL_SRC_FILES := \
adb.c \
console.c \
@@ -162,8 +160,7 @@
-g \
-DADB_HOST=1 \
-DADB_HOST_ON_TARGET=1 \
- -Wall \
- -Wno-unused-parameter \
+ -Wall -Wno-unused-parameter -Werror \
-D_XOPEN_SOURCE \
-D_GNU_SOURCE
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 7f85dc3..63000f2 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -240,3 +240,20 @@
This starts the file synchronisation service, used to implement "adb push"
and "adb pull". Since this service is pretty complex, it will be detailed
in a companion document named SYNC.TXT
+
+reverse:<forward-command>
+ This implements the 'adb reverse' feature, i.e. the ability to reverse
+ socket connections from a device to the host. <forward-command> is one
+ of the forwarding commands that are described above, as in:
+
+ list-forward
+ forward:<local>;<remote>
+ forward:norebind:<local>;<remote>
+ killforward-all
+ killforward:<local>
+
+ Note that in this case, <local> corresponds to the socket on the device
+ and <remote> corresponds to the socket on the host.
+
+ The output of reverse:list-forward is the same as host:list-forward
+ except that <serial> will be just 'host'.
diff --git a/adb/adb.c b/adb/adb.c
index 0e41b34..90bdbaa 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -318,7 +318,18 @@
#endif
}
-static void send_msg_with_okay(int fd, char* msg, size_t msglen) {
+#if !ADB_HOST
+static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
+ char header[5];
+ if (msglen > 0xffff)
+ msglen = 0xffff;
+ snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
+ writex(fd, header, 4);
+ writex(fd, msg, msglen);
+}
+#endif
+
+static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
char header[9];
if (msglen > 0xffff)
msglen = 0xffff;
@@ -1333,30 +1344,29 @@
" unchanged.\n");
}
+ /* add extra groups:
+ ** AID_ADB to access the USB driver
+ ** AID_LOG to read system logs (adb logcat)
+ ** AID_INPUT to diagnose input issues (getevent)
+ ** AID_INET to diagnose network issues (netcfg, ping)
+ ** AID_GRAPHICS to access the frame buffer
+ ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+ ** AID_SDCARD_R to allow reading from the SD card
+ ** AID_SDCARD_RW to allow writing to the SD card
+ ** AID_NET_BW_STATS to read out qtaguid statistics
+ */
+ gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
+ AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
+ AID_NET_BW_STATS };
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
+ exit(1);
+ }
+
/* don't listen on a port (default 5037) if running in secure mode */
/* don't run as root if we are running in secure mode */
if (should_drop_privileges()) {
drop_capabilities_bounding_set_if_needed();
- /* add extra groups:
- ** AID_ADB to access the USB driver
- ** AID_LOG to read system logs (adb logcat)
- ** AID_INPUT to diagnose input issues (getevent)
- ** AID_INET to diagnose network issues (netcfg, ping)
- ** AID_GRAPHICS to access the frame buffer
- ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
- ** AID_SDCARD_R to allow reading from the SD card
- ** AID_SDCARD_RW to allow writing to the SD card
- ** AID_MOUNT to allow unmounting the SD card before rebooting
- ** AID_NET_BW_STATS to read out qtaguid statistics
- */
- gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS,
- AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
- AID_MOUNT, AID_NET_BW_STATS };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- exit(1);
- }
-
/* then switch user and group to "shell" */
if (setgid(AID_SHELL) != 0) {
exit(1);
@@ -1428,6 +1438,120 @@
return 0;
}
+// Try to handle a network forwarding request.
+// This returns 1 on success, 0 on failure, and -1 to indicate this is not
+// a forwarding-related request.
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+{
+ if (!strcmp(service, "list-forward")) {
+ // Create the list of forward redirections.
+ int buffer_size = format_listeners(NULL, 0);
+ // Add one byte for the trailing zero.
+ char* buffer = malloc(buffer_size + 1);
+ if (buffer == NULL) {
+ sendfailmsg(reply_fd, "not enough memory");
+ return 1;
+ }
+ (void) format_listeners(buffer, buffer_size + 1);
+#if ADB_HOST
+ send_msg_with_okay(reply_fd, buffer, buffer_size);
+#else
+ send_msg_with_header(reply_fd, buffer, buffer_size);
+#endif
+ free(buffer);
+ return 1;
+ }
+
+ if (!strcmp(service, "killforward-all")) {
+ remove_all_listeners();
+#if ADB_HOST
+ /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ adb_write(reply_fd, "OKAY", 4);
+#endif
+ adb_write(reply_fd, "OKAY", 4);
+ return 1;
+ }
+
+ if (!strncmp(service, "forward:",8) ||
+ !strncmp(service, "killforward:",12)) {
+ char *local, *remote, *err;
+ int r;
+ atransport *transport;
+
+ int createForward = strncmp(service, "kill", 4);
+ int no_rebind = 0;
+
+ local = strchr(service, ':') + 1;
+
+ // Handle forward:norebind:<local>... here
+ if (createForward && !strncmp(local, "norebind:", 9)) {
+ no_rebind = 1;
+ local = strchr(local, ':') + 1;
+ }
+
+ remote = strchr(local,';');
+
+ if (createForward) {
+ // Check forward: parameter format: '<local>;<remote>'
+ if(remote == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+
+ *remote++ = 0;
+ if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+ } else {
+ // Check killforward: parameter format: '<local>'
+ if (local[0] == 0) {
+ sendfailmsg(reply_fd, "malformed forward spec");
+ return 1;
+ }
+ }
+
+ transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+ if (!transport) {
+ sendfailmsg(reply_fd, err);
+ return 1;
+ }
+
+ if (createForward) {
+ r = install_listener(local, remote, transport, no_rebind);
+ } else {
+ r = remove_listener(local, transport);
+ }
+ if(r == 0) {
+#if ADB_HOST
+ /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ writex(reply_fd, "OKAY", 4);
+#endif
+ writex(reply_fd, "OKAY", 4);
+ return 1;
+ }
+
+ if (createForward) {
+ const char* message;
+ switch (r) {
+ case INSTALL_STATUS_CANNOT_BIND:
+ message = "cannot bind to socket";
+ break;
+ case INSTALL_STATUS_CANNOT_REBIND:
+ message = "cannot rebind existing socket";
+ break;
+ default:
+ message = "internal error";
+ }
+ sendfailmsg(reply_fd, message);
+ } else {
+ sendfailmsg(reply_fd, "cannot remove listener");
+ }
+ return 1;
+ }
+ return 0;
+}
+
int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
{
atransport *transport = NULL;
@@ -1548,97 +1672,9 @@
}
#endif // ADB_HOST
- if(!strcmp(service,"list-forward")) {
- // Create the list of forward redirections.
- int buffer_size = format_listeners(NULL, 0);
- // Add one byte for the trailing zero.
- char* buffer = malloc(buffer_size+1);
- (void) format_listeners(buffer, buffer_size+1);
- send_msg_with_okay(reply_fd, buffer, buffer_size);
- free(buffer);
- return 0;
- }
-
- if (!strcmp(service,"killforward-all")) {
- remove_all_listeners();
- adb_write(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- if(!strncmp(service,"forward:",8) ||
- !strncmp(service,"killforward:",12)) {
- char *local, *remote, *err;
- int r;
- atransport *transport;
-
- int createForward = strncmp(service,"kill",4);
- int no_rebind = 0;
-
- local = strchr(service, ':') + 1;
-
- // Handle forward:norebind:<local>... here
- if (createForward && !strncmp(local, "norebind:", 9)) {
- no_rebind = 1;
- local = strchr(local, ':') + 1;
- }
-
- remote = strchr(local,';');
-
- if (createForward) {
- // Check forward: parameter format: '<local>;<remote>'
- if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')){
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
- } else {
- // Check killforward: parameter format: '<local>'
- if (local[0] == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
- return 0;
- }
- }
-
- transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
- if (!transport) {
- sendfailmsg(reply_fd, err);
- return 0;
- }
-
- if (createForward) {
- r = install_listener(local, remote, transport, no_rebind);
- } else {
- r = remove_listener(local, transport);
- }
- if(r == 0) {
- /* 1st OKAY is connect, 2nd OKAY is status */
- writex(reply_fd, "OKAYOKAY", 8);
- return 0;
- }
-
- if (createForward) {
- const char* message;
- switch (r) {
- case INSTALL_STATUS_CANNOT_BIND:
- message = "cannot bind to socket";
- break;
- case INSTALL_STATUS_CANNOT_REBIND:
- message = "cannot rebind existing socket";
- break;
- default:
- message = "internal error";
- }
- sendfailmsg(reply_fd, message);
- } else {
- sendfailmsg(reply_fd, "cannot remove listener");
- }
- return 0;
- }
+ int ret = handle_forward_request(service, ttype, serial, reply_fd);
+ if (ret >= 0)
+ return ret - 1;
if(!strncmp(service,"get-state",strlen("get-state"))) {
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
diff --git a/adb/adb.h b/adb/adb.h
index 6f5c93c..2504f99 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -323,6 +323,8 @@
int create_jdwp_connection_fd(int jdwp_pid);
#endif
+int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+
#if !ADB_HOST
typedef enum {
BACKUP,
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
index 9039d42..783774a 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.c
@@ -159,13 +159,13 @@
bio = BIO_push(b64, bfile);
BIO_write(bio, &pkey, sizeof(pkey));
- BIO_flush(bio);
+ (void) BIO_flush(bio);
BIO_pop(b64);
BIO_free(b64);
get_user_info(info, sizeof(info));
BIO_write(bfile, info, strlen(info));
- BIO_flush(bfile);
+ (void) BIO_flush(bfile);
BIO_free_all(bfile);
return 1;
diff --git a/adb/backup_service.c b/adb/backup_service.c
index 669ff86..654e0f3 100644
--- a/adb/backup_service.c
+++ b/adb/backup_service.c
@@ -52,15 +52,12 @@
pid_t pid;
int s[2];
char* operation;
- int socketnum;
- // Command string and choice of stdin/stdout for the pipe depend on our invocation
+ // Command string depends on our invocation
if (op == BACKUP) {
operation = "backup";
- socketnum = STDOUT_FILENO;
} else {
operation = "restore";
- socketnum = STDIN_FILENO;
}
D("backup_service(%s, %s)\n", operation, args);
diff --git a/adb/commandline.c b/adb/commandline.c
index 83b568d..18dc6e0 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -136,6 +136,19 @@
" if <local> is already forwarded\n"
" adb forward --remove <local> - remove a specific forward socket connection\n"
" adb forward --remove-all - remove all forward socket connections\n"
+ " adb reverse --list - list all reverse socket connections from device\n"
+ " adb reverse <remote> <local> - reverse socket connections\n"
+ " reverse specs are one of:\n"
+ " tcp:<port>\n"
+ " localabstract:<unix domain socket name>\n"
+ " localreserved:<unix domain socket name>\n"
+ " localfilesystem:<unix domain socket name>\n"
+ " adb reverse --norebind <remote> <local>\n"
+ " - same as 'adb reverse <remote> <local>' but fails\n"
+ " if <remote> is already reversed.\n"
+ " adb reverse --remove <remote>\n"
+ " - remove a specific reversed socket connection\n"
+ " adb reverse --remove-all - remove all reversed socket connections from device\n"
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
" adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
" - push this package file to the device and install it\n"
@@ -406,7 +419,7 @@
}
int opt = CHUNK_SIZE;
- opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
+ opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
total = sz;
ptr = data;
@@ -681,10 +694,10 @@
return 0;
}
-static int mkdirs(char *path)
+static int mkdirs(const char *path)
{
int ret;
- char *x = path + 1;
+ char *x = (char *)path + 1;
for(;;) {
x = adb_dirstart(x);
@@ -727,7 +740,7 @@
if (argc < 2) return usage();
adb_unlink(filename);
- mkdirs((char *)filename);
+ mkdirs(filename);
outFd = adb_creat(filename, 0640);
if (outFd < 0) {
fprintf(stderr, "adb: unable to open file %s\n", filename);
@@ -1299,8 +1312,11 @@
return 0;
}
- if(!strcmp(argv[0], "forward")) {
+ if(!strcmp(argv[0], "forward") ||
+ !strcmp(argv[0], "reverse"))
+ {
char host_prefix[64];
+ char reverse = (char) !strcmp(argv[0], "reverse");
char remove = 0;
char remove_all = 0;
char list = 0;
@@ -1329,15 +1345,19 @@
}
// Determine the <host-prefix> for this command.
- if (serial) {
- snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
- serial);
- } else if (ttype == kTransportUsb) {
- snprintf(host_prefix, sizeof host_prefix, "host-usb");
- } else if (ttype == kTransportLocal) {
- snprintf(host_prefix, sizeof host_prefix, "host-local");
+ if (reverse) {
+ snprintf(host_prefix, sizeof host_prefix, "reverse");
} else {
- snprintf(host_prefix, sizeof host_prefix, "host");
+ if (serial) {
+ snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
+ serial);
+ } else if (ttype == kTransportUsb) {
+ snprintf(host_prefix, sizeof host_prefix, "host-usb");
+ } else if (ttype == kTransportLocal) {
+ snprintf(host_prefix, sizeof host_prefix, "host-local");
+ } else {
+ snprintf(host_prefix, sizeof host_prefix, "host");
+ }
}
// Implement forward --list
@@ -1723,6 +1743,8 @@
} else if (!strcmp(argv[i], "--key")) {
verify_apk = 0;
i++;
+ } else if (!strcmp(argv[i], "--abi")) {
+ i++;
}
}
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 8fad50e..dc4e77f 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -456,10 +456,10 @@
return -1;
}
-static int mkdirs(char *name)
+static int mkdirs(const char *name)
{
int ret;
- char *x = name + 1;
+ char *x = (char *)name + 1;
for(;;) {
x = adb_dirstart(x);
@@ -521,7 +521,7 @@
if((id == ID_DATA) || (id == ID_DONE)) {
adb_unlink(lpath);
- mkdirs((char *)lpath);
+ mkdirs(lpath);
lfd = adb_creat(lpath, 0644);
if(lfd < 0) {
fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c
index fa7fd98..8cbe840 100644
--- a/adb/framebuffer_service.c
+++ b/adb/framebuffer_service.c
@@ -61,7 +61,7 @@
int w, h, f;
int fds[2];
- if (pipe(fds) < 0) goto pipefail;
+ if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail;
pid_t pid = fork();
if (pid < 0) goto done;
diff --git a/adb/remount_service.c b/adb/remount_service.c
index ad61284..d3a649b 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/mount.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <unistd.h>
#include "sysdeps.h"
@@ -35,7 +35,6 @@
{
int fd;
int res;
- int size;
char *token = NULL;
const char delims[] = "\n";
char buf[4096];
@@ -45,7 +44,7 @@
return NULL;
buf[sizeof(buf) - 1] = '\0';
- size = adb_read(fd, buf, sizeof(buf) - 1);
+ adb_read(fd, buf, sizeof(buf) - 1);
adb_close(fd);
token = strtok(buf, delims);
diff --git a/adb/services.c b/adb/services.c
index 5b63a43..7b809da 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -116,23 +116,10 @@
{
char buf[100];
char property_val[PROPERTY_VALUE_MAX];
- int pid, ret;
+ int ret;
sync();
- /* Attempt to unmount the SD card first.
- * No need to bother checking for errors.
- */
- pid = fork();
- if (pid == 0) {
- /* ask vdc to unmount it */
- execl("/system/bin/vdc", "/system/bin/vdc", "volume", "unmount",
- getenv("EXTERNAL_STORAGE"), "force", NULL);
- } else if (pid > 0) {
- /* wait until vdc succeeds or fails */
- waitpid(pid, &ret, 0);
- }
-
ret = snprintf(property_val, sizeof(property_val), "reboot,%s", (char *) arg);
if (ret >= (int) sizeof(property_val)) {
snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
@@ -154,6 +141,17 @@
adb_close(fd);
}
+void reverse_service(int fd, void* arg)
+{
+ const char* command = arg;
+
+ if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
+ sendfailmsg(fd, "not a reverse forwarding command");
+ }
+ free(arg);
+ adb_close(fd);
+}
+
#endif
static int create_service_thread(void (*func)(int, void *), void *cookie)
@@ -398,6 +396,16 @@
ret = create_service_thread(restart_tcp_service, (void *) (uintptr_t) port);
} else if(!strncmp(name, "usb:", 4)) {
ret = create_service_thread(restart_usb_service, NULL);
+ } else if (!strncmp(name, "reverse:", 8)) {
+ char* cookie = strdup(name + 8);
+ if (cookie == NULL) {
+ ret = -1;
+ } else {
+ ret = create_service_thread(reverse_service, cookie);
+ if (ret < 0) {
+ free(cookie);
+ }
+ }
#endif
}
if (ret >= 0) {
@@ -460,7 +468,7 @@
snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
- fd = socket_network_client(hostbuf, port, SOCK_STREAM);
+ fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
if (fd < 0) {
snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
return;
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 4033b72..ba4306f 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -169,6 +169,8 @@
/* normally provided by <cutils/sockets.h> */
extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+ int timeout);
extern int socket_loopback_server(int port, int type);
extern int socket_inaddr_any_server(int port, int type);
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 2105b16..29f58ec 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -701,6 +701,13 @@
}
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
+ // TODO: implement timeouts for Windows.
+ return socket_network_client(host, port, type);
+}
+
+
int socket_inaddr_any_server(int port, int type)
{
FH f = _fh_alloc( &_fh_socket_class );
@@ -956,7 +963,7 @@
avail = len;
memcpy( bip->buff + bip->a_end, src, avail );
- src += avail;
+ src = (const char *)src + avail;
count += avail;
len -= avail;
@@ -1049,7 +1056,7 @@
avail = len;
memcpy( dst, bip->buff + bip->a_start, avail );
- dst += avail;
+ dst = (char *)dst + avail;
count += avail;
len -= avail;
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 0c46a0c..957e5db 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -51,7 +51,9 @@
// BYD's USB Vendor ID
#define VENDOR_ID_BYD 0x1D91
// Compal's USB Vendor ID
-#define VENDOR_ID_COMPAL 0x1219
+#define VENDOR_ID_COMPAL 0x04B7
+// Compalcomm's USB Vendor ID
+#define VENDOR_ID_COMPALCOMM 0x1219
// Dell's USB Vendor ID
#define VENDOR_ID_DELL 0x413c
// ECS's USB Vendor ID
@@ -72,6 +74,8 @@
#define VENDOR_ID_GIGABYTE 0x0414
// Gigaset's USB Vendor ID
#define VENDOR_ID_GIGASET 0x1E85
+// GIONEE's USB Vendor ID
+#define VENDOR_ID_GIONEE 0x271D
// Google's USB Vendor ID
#define VENDOR_ID_GOOGLE 0x18d1
// Haier's USB Vendor ID
@@ -80,6 +84,8 @@
#define VENDOR_ID_HARRIS 0x19A5
// Hisense's USB Vendor ID
#define VENDOR_ID_HISENSE 0x109b
+// Honeywell's USB Vendor ID
+#define VENDOR_ID_HONEYWELL 0x0c2e
// HP's USB Vendor ID
#define VENDOR_ID_HP 0x03f0
// HTC's USB Vendor ID
@@ -156,6 +162,8 @@
#define VENDOR_ID_SHARP 0x04dd
// SK Telesys's USB Vendor ID
#define VENDOR_ID_SK_TELESYS 0x1F53
+// Smartisan's USB Vendor ID
+#define VENDOR_ID_SMARTISAN 0x29a9
// Sony's USB Vendor ID
#define VENDOR_ID_SONY 0x054C
// Sony Ericsson's USB Vendor ID
@@ -170,6 +178,8 @@
#define VENDOR_ID_TI 0x0451
// Toshiba's USB Vendor ID
#define VENDOR_ID_TOSHIBA 0x0930
+// Unowhy's USB Vendor ID
+#define VENDOR_ID_UNOWHY 0x2A49
// Vizio's USB Vendor ID
#define VENDOR_ID_VIZIO 0xE040
// Wacom's USB Vendor ID
@@ -195,6 +205,7 @@
VENDOR_ID_ASUS,
VENDOR_ID_BYD,
VENDOR_ID_COMPAL,
+ VENDOR_ID_COMPALCOMM,
VENDOR_ID_DELL,
VENDOR_ID_ECS,
VENDOR_ID_EMERGING_TECH,
@@ -205,10 +216,12 @@
VENDOR_ID_GARMIN_ASUS,
VENDOR_ID_GIGABYTE,
VENDOR_ID_GIGASET,
+ VENDOR_ID_GIONEE,
VENDOR_ID_GOOGLE,
VENDOR_ID_HAIER,
VENDOR_ID_HARRIS,
VENDOR_ID_HISENSE,
+ VENDOR_ID_HONEYWELL,
VENDOR_ID_HP,
VENDOR_ID_HTC,
VENDOR_ID_HUAWEI,
@@ -247,6 +260,7 @@
VENDOR_ID_SAMSUNG,
VENDOR_ID_SHARP,
VENDOR_ID_SK_TELESYS,
+ VENDOR_ID_SMARTISAN,
VENDOR_ID_SONY,
VENDOR_ID_SONY_ERICSSON,
VENDOR_ID_T_AND_A,
@@ -254,6 +268,7 @@
VENDOR_ID_TELEEPOCH,
VENDOR_ID_TI,
VENDOR_ID_TOSHIBA,
+ VENDOR_ID_UNOWHY,
VENDOR_ID_VIZIO,
VENDOR_ID_WACOM,
VENDOR_ID_XIAOMI,
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 4936b77..1309a78 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -310,14 +310,14 @@
int xfer = (len > 4096) ? 4096 : len;
ret = AdbReadEndpointSync(handle->adb_read_pipe,
- (void*)data,
+ data,
(unsigned long)xfer,
&read,
time_out);
int saved_errno = GetLastError();
D("usb_write got: %ld, expected: %d, errno: %d\n", read, xfer, saved_errno);
if (ret) {
- data += read;
+ data = (char *)data + read;
len -= read;
if (len == 0)
diff --git a/adf/libadf/adf.c b/adf/libadf/adf.c
index 871629e..1d19152 100644
--- a/adf/libadf/adf.c
+++ b/adf/libadf/adf.c
@@ -768,7 +768,7 @@
const __u32 *formats, size_t n_formats,
adf_id_t *interface, adf_id_t *overlay_engine)
{
- adf_id_t *intfs;
+ adf_id_t *intfs = NULL;
ssize_t n_intfs = adf_interfaces(dev, &intfs);
if (n_intfs < 0)
diff --git a/charger/charger.c b/charger/charger.c
index e3cadb1..47b1c07 100644
--- a/charger/charger.c
+++ b/charger/charger.c
@@ -40,6 +40,7 @@
#include <cutils/list.h>
#include <cutils/misc.h>
#include <cutils/uevent.h>
+#include <cutils/properties.h>
#ifdef CHARGER_ENABLE_SUSPEND
#include <suspend/autosuspend.h>
@@ -750,24 +751,33 @@
/* schedule next screen transition */
charger->next_screen_transition = now + disp_time;
- /* advance frame cntr to the next valid frame
+ /* advance frame cntr to the next valid frame only if we are charging
* if necessary, advance cycle cntr, and reset frame cntr
*/
- batt_anim->cur_frame++;
-
- /* if the frame is used for level-only, that is only show it when it's
- * the current level, skip it during the animation.
- */
- while (batt_anim->cur_frame < batt_anim->num_frames &&
- batt_anim->frames[batt_anim->cur_frame].level_only)
+ if (charger->num_supplies_online != 0) {
batt_anim->cur_frame++;
- if (batt_anim->cur_frame >= batt_anim->num_frames) {
- batt_anim->cur_cycle++;
- batt_anim->cur_frame = 0;
+
+ /* if the frame is used for level-only, that is only show it when it's
+ * the current level, skip it during the animation.
+ */
+ while (batt_anim->cur_frame < batt_anim->num_frames &&
+ batt_anim->frames[batt_anim->cur_frame].level_only)
+ batt_anim->cur_frame++;
+ if (batt_anim->cur_frame >= batt_anim->num_frames) {
+ batt_anim->cur_cycle++;
+ batt_anim->cur_frame = 0;
/* don't reset the cycle counter, since we use that as a signal
* in a test above to check if animation is over
*/
+ }
+ } else {
+ /* Stop animating if we're not charging.
+ * If we stop it immediately instead of going through this loop, then
+ * the animation would stop somewhere in the middle.
+ */
+ batt_anim->cur_frame = 0;
+ batt_anim->cur_cycle++;
}
}
@@ -830,8 +840,16 @@
if (key->down) {
int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
if (now >= reboot_timeout) {
- LOGI("[%lld] rebooting\n", now);
- android_reboot(ANDROID_RB_RESTART, 0, 0);
+ /* We do not currently support booting from charger mode on
+ all devices. Check the property and continue booting or reboot
+ accordingly. */
+ if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+ LOGI("[%lld] booting from charger mode\n", now);
+ property_set("sys.boot_from_charger_mode", "1");
+ } else {
+ LOGI("[%lld] rebooting\n", now);
+ android_reboot(ANDROID_RB_RESTART, 0, 0);
+ }
} else {
/* if the key is pressed but timeout hasn't expired,
* make sure we wake up at the right-ish time to check
diff --git a/cpio/Android.mk b/cpio/Android.mk
index 5184463..575beb2 100644
--- a/cpio/Android.mk
+++ b/cpio/Android.mk
@@ -8,6 +8,8 @@
LOCAL_MODULE := mkbootfs
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE))
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7d3740c..7175749 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -78,8 +78,9 @@
s->st_mode = empty_path_config->mode | (s->st_mode & ~07777);
} else {
// Use the compiled-in fs_config() function.
-
- fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities);
+ unsigned st_mode = s->st_mode;
+ fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+ s->st_mode = (typeof(s->st_mode)) st_mode;
}
}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index f6d8f0c..c33b263 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -3,39 +3,30 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- backtrace.cpp \
- debuggerd.cpp \
- getevent.cpp \
- tombstone.cpp \
- utility.cpp \
+ backtrace.cpp \
+ debuggerd.cpp \
+ getevent.cpp \
+ tombstone.cpp \
+ utility.cpp \
LOCAL_SRC_FILES_arm := arm/machine.cpp
LOCAL_SRC_FILES_arm64 := arm64/machine.cpp
LOCAL_SRC_FILES_mips := mips/machine.cpp
+LOCAL_SRC_FILES_mips64 := mips/machine.cpp
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
-LOCAL_CONLYFLAGS := -std=gnu99
-LOCAL_CPPFLAGS := -std=gnu++11
-LOCAL_CFLAGS := \
- -Wall \
- -Wno-array-bounds \
- -Werror \
- -Wno-unused-parameter \
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP
-endif # ARCH_ARM_HAVE_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
+LOCAL_CPPFLAGS := \
+ -std=gnu++11 \
+ -W -Wall -Wextra \
+ -Wunused \
+ -Werror \
LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- libc \
- libcutils \
- liblog \
- libselinux \
+ libbacktrace \
+ libcutils \
+ liblog \
+ libselinux \
include external/stlport/libstlport.mk
@@ -43,51 +34,34 @@
LOCAL_MODULE_STEM_32 := debuggerd
LOCAL_MODULE_STEM_64 := debuggerd64
LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
include $(BUILD_EXECUTABLE)
+
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES := crasher.c
LOCAL_SRC_FILES_arm := arm/crashglue.S
LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
LOCAL_SRC_FILES_mips := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips/crashglue.S
LOCAL_SRC_FILES_x86 := x86/crashglue.S
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Wno-unused-parameter -Wno-free-nonheap-object
+LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
LOCAL_MODULE := crasher
LOCAL_MODULE_STEM_32 := crasher
LOCAL_MODULE_STEM_64 := crasher64
LOCAL_MULTILIB := both
include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-ifeq ($(ARCH_ARM_HAVE_VFP),true)
-LOCAL_MODULE_TARGET_ARCH += arm
-LOCAL_SRC_FILES_arm := arm/vfp.S
-LOCAL_CFLAGS_arm += -DWITH_VFP
-ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
-LOCAL_CFLAGS_arm += -DWITH_VFP_D32
-endif # ARCH_ARM_HAVE_VFP_D32
-endif # ARCH_ARM_HAVE_VFP == true
-
-LOCAL_SRC_FILES_arm64 := arm64/vfp.S
-LOCAL_MODULE_TARGET_ARCH += arm64
-
-LOCAL_SRC_FILES := vfp-crasher.c
-LOCAL_MODULE := vfp-crasher
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
-
-LOCAL_MODULE_STEM_32 := vfp-crasher
-LOCAL_MODULE_STEM_64 := vfp-crasher64
-LOCAL_MULTILIB := both
-
-include $(BUILD_EXECUTABLE)
diff --git a/debuggerd/arm/crashglue.S b/debuggerd/arm/crashglue.S
index eb9d0e3..4fbfd6e 100644
--- a/debuggerd/arm/crashglue.S
+++ b/debuggerd/arm/crashglue.S
@@ -1,8 +1,5 @@
.globl crash1
.type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
crash1:
ldr r0, =0xa5a50000
ldr r1, =0xa5a50001
@@ -18,11 +15,48 @@
ldr r11, =0xa5a50011
ldr r12, =0xa5a50012
+
+ fconstd d0, #0
+ fconstd d1, #1
+ fconstd d2, #2
+ fconstd d3, #3
+ fconstd d4, #4
+ fconstd d5, #5
+ fconstd d6, #6
+ fconstd d7, #7
+ fconstd d8, #8
+ fconstd d9, #9
+ fconstd d10, #10
+ fconstd d11, #11
+ fconstd d12, #12
+ fconstd d13, #13
+ fconstd d14, #14
+ fconstd d15, #15
+#if defined(HAS_VFP_D32)
+ fconstd d16, #16
+ fconstd d17, #17
+ fconstd d18, #18
+ fconstd d19, #19
+ fconstd d20, #20
+ fconstd d21, #21
+ fconstd d22, #22
+ fconstd d23, #23
+ fconstd d24, #24
+ fconstd d25, #25
+ fconstd d26, #26
+ fconstd d27, #27
+ fconstd d28, #28
+ fconstd d29, #29
+ fconstd d30, #30
+ fconstd d31, #31
+#endif
+
mov lr, #0
ldr lr, [lr]
b .
-
+.globl crashnostack
+.type crashnostack, %function
crashnostack:
mov sp, #0
mov r0, #0
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index fd2f69b..8270066 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -27,87 +27,68 @@
#include "../utility.h"
#include "../machine.h"
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-#ifdef WITH_VFP
-#ifdef WITH_VFP_D32
-#define NUM_VFP_REGS 32
-#else
-#define NUM_VFP_REGS 16
-#endif
-#endif
-
-// If configured to do so, dump memory around *all* registers
-// for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
- struct pt_regs regs;
+void dump_memory_and_code(log_t* log, pid_t tid) {
+ pt_regs regs;
if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
+ static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
- for (int reg = 0; reg < 14; reg++) {
- // this may not be a valid way to access, but it'll do for now
- uintptr_t addr = regs.uregs[reg];
+ for (int reg = 0; reg < 14; reg++) {
+ // this may not be a valid way to access, but it'll do for now
+ uintptr_t addr = regs.uregs[reg];
- // Don't bother if it looks like a small int or ~= null, or if
- // it's in the kernel area.
- if (addr < 4096 || addr >= 0xc0000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0xc0000000) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr);
}
// explicitly allow upload of code dump logging
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
if (regs.ARM_pc != regs.ARM_lr) {
- _LOG(log, scope_flags, "\ncode around lr:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
+ dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
- struct pt_regs r;
+void dump_registers(log_t* log, pid_t tid) {
+ pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
- _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
- _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n",
+ _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n",
static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
- _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
+ _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
static_cast<uint32_t>(r.ARM_cpsr));
-#ifdef WITH_VFP
- struct user_vfp vfp_regs;
- int i;
-
+ user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
return;
}
- for (i = 0; i < NUM_VFP_REGS; i += 2) {
- _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n",
+ for (size_t i = 0; i < 32; i += 2) {
+ _LOG(log, logtype::REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
}
- _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr);
-#endif
+ _LOG(log, logtype::REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
}
diff --git a/debuggerd/arm/vfp.S b/debuggerd/arm/vfp.S
deleted file mode 100644
index 9744f6f..0000000
--- a/debuggerd/arm/vfp.S
+++ /dev/null
@@ -1,43 +0,0 @@
- .text
- .align 2
- .global crash
- .type crash, %function
-crash:
- fconstd d0, #0
- fconstd d1, #1
- fconstd d2, #2
- fconstd d3, #3
- fconstd d4, #4
- fconstd d5, #5
- fconstd d6, #6
- fconstd d7, #7
- fconstd d8, #8
- fconstd d9, #9
- fconstd d10, #10
- fconstd d11, #11
- fconstd d12, #12
- fconstd d13, #13
- fconstd d14, #14
- fconstd d15, #15
-#ifdef WITH_VFP_D32
- fconstd d16, #16
- fconstd d17, #17
- fconstd d18, #18
- fconstd d19, #19
- fconstd d20, #20
- fconstd d21, #21
- fconstd d22, #22
- fconstd d23, #23
- fconstd d24, #24
- fconstd d25, #25
- fconstd d26, #26
- fconstd d27, #27
- fconstd d28, #28
- fconstd d29, #29
- fconstd d30, #30
- fconstd d31, #31
-#endif
- mov r0, #0
- str r0, [r0]
- bx lr
-
diff --git a/debuggerd/arm64/crashglue.S b/debuggerd/arm64/crashglue.S
index b06b67c..e58b542 100644
--- a/debuggerd/arm64/crashglue.S
+++ b/debuggerd/arm64/crashglue.S
@@ -1,8 +1,5 @@
.globl crash1
.type crash1, %function
-.globl crashnostack
-.type crashnostack, %function
-
crash1:
ldr x0, =0xa5a50000
ldr x1, =0xa5a50001
@@ -35,11 +32,46 @@
ldr x28, =0xa5a50028
ldr x29, =0xa5a50029
+ fmov d0, -1.0 // -1 is more convincing than 0.
+ fmov d1, 1.0
+ fmov d2, 2.0
+ fmov d3, 3.0
+ fmov d4, 4.0
+ fmov d5, 5.0
+ fmov d6, 6.0
+ fmov d7, 7.0
+ fmov d8, 8.0
+ fmov d9, 9.0
+ fmov d10, 10.0
+ fmov d11, 11.0
+ fmov d12, 12.0
+ fmov d13, 13.0
+ fmov d14, 14.0
+ fmov d15, 15.0
+ fmov d16, 16.0
+ fmov d17, 17.0
+ fmov d18, 18.0
+ fmov d19, 19.0
+ fmov d20, 20.0
+ fmov d21, 21.0
+ fmov d22, 22.0
+ fmov d23, 23.0
+ fmov d24, 24.0
+ fmov d25, 25.0
+ fmov d26, 26.0
+ fmov d27, 27.0
+ fmov d28, 28.0
+ fmov d29, 29.0
+ fmov d30, 30.0
+ fmov d31, 31.0
+
mov x30, xzr
ldr x30, [x30]
b .
+.globl crashnostack
+.type crashnostack, %function
crashnostack:
mov x0, xzr
add sp, x0, xzr
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 7159228..ec664bd 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -30,77 +30,66 @@
#include "../utility.h"
#include "../machine.h"
-/* enable to dump memory pointed to by every register */
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
-/*
- * If configured to do so, dump memory around *all* registers
- * for the crashing thread.
- */
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
struct user_pt_regs regs;
struct iovec io;
io.iov_base = ®s;
io.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
- _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n",
+ _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
__func__, strerror(errno));
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- for (int reg = 0; reg < 31; reg++) {
- uintptr_t addr = regs.regs[reg];
+ for (int reg = 0; reg < 31; reg++) {
+ uintptr_t addr = regs.regs[reg];
- /*
- * Don't bother if it looks like a small int or ~= null, or if
- * it's in the kernel area.
- */
- if (addr < 4096 || addr >= (1UL<<63)) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ /*
+ * Don't bother if it looks like a small int or ~= null, or if
+ * it's in the kernel area.
+ */
+ if (addr < 4096 || addr >= (1UL<<63)) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
+ dump_memory(log, tid, addr);
}
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)regs.pc);
if (regs.pc != regs.sp) {
- _LOG(log, scope_flags, "\ncode around sp:\n");
- dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
+ dump_memory(log, tid, (uintptr_t)regs.sp);
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags)
-{
+void dump_registers(log_t* log, pid_t tid) {
struct user_pt_regs r;
struct iovec io;
io.iov_base = &r;
io.iov_len = sizeof(r);
- bool only_in_tombstone = !IS_AT_FAULT(scope_flags);
-
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
- _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
for (int i = 0; i < 28; i += 4) {
- _LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
+ _LOG(log, logtype::REGISTERS,
+ " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n",
i, (uint64_t)r.regs[i],
i+1, (uint64_t)r.regs[i+1],
i+2, (uint64_t)r.regs[i+2],
i+3, (uint64_t)r.regs[i+3]);
}
- _LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " x28 %016lx x29 %016lx x30 %016lx\n",
(uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
- _LOG(log, scope_flags, " sp %016lx pc %016lx\n",
+ _LOG(log, logtype::REGISTERS, " sp %016lx pc %016lx\n",
(uint64_t)r.sp, (uint64_t)r.pc);
@@ -109,12 +98,12 @@
io.iov_len = sizeof(f);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
- _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
for (int i = 0; i < 32; i += 4) {
- _LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
+ _LOG(log, logtype::REGISTERS, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n",
i, (uint64_t)f.vregs[i],
i+1, (uint64_t)f.vregs[i+1],
i+2, (uint64_t)f.vregs[i+2],
diff --git a/debuggerd/arm64/vfp.S b/debuggerd/arm64/vfp.S
deleted file mode 100644
index bf12c22..0000000
--- a/debuggerd/arm64/vfp.S
+++ /dev/null
@@ -1,42 +0,0 @@
- .text
- .align 2
- .global crash
- .type crash, %function
-crash:
- fmov d0, XZR
- fmov d1, 1.0
- fmov d2, 2.0
- fmov d3, 3.0
- fmov d4, 4.0
- fmov d5, 5.0
- fmov d6, 6.0
- fmov d7, 7.0
- fmov d8, 8.0
- fmov d9, 9.0
- fmov d10, 10.0
- fmov d11, 11.0
- fmov d12, 12.0
- fmov d13, 13.0
- fmov d14, 14.0
- fmov d15, 15.0
- fmov d16, 16.0
- fmov d17, 17.0
- fmov d18, 18.0
- fmov d19, 19.0
- fmov d20, 20.0
- fmov d21, 21.0
- fmov d22, 22.0
- fmov d23, 23.0
- fmov d24, 24.0
- fmov d25, 25.0
- fmov d26, 26.0
- fmov d27, 27.0
- fmov d28, 28.0
- fmov d29, 29.0
- fmov d30, 30.0
- fmov d31, 31.0
-
- mov x0, xzr
- str x0, [x0]
- br x30
-
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d388348..c4a2143 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -30,6 +30,7 @@
#include <UniquePtr.h>
#include "backtrace.h"
+
#include "utility.h"
static void dump_process_header(log_t* log, pid_t pid) {
@@ -48,16 +49,17 @@
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
+ _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
strftime(timestr, sizeof(timestr), "%F %T", &tm);
- _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr);
+ _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
if (procname) {
- _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname);
+ _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
}
}
static void dump_process_footer(log_t* log, pid_t pid) {
- _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid);
+ _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
static void dump_thread(
@@ -79,10 +81,10 @@
}
}
- _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
+ _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) {
- _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno));
+ _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno));
return;
}
@@ -90,11 +92,11 @@
UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
if (backtrace->Unwind(0)) {
- dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " ");
+ dump_backtrace_to_log(backtrace.get(), log, " ");
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno));
*detach_failed = true;
}
}
@@ -104,7 +106,6 @@
log_t log;
log.tfd = fd;
log.amfd = amfd;
- log.quiet = true;
dump_process_header(&log, pid);
dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec);
@@ -133,9 +134,8 @@
dump_process_footer(&log, pid);
}
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
- int scope_flags, const char* prefix) {
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
}
}
diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h
index 2ec8afb..da14cd4 100644
--- a/debuggerd/backtrace.h
+++ b/debuggerd/backtrace.h
@@ -29,7 +29,6 @@
int* total_sleep_time_usec);
/* Dumps the backtrace in the backtrace data structure to the log. */
-void dump_backtrace_to_log(Backtrace* backtrace, log_t* log,
- int scope_flags, const char* prefix);
+void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 5a2bc3c..9df3c64 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -1,21 +1,24 @@
-
-//#include <cutils/misc.h>
-
-#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sched.h>
-#include <errno.h>
-
-#include <signal.h>
+#include <sys/cdefs.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
-#include <sys/wait.h>
#include <sys/socket.h>
-
-#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include <cutils/sockets.h>
+#include <log/log.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
extern const char* __progname;
@@ -23,13 +26,13 @@
void crashnostack(void);
static int do_action(const char* arg);
-static void maybeabort() {
- if(time(0) != 42) {
+static void maybe_abort() {
+ if (time(0) != 42) {
abort();
}
}
-static int smash_stack(int i) {
+static int smash_stack(int i __unused) {
printf("crasher: deliberately corrupting stack...\n");
// Unless there's a "big enough" buffer on the stack, gcc
// doesn't bother inserting checks.
@@ -50,11 +53,6 @@
overflow_stack(&buf);
}
-static void test_call1()
-{
- *((int*) 32) = 1;
-}
-
static void *noisy(void *x)
{
char c = (uintptr_t) x;
@@ -113,41 +111,77 @@
free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
+static void sigsegv_non_null() {
+ int* a = (int *)(&do_action);
+ *a = 42;
+}
+
static int do_action(const char* arg)
{
fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
- } else if (!strcmp(arg,"smash-stack")) {
+ } else if (!strcmp(arg, "SIGSEGV-non-null")) {
+ sigsegv_non_null();
+ } else if (!strcmp(arg, "smash-stack")) {
return smash_stack(42);
- } else if (!strcmp(arg,"stack-overflow")) {
+ } else if (!strcmp(arg, "stack-overflow")) {
overflow_stack(NULL);
- } else if (!strcmp(arg,"nostack")) {
+ } else if (!strcmp(arg, "nostack")) {
crashnostack();
- } else if (!strcmp(arg,"ctest")) {
+ } else if (!strcmp(arg, "ctest")) {
return ctest();
- } else if (!strcmp(arg,"exit")) {
+ } else if (!strcmp(arg, "exit")) {
exit(1);
- } else if (!strcmp(arg,"crash")) {
+ } else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
return crash(42);
- } else if (!strcmp(arg,"abort")) {
- maybeabort();
+ } else if (!strcmp(arg, "abort")) {
+ maybe_abort();
+ } else if (!strcmp(arg, "assert")) {
+ __assert("some_file.c", 123, "false");
+ } else if (!strcmp(arg, "assert2")) {
+ __assert2("some_file.c", 123, "some_function", "false");
+ } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
+ LOG_ALWAYS_FATAL("hello %s", "world");
+ } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
+ LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+ } else if (!strcmp(arg, "SIGPIPE")) {
+ int pipe_fds[2];
+ pipe(pipe_fds);
+ close(pipe_fds[0]);
+ write(pipe_fds[1], "oops", 4);
+ return EXIT_SUCCESS;
+ } else if (!strcmp(arg, "SIGTRAP")) {
+ raise(SIGTRAP);
+ return EXIT_SUCCESS;
} else if (!strcmp(arg, "heap-usage")) {
abuse_heap();
+ } else if (!strcmp(arg, "SIGSEGV-unmapped")) {
+ char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ munmap(map, sizeof(int));
+ map[0] = '8';
}
fprintf(stderr, "%s OP\n", __progname);
fprintf(stderr, "where OP is:\n");
- fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
- fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
- fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
- fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
- fprintf(stderr, " nostack crash with a NULL stack pointer\n");
- fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
- fprintf(stderr, " exit call exit(1)\n");
- fprintf(stderr, " crash cause a SIGSEGV\n");
- fprintf(stderr, " abort call abort()\n");
+ fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
+ fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
+ fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
+ fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
+ fprintf(stderr, " nostack crash with a NULL stack pointer\n");
+ fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
+ fprintf(stderr, " exit call exit(1)\n");
+ fprintf(stderr, " abort call abort()\n");
+ fprintf(stderr, " assert call assert() without a function\n");
+ fprintf(stderr, " assert2 call assert() with a function\n");
+ fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
+ fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
+ fprintf(stderr, " SIGPIPE cause a SIGPIPE\n");
+ fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n");
+ fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n");
+ fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n");
+ fprintf(stderr, " SIGTRAP cause a SIGTRAP\n");
fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
fprintf(stderr, "on the process' main thread.\n");
return EXIT_SUCCESS;
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index a2b164e..61805c9 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -30,7 +30,6 @@
#include <sys/stat.h>
#include <sys/poll.h>
-#include <log/logd.h>
#include <log/logger.h>
#include <cutils/sockets.h>
@@ -51,100 +50,50 @@
pid_t pid, tid;
uid_t uid, gid;
uintptr_t abort_msg_address;
+ int32_t original_si_code;
};
-static int write_string(const char* file, const char* string) {
- int len;
- int fd;
- ssize_t amt;
- fd = open(file, O_RDWR);
- len = strlen(string);
- if (fd < 0)
- return -errno;
- amt = write(fd, string, len);
- close(fd);
- return amt >= 0 ? 0 : -errno;
-}
+static void wait_for_user_action(const debugger_request_t &request) {
+ // Find out the name of the process that crashed.
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/%d/exe", request.pid);
-static void init_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- write_string("/sys/class/leds/green/brightness", "0");
- write_string("/sys/class/leds/blue/brightness", "0");
- write_string("/sys/class/leds/red/device/blink", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
+ char exe[PATH_MAX];
+ int count;
+ if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
+ ALOGE("readlink('%s') failed: %s", path, strerror(errno));
+ strlcpy(exe, "unknown", sizeof(exe));
+ } else {
+ exe[count] = '\0';
+ }
-static void enable_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "255");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "1,0");
-}
+ // Explain how to attach the debugger.
+ ALOGI("********************************************************\n"
+ "* Process %d has been suspended while crashing.\n"
+ "* To attach gdbserver for a gdb connection on port 5039\n"
+ "* and start gdbclient:\n"
+ "*\n"
+ "* gdbclient %s :5039 %d\n"
+ "*\n"
+ "* Wait for gdb to start, then press the VOLUME DOWN key\n"
+ "* to let the process continue crashing.\n"
+ "********************************************************\n",
+ request.pid, exe, request.tid);
-static void disable_debug_led() {
- // trout leds
- write_string("/sys/class/leds/red/brightness", "0");
- // sardine leds
- write_string("/sys/class/leds/left/cadence", "0,0");
-}
-
-static void wait_for_user_action(pid_t pid) {
- // First log a helpful message
- LOG( "********************************************************\n"
- "* Process %d has been suspended while crashing. To\n"
- "* attach gdbserver for a gdb connection on port 5039\n"
- "* and start gdbclient:\n"
- "*\n"
- "* gdbclient app_process :5039 %d\n"
- "*\n"
- "* Wait for gdb to start, then press HOME or VOLUME DOWN key\n"
- "* to let the process continue crashing.\n"
- "********************************************************\n",
- pid, pid);
-
- // wait for HOME or VOLUME DOWN key
+ // Wait for VOLUME DOWN.
if (init_getevent() == 0) {
- int ms = 1200 / 10;
- int dit = 1;
- int dah = 3*dit;
- int _ = -dit;
- int ___ = 3*_;
- int _______ = 7*_;
- const int codes[] = {
- dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______
- };
- size_t s = 0;
- input_event e;
- bool done = false;
- init_debug_led();
- enable_debug_led();
- do {
- int timeout = abs(codes[s]) * ms;
- int res = get_event(&e, timeout);
- if (res == 0) {
- if (e.type == EV_KEY
- && (e.code == KEY_HOME || e.code == KEY_VOLUMEDOWN)
- && e.value == 0) {
- done = true;
- }
- } else if (res == 1) {
- if (++s >= sizeof(codes)/sizeof(*codes))
- s = 0;
- if (codes[s] > 0) {
- enable_debug_led();
- } else {
- disable_debug_led();
+ while (true) {
+ input_event e;
+ if (get_event(&e, -1) == 0) {
+ if (e.type == EV_KEY && e.code == KEY_VOLUMEDOWN && e.value == 0) {
+ break;
}
}
- } while (!done);
+ }
uninit_getevent();
}
- // don't forget to turn debug led off
- disable_debug_led();
- LOG("debuggerd resuming process %d", pid);
+ ALOGI("debuggerd resuming process %d", request.pid);
}
static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
@@ -180,11 +129,11 @@
socklen_t len = sizeof(cr);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
- LOG("cannot get credentials\n");
+ ALOGE("cannot get credentials\n");
return -1;
}
- XLOG("reading tid\n");
+ ALOGV("reading tid\n");
fcntl(fd, F_SETFL, O_NONBLOCK);
pollfd pollfds[1];
@@ -193,7 +142,7 @@
pollfds[0].revents = 0;
status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
if (status != 1) {
- LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
+ ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
return -1;
}
@@ -201,14 +150,11 @@
memset(&msg, 0, sizeof(msg));
status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
if (status < 0) {
- LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
+ ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
return -1;
}
- if (status == sizeof(debugger_msg_t)) {
- XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n",
- status, msg.abort_msg_address);
- } else {
- LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
+ if (status != sizeof(debugger_msg_t)) {
+ ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
return -1;
}
@@ -218,6 +164,7 @@
out_request->uid = cr.uid;
out_request->gid = cr.gid;
out_request->abort_msg_address = msg.abort_msg_address;
+ out_request->original_si_code = msg.original_si_code;
if (msg.action == DEBUGGER_ACTION_CRASH) {
// Ensure that the tid reported by the crashing process is valid.
@@ -225,7 +172,7 @@
struct stat s;
snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
if (stat(buf, &s)) {
- LOG("tid %d does not exist in pid %d. ignoring debug request\n",
+ ALOGE("tid %d does not exist in pid %d. ignoring debug request\n",
out_request->tid, out_request->pid);
return -1;
}
@@ -236,7 +183,7 @@
status = get_process_info(out_request->tid, &out_request->pid,
&out_request->uid, &out_request->gid);
if (status < 0) {
- LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
+ ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
return -1;
}
} else {
@@ -257,13 +204,13 @@
}
static void handle_request(int fd) {
- XLOG("handle_request(%d)\n", fd);
+ ALOGV("handle_request(%d)\n", fd);
debugger_request_t request;
memset(&request, 0, sizeof(request));
int status = read_request(fd, &request);
if (!status) {
- XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
+ ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
request.pid, request.uid, request.gid, request.tid);
// At this point, the thread that made the request is blocked in
@@ -277,12 +224,12 @@
// See details in bionic/libc/linker/debugger.c, in function
// debugger_signal_handler().
if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
- LOG("ptrace attach failed: %s\n", strerror(errno));
+ ALOGE("ptrace attach failed: %s\n", strerror(errno));
} else {
bool detach_failed = false;
bool attach_gdb = should_attach_gdb(&request);
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
- LOG("failed responding to client: %s\n", strerror(errno));
+ ALOGE("failed responding to client: %s\n", strerror(errno));
} else {
char* tombstone_path = NULL;
@@ -301,34 +248,36 @@
switch (signal) {
case SIGSTOP:
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
- XLOG("stopped -- dumping to tombstone\n");
- tombstone_path = engrave_tombstone(
- request.pid, request.tid, signal, request.abort_msg_address, true, true,
- &detach_failed, &total_sleep_time_usec);
+ ALOGV("stopped -- dumping to tombstone\n");
+ tombstone_path = engrave_tombstone(request.pid, request.tid,
+ signal, request.original_si_code,
+ request.abort_msg_address, true,
+ &detach_failed, &total_sleep_time_usec);
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
- XLOG("stopped -- dumping to fd\n");
+ ALOGV("stopped -- dumping to fd\n");
dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
&total_sleep_time_usec);
} else {
- XLOG("stopped -- continuing\n");
+ ALOGV("stopped -- continuing\n");
status = ptrace(PTRACE_CONT, request.tid, 0, 0);
if (status) {
- LOG("ptrace continue failed: %s\n", strerror(errno));
+ ALOGE("ptrace continue failed: %s\n", strerror(errno));
}
continue; // loop again
}
break;
- case SIGILL:
case SIGABRT:
case SIGBUS:
case SIGFPE:
- case SIGSEGV:
+ case SIGILL:
case SIGPIPE:
+ case SIGSEGV:
#ifdef SIGSTKFLT
case SIGSTKFLT:
#endif
- XLOG("stopped -- fatal signal\n");
+ case SIGTRAP:
+ ALOGV("stopped -- fatal signal\n");
// Send a SIGSTOP to the process to make all of
// the non-signaled threads stop moving. Without
// this we get a lot of "ptrace detach failed:
@@ -336,14 +285,14 @@
kill(request.pid, SIGSTOP);
// don't dump sibling threads when attaching to GDB because it
// makes the process less reliable, apparently...
- tombstone_path = engrave_tombstone(
- request.pid, request.tid, signal, request.abort_msg_address, !attach_gdb,
- false, &detach_failed, &total_sleep_time_usec);
+ tombstone_path = engrave_tombstone(request.pid, request.tid,
+ signal, request.original_si_code,
+ request.abort_msg_address, !attach_gdb,
+ &detach_failed, &total_sleep_time_usec);
break;
default:
- XLOG("stopped -- unexpected signal\n");
- LOG("process stopped due to unexpected signal %d\n", signal);
+ ALOGE("process stopped due to unexpected signal %d\n", signal);
break;
}
break;
@@ -359,14 +308,14 @@
free(tombstone_path);
}
- XLOG("detaching\n");
+ ALOGV("detaching\n");
if (attach_gdb) {
// stop the process so we can debug
kill(request.pid, SIGSTOP);
// detach so we can attach gdbserver
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
detach_failed = true;
}
@@ -374,11 +323,11 @@
// for user action for the crashing process.
// in this case, we log a message and turn the debug LED on
// waiting for a gdb connection (for instance)
- wait_for_user_action(request.pid);
+ wait_for_user_action(request);
} else {
// just detach
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
detach_failed = true;
}
}
@@ -390,7 +339,7 @@
// actual parent won't receive a death notification via wait(2). At this point
// there's not much we can do about that.
if (detach_failed) {
- LOG("debuggerd committing suicide to free the zombie!\n");
+ ALOGE("debuggerd committing suicide to free the zombie!\n");
kill(getpid(), SIGKILL);
}
}
@@ -402,52 +351,50 @@
}
static int do_server() {
- int s;
- struct sigaction act;
- int logsocket = -1;
-
- // debuggerd crashes can't be reported to debuggerd. Reset all of the
- // crash handlers.
- signal(SIGILL, SIG_DFL);
+ // debuggerd crashes can't be reported to debuggerd.
+ // Reset all of the crash handlers.
signal(SIGABRT, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGFPE, SIG_DFL);
+ signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, SIG_DFL);
#endif
+ signal(SIGTRAP, SIG_DFL);
// Ignore failed writes to closed sockets
signal(SIGPIPE, SIG_IGN);
- logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
+ int logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM);
if (logsocket < 0) {
logsocket = -1;
} else {
fcntl(logsocket, F_SETFD, FD_CLOEXEC);
}
+ struct sigaction act;
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,SIGCHLD);
act.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD, &act, 0);
- s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ int s = socket_local_server(DEBUGGER_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if (s < 0)
return 1;
fcntl(s, F_SETFD, FD_CLOEXEC);
- LOG("debuggerd: " __DATE__ " " __TIME__ "\n");
+ ALOGI("debuggerd: " __DATE__ " " __TIME__ "\n");
for (;;) {
sockaddr addr;
socklen_t alen = sizeof(addr);
- XLOG("waiting for connection\n");
+ ALOGV("waiting for connection\n");
int fd = accept(s, &addr, &alen);
if (fd < 0) {
- XLOG("accept failed: %s\n", strerror(errno));
+ ALOGV("accept failed: %s\n", strerror(errno));
continue;
}
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index 2f1e201..fca9fbe 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -21,7 +21,7 @@
#include "utility.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags);
-void dump_registers(log_t* log, pid_t tid, int scope_flags);
+void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_registers(log_t* log, pid_t tid);
#endif // _DEBUGGERD_MACHINE_H
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 7b4e29e..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -22,86 +22,91 @@
#include <sys/types.h>
#include <sys/ptrace.h>
-#include <corkscrew/ptrace.h>
-
#include <sys/user.h>
#include "../utility.h"
#include "../machine.h"
-// enable to dump memory pointed to by every register
-#define DUMP_MEMORY_FOR_ALL_REGISTERS 1
-
#define R(x) (static_cast<unsigned int>(x))
+// The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS
+// writes 64-bit quantities even though the public struct uses 32-bit ones.
+struct pt_regs_mips_t {
+ uint64_t regs[32];
+ uint64_t lo;
+ uint64_t hi;
+ uint64_t cp0_epc;
+ uint64_t cp0_badvaddr;
+ uint64_t cp0_status;
+ uint64_t cp0_cause;
+};
+
// If configured to do so, dump memory around *all* registers
// for the crashing thread.
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t* log, pid_t tid) {
pt_regs_mips_t r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
return;
}
- if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) {
- static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+ static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
- for (int reg = 0; reg < 32; reg++) {
- // skip uninteresting registers
- if (reg == 0 // $0
- || reg == 26 // $k0
- || reg == 27 // $k1
- || reg == 31 // $ra (done below)
- )
- continue;
+ for (int reg = 0; reg < 32; reg++) {
+ // skip uninteresting registers
+ if (reg == 0 // $0
+ || reg == 26 // $k0
+ || reg == 27 // $k1
+ || reg == 31 // $ra (done below)
+ )
+ continue;
- uintptr_t addr = R(r.regs[reg]);
+ uintptr_t addr = R(r.regs[reg]);
- // Don't bother if it looks like a small int or ~= null, or if
- // it's in the kernel area.
- if (addr < 4096 || addr >= 0x80000000) {
- continue;
- }
-
- _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE);
+ // Don't bother if it looks like a small int or ~= null, or if
+ // it's in the kernel area.
+ if (addr < 4096 || addr >= 0x80000000) {
+ continue;
}
+
+ _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
+ dump_memory(log, tid, addr);
}
unsigned int pc = R(r.cp0_epc);
unsigned int ra = R(r.regs[31]);
- _LOG(log, scope_flags, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
+ dump_memory(log, tid, (uintptr_t)pc);
if (pc != ra) {
- _LOG(log, scope_flags, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra, scope_flags);
+ _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
+ dump_memory(log, tid, (uintptr_t)ra);
}
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
pt_regs_mips_t r;
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " zr %08x at %08x v0 %08x v1 %08x\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n",
+ _LOG(log, logtype::REGISTERS, " gp %08x sp %08x s8 %08x ra %08x\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n",
+ _LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 6a1b963..f41166b 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "DEBUG"
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -31,9 +33,10 @@
#include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
#include <log/log.h>
#include <log/logger.h>
-#include <cutils/properties.h>
+#include <log/logprint.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -55,12 +58,12 @@
// Must match the path defined in NativeCrashListener.java
#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-static bool signal_has_address(int sig) {
+static bool signal_has_si_addr(int sig) {
switch (sig) {
- case SIGILL:
- case SIGFPE:
- case SIGSEGV:
case SIGBUS:
+ case SIGFPE:
+ case SIGILL:
+ case SIGSEGV:
return true;
default:
return false;
@@ -69,16 +72,17 @@
static const char* get_signame(int sig) {
switch(sig) {
- case SIGILL: return "SIGILL";
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
- case SIGSEGV: return "SIGSEGV";
+ case SIGILL: return "SIGILL";
case SIGPIPE: return "SIGPIPE";
-#ifdef SIGSTKFLT
+ case SIGSEGV: return "SIGSEGV";
+#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
#endif
case SIGSTOP: return "SIGSTOP";
+ case SIGTRAP: return "SIGTRAP";
default: return "?";
}
}
@@ -97,13 +101,17 @@
case ILL_COPROC: return "ILL_COPROC";
case ILL_BADSTK: return "ILL_BADSTK";
}
+ static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
break;
case SIGBUS:
switch (code) {
case BUS_ADRALN: return "BUS_ADRALN";
case BUS_ADRERR: return "BUS_ADRERR";
case BUS_OBJERR: return "BUS_OBJERR";
+ case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
+ case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
}
+ static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
break;
case SIGFPE:
switch (code) {
@@ -116,74 +124,76 @@
case FPE_FLTINV: return "FPE_FLTINV";
case FPE_FLTSUB: return "FPE_FLTSUB";
}
+ static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
break;
case SIGSEGV:
switch (code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
}
+ static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
break;
case SIGTRAP:
switch (code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
case TRAP_TRACE: return "TRAP_TRACE";
+ case TRAP_BRANCH: return "TRAP_BRANCH";
+ case TRAP_HWBKPT: return "TRAP_HWBKPT";
}
+ static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
break;
}
// Then the other codes...
switch (code) {
case SI_USER: return "SI_USER";
-#if defined(SI_KERNEL)
case SI_KERNEL: return "SI_KERNEL";
-#endif
case SI_QUEUE: return "SI_QUEUE";
case SI_TIMER: return "SI_TIMER";
case SI_MESGQ: return "SI_MESGQ";
case SI_ASYNCIO: return "SI_ASYNCIO";
-#if defined(SI_SIGIO)
case SI_SIGIO: return "SI_SIGIO";
-#endif
-#if defined(SI_TKILL)
case SI_TKILL: return "SI_TKILL";
-#endif
+ case SI_DETHREAD: return "SI_DETHREAD";
}
// Then give up...
return "?";
}
-static void dump_revision_info(log_t* log) {
+static void dump_header_info(log_t* log) {
+ char fingerprint[PROPERTY_VALUE_MAX];
char revision[PROPERTY_VALUE_MAX];
+ property_get("ro.build.fingerprint", fingerprint, "unknown");
property_get("ro.revision", revision, "unknown");
- _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision);
+ _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
+ _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
+ _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
-static void dump_build_info(log_t* log) {
- char fingerprint[PROPERTY_VALUE_MAX];
-
- property_get("ro.build.fingerprint", fingerprint, "unknown");
-
- _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint);
-}
-
-static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
+static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
siginfo_t si;
-
memset(&si, 0, sizeof(si));
- if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
- _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
- } else if (signal_has_address(sig)) {
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n",
- sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
- reinterpret_cast<uintptr_t>(si.si_addr));
- } else {
- _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
- sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
+ if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
+ _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
+ return;
}
+
+ // bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
+ si.si_code = si_code;
+
+ char addr_desc[32]; // ", fault addr 0x1234"
+ if (signal_has_si_addr(signal)) {
+ snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
+ } else {
+ snprintf(addr_desc, sizeof(addr_desc), "--------");
+ }
+
+ _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
+ signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
}
-static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) {
+static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
char path[64];
char threadnamebuf[1024];
char* threadname = NULL;
@@ -201,25 +211,21 @@
}
}
- if (IS_AT_FAULT(scope_flags)) {
- char procnamebuf[1024];
- char* procname = NULL;
+ char procnamebuf[1024];
+ char* procname = NULL;
- snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- if ((fp = fopen(path, "r"))) {
- procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
- fclose(fp);
- }
-
- _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
- threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
- } else {
- _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN");
+ snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+ if ((fp = fopen(path, "r"))) {
+ procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
+ fclose(fp);
}
+
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
+ threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
}
static void dump_stack_segment(
- Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
+ Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
for (size_t i = 0; i < words; i++) {
word_t stack_content;
if (!backtrace->ReadWord(*sp, &stack_content)) {
@@ -238,27 +244,27 @@
if (!func_name.empty()) {
if (!i && label >= 0) {
if (offset) {
- _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
+ _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
label, *sp, stack_content, map_name, func_name.c_str(), offset);
} else {
- _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
+ _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
label, *sp, stack_content, map_name, func_name.c_str());
}
} else {
if (offset) {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
+ _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n",
*sp, stack_content, map_name, func_name.c_str(), offset);
} else {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
+ _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
*sp, stack_content, map_name, func_name.c_str());
}
}
} else {
if (!i && label >= 0) {
- _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
+ _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
label, *sp, stack_content, map_name);
} else {
- _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n",
+ _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s\n",
*sp, stack_content, map_name);
}
}
@@ -267,7 +273,7 @@
}
}
-static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_stack(Backtrace* backtrace, log_t* log) {
size_t first = 0, last;
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
@@ -283,27 +289,22 @@
}
first--;
- scope_flags |= SCOPE_SENSITIVE;
-
// Dump a few words before the first frame.
word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
- dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
+ dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
if (sp != frame->sp) {
- _LOG(log, scope_flags, " ........ ........\n");
+ _LOG(log, logtype::STACK, " ........ ........\n");
sp = frame->sp;
}
- if (i - first == 3) {
- scope_flags &= (~SCOPE_AT_FAULT);
- }
if (i == last) {
- dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
+ dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
if (sp < frame->sp + frame->stack_size) {
- _LOG(log, scope_flags, " ........ ........\n");
+ _LOG(log, logtype::STACK, " ........ ........\n");
}
} else {
size_t words = frame->stack_size / sizeof(word_t);
@@ -312,98 +313,87 @@
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
- dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
+ dump_stack_segment(backtrace, log, &sp, words, i);
}
}
}
-static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
+static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
if (backtrace->NumFrames()) {
- _LOG(log, scope_flags, "\nbacktrace:\n");
- dump_backtrace_to_log(backtrace, log, scope_flags, " ");
+ _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
+ dump_backtrace_to_log(backtrace, log, " ");
- _LOG(log, scope_flags, "\nstack:\n");
- dump_stack(backtrace, log, scope_flags);
+ _LOG(log, logtype::STACK, "\nstack:\n");
+ dump_stack(backtrace, log);
}
}
-static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
- if (map != NULL) {
- _LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
+static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
+ _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c %7" PRIdPTR " %s\n",
+ (fault_addr? "--->" : " "), map->start, map->end - 1,
(map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
- (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
- } else {
- _LOG(log, scope_flags, " (no %s)\n", what);
- }
+ (map->flags & PROT_EXEC) ? 'x' : '-',
+ (map->end - map->start), map->name.c_str());
}
-static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
- scope_flags |= SCOPE_SENSITIVE;
+static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) {
siginfo_t si;
memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
- _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
- return;
- }
- if (!signal_has_address(si.si_signo)) {
+ _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
return;
}
+ bool is_running = (si.si_code == SI_USER);
uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
addr &= ~0xfff; // round to 4K page boundary
- if (addr == 0) { // null-pointer deref
+ if (!is_running && addr == 0) { // null-pointer deref
return;
}
- _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n",
- reinterpret_cast<uintptr_t>(si.si_addr));
+ _LOG(log, logtype::MAPS, "\nmemory map: %s\n", is_running? "" : "(fault address prefixed with --->)");
- // Search for a match, or for a hole where the match would be. The list
- // is backward from the file content, so it starts at high addresses.
- const backtrace_map_t* cur_map = NULL;
- const backtrace_map_t* next_map = NULL;
- const backtrace_map_t* prev_map = NULL;
- for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
- if (addr >= it->start && addr < it->end) {
- cur_map = &*it;
- if (it != map->begin()) {
- prev_map = &*(it-1);
- }
- if (++it != map->end()) {
- next_map = &*it;
- }
- break;
- }
+ if(!is_running && (addr < map->begin()->start)) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
}
- // Show the map address in ascending order (like /proc/pid/maps).
- dump_map(log, prev_map, "map below", scope_flags);
- dump_map(log, cur_map, "map for address", scope_flags);
- dump_map(log, next_map, "map above", scope_flags);
+ BacktraceMap::const_iterator prev = map->begin();
+ for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
+ if (addr >= (*prev).end && addr < (*it).start) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
+ }
+ prev = it;
+ bool in_map = !is_running && (addr >= (*it).start) && (addr < (*it).end);
+ dump_map(log, &*it, in_map);
+ }
+ if (!is_running && (addr >= (*prev).end)) {
+ _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
+ }
}
static void dump_thread(
- Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) {
+ Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
+
wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
- dump_registers(log, backtrace->Tid(), scope_flags);
- dump_backtrace_and_stack(backtrace, log, scope_flags);
- if (IS_AT_FAULT(scope_flags)) {
- dump_memory_and_code(log, backtrace->Tid(), scope_flags);
- dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
- }
+ dump_registers(log, backtrace->Tid());
+ dump_backtrace_and_stack(backtrace, log);
+
+ dump_memory_and_code(log, backtrace->Tid());
+ dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid());
}
// Return true if some thread is not detached cleanly
static bool dump_sibling_thread_report(
log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
char task_path[64];
+
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
DIR* d = opendir(task_path);
// Bail early if the task directory cannot be opened
if (d == NULL) {
- XLOG("Cannot open /proc/%d/task\n", pid);
+ ALOGE("Cannot open /proc/%d/task\n", pid);
return false;
}
@@ -424,19 +414,23 @@
// Skip this thread if cannot ptrace it
if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
+ _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
continue;
}
- _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
- dump_thread_info(log, pid, new_tid, 0);
+ log->current_tid = new_tid;
+ _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
+ dump_thread_info(log, pid, new_tid);
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
if (backtrace->Unwind(0)) {
- dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log, total_sleep_time_usec);
}
+ log->current_tid = log->crashed_tid;
+
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
- LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
detach_failed = true;
}
}
@@ -448,17 +442,19 @@
// Reads the contents of the specified log device, filters out the entries
// that don't match the specified pid, and writes them to the tombstone file.
//
-// If "tail" is set, we only print the last few lines.
-static void dump_log_file(log_t* log, pid_t pid, const char* filename,
- unsigned int tail) {
+// If "tail" is non-zero, log the last "tail" number of lines.
+static EventTagMap* g_eventTagMap = NULL;
+
+static void dump_log_file(
+ log_t* log, pid_t pid, const char* filename, unsigned int tail) {
bool first = true;
- struct logger_list *logger_list;
+ struct logger_list* logger_list;
logger_list = android_logger_list_open(
- android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
+ android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
if (!logger_list) {
- XLOG("Unable to open %s: %s\n", filename, strerror(errno));
+ ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
return;
}
@@ -466,6 +462,7 @@
while (true) {
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+ struct logger_entry* entry;
if (actual < 0) {
if (actual == -EINTR) {
@@ -475,29 +472,25 @@
// non-blocking EOF; we're done
break;
} else {
- _LOG(log, 0, "Error while reading log: %s\n",
+ _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
strerror(-actual));
break;
}
} else if (actual == 0) {
- _LOG(log, 0, "Got zero bytes while reading log: %s\n",
+ _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n",
strerror(errno));
break;
}
- // NOTE: if you XLOG something here, this will spin forever,
+ // NOTE: if you ALOGV something here, this will spin forever,
// because you will be writing as fast as you're reading. Any
// high-frequency debug diagnostics should just be written to
// the tombstone file.
- struct logger_entry* entry = &log_entry.entry_v1;
- if (entry->pid != static_cast<int32_t>(pid)) {
- // wrong pid, ignore
- continue;
- }
+ entry = &log_entry.entry_v1;
if (first) {
- _LOG(log, 0, "--------- %slog %s\n",
+ _LOG(log, logtype::LOGS, "--------- %slog %s\n",
tail ? "tail end of " : "", filename);
first = false;
}
@@ -511,18 +504,7 @@
if (!hdr_size) {
hdr_size = sizeof(log_entry.entry_v1);
}
- char* msg = (char *)log_entry.buf + hdr_size;
- unsigned char prio = msg[0];
- char* tag = msg + 1;
- msg = tag + strlen(tag) + 1;
-
- // consume any trailing newlines
- char* nl = msg + strlen(msg) - 1;
- while (nl >= msg && *nl == '\n') {
- *nl-- = '\0';
- }
-
- char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+ char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
char timeBuf[32];
time_t sec = static_cast<time_t>(entry->sec);
@@ -531,6 +513,31 @@
ptm = localtime_r(&sec, &tmBuf);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+ if (log_entry.id() == LOG_ID_EVENTS) {
+ if (!g_eventTagMap) {
+ g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ }
+ AndroidLogEntry e;
+ char buf[512];
+ android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
+ timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
+ 'I', e.tag, e.message);
+ continue;
+ }
+
+ unsigned char prio = msg[0];
+ char* tag = msg + 1;
+ msg = tag + strlen(tag) + 1;
+
+ // consume any trailing newlines
+ char* nl = msg + strlen(msg) - 1;
+ while (nl >= msg && *nl == '\n') {
+ *nl-- = '\0';
+ }
+
+ char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
+
// Look for line breaks ('\n') and display each text line
// on a separate line, prefixed with the header, like logcat does.
do {
@@ -540,10 +547,9 @@
++nl;
}
- _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+ _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
prioChar, tag, msg);
-
} while ((msg = nl));
}
@@ -552,7 +558,7 @@
// Dumps the logs generated by the specified pid to the tombstone, from both
// "system" and "main" log devices. Ideally we'd interleave the output.
-static void dump_logs(log_t* log, pid_t pid, unsigned tail) {
+static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
dump_log_file(log, pid, "system", tail);
dump_log_file(log, pid, "main", tail);
}
@@ -580,12 +586,13 @@
}
msg[sizeof(msg) - 1] = '\0';
- _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg);
+ _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
}
// Dumps all information about the specified pid to the tombstone.
-static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
- bool dump_sibling_threads, int* total_sleep_time_usec) {
+static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code,
+ uintptr_t abort_msg_address, bool dump_sibling_threads,
+ int* total_sleep_time_usec) {
// don't copy log messages to tombstone unless this is a dev device
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "0");
@@ -601,20 +608,20 @@
TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) );
}
- _LOG(log, SCOPE_AT_FAULT,
+ _LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
- dump_build_info(log);
- dump_revision_info(log);
- dump_thread_info(log, pid, tid, SCOPE_AT_FAULT);
+ dump_header_info(log);
+ dump_thread_info(log, pid, tid);
+
if (signal) {
- dump_fault_addr(log, tid, signal);
+ dump_signal_info(log, tid, signal, si_code);
}
UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
if (backtrace->Unwind(0)) {
dump_abort_message(backtrace.get(), log, abort_msg_address);
- dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log, total_sleep_time_usec);
}
if (want_logs) {
@@ -676,7 +683,7 @@
}
if (oldest < 0) {
- LOG("Failed to find a valid tombstone, default to using tombstone 0.\n");
+ ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n");
oldest = 0;
}
@@ -684,7 +691,7 @@
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (*fd < 0) {
- LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno));
+ ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
return NULL;
}
fchown(*fd, AID_SYSTEM, AID_SYSTEM);
@@ -721,37 +728,49 @@
return amfd;
}
-char* engrave_tombstone(
- pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address, bool dump_sibling_threads,
- bool quiet, bool* detach_failed, int* total_sleep_time_usec) {
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+ uintptr_t abort_msg_address, bool dump_sibling_threads,
+ bool* detach_failed, int* total_sleep_time_usec) {
+
+ log_t log;
+ log.current_tid = tid;
+ log.crashed_tid = tid;
+
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
- LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
}
if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
- LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+ _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
}
- if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == -1) {
+ int fd = -1;
+ char* path = NULL;
+ if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
+ path = find_and_open_tombstone(&fd);
+ } else {
+ _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n");
+ }
+
+ if (fd < 0) {
+ _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n");
*detach_failed = false;
return NULL;
}
- int fd;
- char* path = find_and_open_tombstone(&fd);
- if (!path) {
- *detach_failed = false;
- return NULL;
- }
-
- log_t log;
log.tfd = fd;
- log.amfd = activity_manager_connect();
- log.quiet = quiet;
- *detach_failed = dump_crash(
- &log, pid, tid, signal, abort_msg_address, dump_sibling_threads, total_sleep_time_usec);
+ // Preserve amfd since it can be modified through the calls below without
+ // being closed.
+ int amfd = activity_manager_connect();
+ log.amfd = amfd;
+ *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
+ dump_sibling_threads, total_sleep_time_usec);
- close(log.amfd);
+ ALOGI("\nTombstone written to: %s\n", path);
+
+ // Either of these file descriptors can be -1, any error is ignored.
+ close(amfd);
close(fd);
+
return path;
}
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index e9878bf..7e2b2fe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -23,7 +23,9 @@
/* Creates a tombstone file and writes the crash dump to it.
* Returns the path of the tombstone, which must be freed using free(). */
-char* engrave_tombstone(pid_t pid, pid_t tid, int signal, uintptr_t abort_msg_address,
- bool dump_sibling_threads, bool quiet, bool* detach_failed, int* total_sleep_time_usec);
+char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code,
+ uintptr_t abort_msg_address,
+ bool dump_sibling_threads, bool* detach_failed,
+ int* total_sleep_time_usec);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index d4c252f..a163344 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "DEBUG"
+
#include "utility.h"
#include <errno.h>
@@ -25,7 +27,6 @@
#include <backtrace/Backtrace.h>
#include <log/log.h>
-#include <log/logd.h>
const int sleep_time_usec = 50000; // 0.05 seconds
const int max_total_sleep_usec = 10000000; // 10 seconds
@@ -36,7 +37,7 @@
int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
if (written < 0) {
// hard failure
- LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
+ ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
return -1;
}
to_write -= written;
@@ -44,10 +45,22 @@
return len;
}
-void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
- bool want_tfd_write = log && log->tfd >= 0;
- bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
- bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
+// Whitelist output desired in the logcat output.
+bool is_allowed_in_logcat(enum logtype ltype) {
+ if ((ltype == ERROR)
+ || (ltype == HEADER)
+ || (ltype == REGISTERS)
+ || (ltype == BACKTRACE)) {
+ return true;
+ }
+ return false;
+}
+
+void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
+ bool write_to_tombstone = (log->tfd != -1);
+ bool write_to_logcat = is_allowed_in_logcat(ltype)
+ && (log->crashed_tid == log->current_tid);
+ bool write_to_activitymanager = (log->amfd != -1);
char buf[512];
va_list ap;
@@ -60,13 +73,13 @@
return;
}
- if (want_tfd_write) {
+ if (write_to_tombstone) {
TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
}
- if (want_log_write) {
- __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf);
- if (want_amfd_write) {
+ if (write_to_logcat) {
+ __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+ if (write_to_activitymanager) {
int written = write_to_am(log->amfd, buf, len);
if (written <= 0) {
// timeout or other failure on write; stop informing the activity manager
@@ -83,25 +96,25 @@
if (n < 0) {
if (errno == EAGAIN)
continue;
- LOG("waitpid failed: %s\n", strerror(errno));
+ ALOGE("waitpid failed: %s\n", strerror(errno));
return -1;
} else if (n > 0) {
- XLOG("waitpid: n=%d status=%08x\n", n, status);
+ ALOGV("waitpid: n=%d status=%08x\n", n, status);
if (WIFSTOPPED(status)) {
return WSTOPSIG(status);
} else {
- LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status);
+ ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
return -1;
}
}
if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to die\n", tid);
+ ALOGE("timed out waiting for tid=%d to die\n", tid);
return -1;
}
// not ready yet
- XLOG("not ready yet\n");
+ ALOGV("not ready yet\n");
usleep(sleep_time_usec);
*total_sleep_time_usec += sleep_time_usec;
}
@@ -111,7 +124,7 @@
siginfo_t si;
while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
if (*total_sleep_time_usec > max_total_sleep_usec) {
- LOG("timed out waiting for tid=%d to stop\n", tid);
+ ALOGE("timed out waiting for tid=%d to stop\n", tid);
break;
}
@@ -126,7 +139,7 @@
#define DUMP_MEMORY_AS_ASCII 0
#endif
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) {
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
char code_buffer[64];
char ascii_buffer[32];
uintptr_t p, end;
@@ -190,6 +203,6 @@
p += sizeof(long);
}
*asc_out = '\0';
- _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer);
+ _LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
}
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 0f88605..f2e2d29 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,48 +21,53 @@
#include <stdbool.h>
#include <sys/types.h>
+// Figure out the abi based on defined macros.
+#if defined(__arm__)
+#define ABI_STRING "arm"
+#elif defined(__aarch64__)
+#define ABI_STRING "arm64"
+#elif defined(__mips__)
+#define ABI_STRING "mips"
+#elif defined(__i386__)
+#define ABI_STRING "x86"
+#elif defined(__x86_64__)
+#define ABI_STRING "x86_64"
+#else
+#error "Unsupported ABI"
+#endif
+
+
typedef struct {
/* tombstone file descriptor */
int tfd;
/* Activity Manager socket file descriptor */
int amfd;
- /* if true, does not log anything to the Android logcat or Activity Manager */
- bool quiet;
+ // The tid of the thread that crashed.
+ pid_t crashed_tid;
+ // The tid of the thread we are currently working with.
+ pid_t current_tid;
} log_t;
-/* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined
- * here. */
-void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
+// List of types of logs to simplify the logging decision in _LOG
+enum logtype {
+ ERROR,
+ HEADER,
+ THREAD,
+ REGISTERS,
+ BACKTRACE,
+ MAPS,
+ MEMORY,
+ STACK,
+ LOGS
+};
+
+/* Log information onto the tombstone. */
+void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
-/* The message pertains specifically to the faulting thread / process */
-#define SCOPE_AT_FAULT (1 << 0)
-/* The message contains sensitive information such as RAM contents */
-#define SCOPE_SENSITIVE (1 << 1)
-
-#define IS_AT_FAULT(x) (((x) & SCOPE_AT_FAULT) != 0)
-#define IS_SENSITIVE(x) (((x) & SCOPE_SENSITIVE) != 0)
-
-/* Further helpful macros */
-#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-
-/* Set to 1 for normal debug traces */
-#if 0
-#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG(fmt...) do {} while(0)
-#endif
-
-/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */
-#if 0
-#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt)
-#else
-#define XLOG2(fmt...) do {} while(0)
-#endif
-
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags);
+void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/vfp-crasher.c b/debuggerd/vfp-crasher.c
deleted file mode 100644
index 7a19cdd..0000000
--- a/debuggerd/vfp-crasher.c
+++ /dev/null
@@ -1,7 +0,0 @@
-int main()
-{
- extern void crash(void);
-
- crash();
- return 0;
-}
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 141f19a..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -25,21 +25,21 @@
#include "../utility.h"
#include "../machine.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
struct pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
+ _LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
- _LOG(log, scope_flags, " esi %08lx edi %08lx\n",
+ _LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
r.esi, r.edi);
- _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
+ _LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
r.xcs, r.xds, r.xes, r.xfs, r.xss);
- _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
+ _LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
r.eip, r.ebp, r.esp, r.eflags);
}
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 406851a..af4f35a 100755
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -27,25 +27,25 @@
#include "../utility.h"
#include "../machine.h"
-void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
+void dump_memory_and_code(log_t*, pid_t) {
}
-void dump_registers(log_t* log, pid_t tid, int scope_flags) {
+void dump_registers(log_t* log, pid_t tid) {
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- _LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
r.rax, r.rbx, r.rcx, r.rdx);
- _LOG(log, scope_flags, " rsi %016lx rdi %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
r.rsi, r.rdi);
- _LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
r.r8, r.r9, r.r10, r.r11);
- _LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
r.r12, r.r13, r.r14, r.r15);
- _LOG(log, scope_flags, " cs %016lx ss %016lx\n",
+ _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
r.cs, r.ss);
- _LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
+ _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
r.rip, r.rbp, r.rsp, r.eflags);
}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b9b3c92..73794a0 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,10 +18,10 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
$(LOCAL_PATH)/../../extras/ext4_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c
+LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
-LOCAL_CFLAGS += -std=gnu99
+LOCAL_CFLAGS += -std=gnu99 -Werror
ifeq ($(HOST_OS),linux)
LOCAL_SRC_FILES += usb_linux.c util_linux.c
@@ -72,6 +72,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c
LOCAL_MODULE := usbtest
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
endif
diff --git a/fastboot/engine.c b/fastboot/engine.c
index 972c4ed..2f90e41 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.c
@@ -27,13 +27,13 @@
*/
#include "fastboot.h"
-#include "make_ext4fs.h"
+#include "fs.h"
#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -45,15 +45,18 @@
#include <sys/mman.h>
#endif
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define OP_DOWNLOAD 1
#define OP_COMMAND 2
#define OP_QUERY 3
#define OP_NOTICE 4
-#define OP_FORMAT 5
-#define OP_DOWNLOAD_SPARSE 6
-#define OP_WAIT_FOR_DISCONNECT 7
+#define OP_DOWNLOAD_SPARSE 5
+#define OP_WAIT_FOR_DISCONNECT 6
typedef struct Action Action;
@@ -79,14 +82,7 @@
static Action *action_last = 0;
-struct image_data {
- long long partition_size;
- long long image_size; // real size of image file
- void *buffer;
-};
-void generate_ext4_image(struct image_data *image);
-void cleanup_image(struct image_data *image);
int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...)
{
@@ -102,24 +98,6 @@
return fb_command_response(usb, cmd, response);
}
-struct generator {
- char *fs_type;
-
- /* generate image and return it as image->buffer.
- * size of the buffer returned as image->image_size.
- *
- * image->partition_size specifies what is the size of the
- * file partition we generate image for.
- */
- void (*generate)(struct image_data *image);
-
- /* it cleans the buffer allocated during image creation.
- * this function probably does free() or munmap().
- */
- void (*cleanup)(struct image_data *image);
-} generators[] = {
- { "ext4", generate_ext4_image, cleanup_image }
-};
/* Return true if this partition is supported by the fastboot format command.
* It is also used to determine if we should first erase a partition before
@@ -128,30 +106,19 @@
* Not all devices report the filesystem type, so don't report any errors,
* just return false.
*/
-int fb_format_supported(usb_handle *usb, const char *partition)
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override)
{
- char response[FB_RESPONSE_SZ+1];
- struct generator *generator = NULL;
+ char fs_type[FB_RESPONSE_SZ + 1] = {0,};
int status;
- unsigned int i;
- status = fb_getvar(usb, response, "partition-type:%s", partition);
+ if (type_override) {
+ return !!fs_get_generator(type_override);
+ }
+ status = fb_getvar(usb, fs_type, "partition-type:%s", partition);
if (status) {
return 0;
}
-
- for (i = 0; i < ARRAY_SIZE(generators); i++) {
- if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
- generator = &generators[i];
- break;
- }
- }
-
- if (generator) {
- return 1;
- }
-
- return 0;
+ return !!fs_get_generator(fs_type);
}
static int cb_default(Action *a, int status, char *resp)
@@ -205,163 +172,6 @@
a->msg = mkmsg("erasing '%s'", ptn);
}
-/* Loads file content into buffer. Returns NULL on error. */
-static void *load_buffer(int fd, off_t size)
-{
- void *buffer;
-
-#ifdef USE_MINGW
- ssize_t count = 0;
-
- // mmap is more efficient but mingw does not support it.
- // In this case we read whole image into memory buffer.
- buffer = malloc(size);
- if (!buffer) {
- perror("malloc");
- return NULL;
- }
-
- lseek(fd, 0, SEEK_SET);
- while(count < size) {
- ssize_t actually_read = read(fd, (char*)buffer+count, size-count);
-
- if (actually_read == 0) {
- break;
- }
- if (actually_read < 0) {
- if (errno == EINTR) {
- continue;
- }
- perror("read");
- free(buffer);
- return NULL;
- }
-
- count += actually_read;
- }
-#else
- buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (buffer == MAP_FAILED) {
- perror("mmap");
- return NULL;
- }
-#endif
-
- return buffer;
-}
-
-void cleanup_image(struct image_data *image)
-{
-#ifdef USE_MINGW
- free(image->buffer);
-#else
- munmap(image->buffer, image->image_size);
-#endif
-}
-
-void generate_ext4_image(struct image_data *image)
-{
- int fd;
- struct stat st;
-
- fd = fileno(tmpfile());
- make_ext4fs_sparse_fd(fd, image->partition_size, NULL, NULL);
-
- fstat(fd, &st);
- image->image_size = st.st_size;
- image->buffer = load_buffer(fd, st.st_size);
-
- close(fd);
-}
-
-int fb_format(Action *a, usb_handle *usb, int skip_if_not_supported)
-{
- const char *partition = a->cmd;
- char response[FB_RESPONSE_SZ+1];
- int status = 0;
- struct image_data image;
- struct generator *generator = NULL;
- int fd;
- unsigned i;
- char cmd[CMD_SIZE];
-
- status = fb_getvar(usb, response, "partition-type:%s", partition);
- if (status) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr,
- "Can't determine partition type.\n");
- return 0;
- }
- fprintf(stderr,"FAILED (%s)\n", fb_get_error());
- return status;
- }
-
- for (i = 0; i < ARRAY_SIZE(generators); i++) {
- if (!strncmp(generators[i].fs_type, response, FB_RESPONSE_SZ)) {
- generator = &generators[i];
- break;
- }
- }
- if (!generator) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr,
- "File system type %s not supported.\n", response);
- return 0;
- }
- fprintf(stderr,"Formatting is not supported for filesystem with type '%s'.\n",
- response);
- return -1;
- }
-
- status = fb_getvar(usb, response, "partition-size:%s", partition);
- if (status) {
- if (skip_if_not_supported) {
- fprintf(stderr,
- "Erase successful, but not automatically formatting.\n");
- fprintf(stderr, "Unable to get partition size\n.");
- return 0;
- }
- fprintf(stderr,"FAILED (%s)\n", fb_get_error());
- return status;
- }
- image.partition_size = strtoll(response, (char **)NULL, 16);
-
- generator->generate(&image);
- if (!image.buffer) {
- fprintf(stderr,"Cannot generate image.\n");
- return -1;
- }
-
- // Following piece of code is similar to fb_queue_flash() but executes
- // actions directly without queuing
- fprintf(stderr, "sending '%s' (%lli KB)...\n", partition, image.image_size/1024);
- status = fb_download_data(usb, image.buffer, image.image_size);
- if (status) goto cleanup;
-
- fprintf(stderr, "writing '%s'...\n", partition);
- snprintf(cmd, sizeof(cmd), "flash:%s", partition);
- status = fb_command(usb, cmd);
- if (status) goto cleanup;
-
-cleanup:
- generator->cleanup(&image);
-
- return status;
-}
-
-void fb_queue_format(const char *partition, int skip_if_not_supported)
-{
- Action *a;
-
- a = queue_action(OP_FORMAT, partition);
- a->data = (void*)skip_if_not_supported;
- a->msg = mkmsg("formatting '%s' partition", partition);
-}
-
void fb_queue_flash(const char *ptn, void *data, unsigned sz)
{
Action *a;
@@ -390,9 +200,7 @@
static int match(char *str, const char **value, unsigned count)
{
- const char *val;
unsigned n;
- int len;
for (n = 0; n < count; n++) {
const char *val = value[n];
@@ -518,7 +326,7 @@
a->func = cb_save;
}
-static int cb_do_nothing(Action *a, int status, char *resp)
+static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused)
{
fprintf(stderr,"\n");
return 0;
@@ -589,10 +397,6 @@
if (status) break;
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
- } else if (a->op == OP_FORMAT) {
- status = fb_format(a, usb, (int)a->data);
- status = a->func(a, status, status ? fb_get_error() : "");
- if (status) break;
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(usb, a->data);
status = a->func(a, status, status ? fb_get_error() : "");
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 73a6e56..266d0b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -28,27 +28,28 @@
#define _LARGEFILE64_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <limits.h>
-#include <ctype.h>
#include <getopt.h>
-
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
+#include <unistd.h>
#include <bootimg.h>
#include <sparse/sparse.h>
#include <zipfile/zipfile.h>
#include "fastboot.h"
+#include "fs.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -70,7 +71,6 @@
static const char *serial = 0;
static const char *product = 0;
static const char *cmdline = 0;
-static int wipe_data = 0;
static unsigned short vendor_id = 0;
static int long_listing = 0;
static int64_t sparse_limit = -1;
@@ -99,10 +99,11 @@
char sig_name[13];
char part_name[9];
bool is_optional;
-} images[3] = {
+} images[4] = {
{"boot.img", "boot.sig", "boot", false},
{"recovery.img", "recovery.sig", "recovery", true},
{"system.img", "system.sig", "system", false},
+ {"tos.img", "tos.sig", "tos", true},
};
void get_my_path(char *path);
@@ -119,6 +120,8 @@
fn = "recovery.img";
} else if(!strcmp(item,"system")) {
fn = "system.img";
+ } else if(!strcmp(item,"tos")) {
+ fn = "tos.img";
} else if(!strcmp(item,"userdata")) {
fn = "userdata.img";
} else if(!strcmp(item,"cache")) {
@@ -265,7 +268,7 @@
announce = 0;
fprintf(stderr,"< waiting for device >\n");
}
- sleep(1);
+ usleep(1000);
}
}
@@ -284,10 +287,13 @@
"\n"
"commands:\n"
" update <filename> reflash device from update.zip\n"
- " flashall flash boot + recovery + system\n"
+ " flashall flash boot, system, and if found,\n"
+ " recovery, tos\n"
" flash <partition> [ <filename> ] write a file to a flash partition\n"
" erase <partition> erase a flash partition\n"
- " format <partition> format a flash partition \n"
+ " format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
+ " Can override the fs type and/or\n"
+ " size the bootloader reports.\n"
" getvar <variable> display a bootloader variable\n"
" boot <kernel> [ <ramdisk> ] download and boot kernel\n"
" flash:raw boot <kernel> [ <ramdisk> ] create bootimage and flash it\n"
@@ -308,10 +314,12 @@
" -p <product> specify product name\n"
" -c <cmdline> override kernel commandline\n"
" -i <vendor id> specify a custom USB vendor id\n"
- " -b <base_addr> specify a custom kernel base address. default: 0x10000000\n"
- " -n <page size> specify the nand page size. default: 2048\n"
- " -S <size>[K|M|G] automatically sparse files greater than\n"
- " size. 0 to disable\n"
+ " -b <base_addr> specify a custom kernel base address.\n"
+ " default: 0x10000000\n"
+ " -n <page size> specify the nand page size.\n"
+ " default: 2048\n"
+ " -S <size>[K|M|G] automatically sparse files greater\n"
+ " than size. 0 to disable\n"
);
}
@@ -418,7 +426,7 @@
return -1;
}
- if (write(fd, data, sz) != sz) {
+ if (write(fd, data, sz) != (ssize_t)sz) {
fd = -1;
}
@@ -569,7 +577,7 @@
if (!status) {
limit = strtoul(response, NULL, 0);
if (limit > 0) {
- fprintf(stderr, "target reported max download size of %lld bytes\n",
+ fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
limit);
}
}
@@ -612,7 +620,7 @@
/* The function fb_format_supported() currently returns the value
* we want, so just call it.
*/
- return fb_format_supported(usb, part);
+ return fb_format_supported(usb, part, NULL);
}
static int load_buf_fd(usb_handle *usb, int fd,
@@ -622,10 +630,13 @@
void *data;
int64_t limit;
+
sz64 = file_size(fd);
if (sz64 < 0) {
return -1;
}
+
+ lseek(fd, 0, SEEK_SET);
limit = get_sparse_limit(usb, sz64);
if (limit) {
struct sparse_file **s = load_sparse_files(fd, limit);
@@ -653,7 +664,7 @@
fd = open(fname, O_RDONLY | O_BINARY);
if (fd < 0) {
- die("cannot open '%s'\n", fname);
+ return -1;
}
return load_buf_fd(usb, fd, buf);
@@ -709,7 +720,7 @@
int fd;
int rc;
struct fastboot_buffer buf;
- int i;
+ size_t i;
queue_info_dump();
@@ -783,7 +794,7 @@
void *data;
unsigned sz;
struct fastboot_buffer buf;
- int i;
+ size_t i;
queue_info_dump();
@@ -815,7 +826,6 @@
int do_oem_command(int argc, char **argv)
{
- int i;
char command[256];
if (argc <= 1) return 0;
@@ -872,6 +882,92 @@
return num;
}
+void fb_perform_format(const char *partition, int skip_if_not_supported,
+ const char *type_override, const char *size_override)
+{
+ char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
+ char *pType = pTypeBuff;
+ char *pSize = pSizeBuff;
+ unsigned int limit = INT_MAX;
+ struct fastboot_buffer buf;
+ const char *errMsg = NULL;
+ const struct fs_generator *gen;
+ uint64_t pSz;
+ int status;
+ int fd;
+
+ if (target_sparse_limit > 0 && target_sparse_limit < limit)
+ limit = target_sparse_limit;
+ if (sparse_limit > 0 && sparse_limit < limit)
+ limit = sparse_limit;
+
+ status = fb_getvar(usb, pType, "partition-type:%s", partition);
+ if (status) {
+ errMsg = "Can't determine partition type.\n";
+ goto failed;
+ }
+ if (type_override) {
+ if (strcmp(type_override, pType)) {
+ fprintf(stderr,
+ "Warning: %s type is %s, but %s was requested for formating.\n",
+ partition, pType, type_override);
+ }
+ pType = (char *)type_override;
+ }
+
+ status = fb_getvar(usb, pSize, "partition-size:%s", partition);
+ if (status) {
+ errMsg = "Unable to get partition size\n";
+ goto failed;
+ }
+ if (size_override) {
+ if (strcmp(size_override, pSize)) {
+ fprintf(stderr,
+ "Warning: %s size is %s, but %s was requested for formating.\n",
+ partition, pSize, size_override);
+ }
+ pSize = (char *)size_override;
+ }
+
+ gen = fs_get_generator(pType);
+ if (!gen) {
+ if (skip_if_not_supported) {
+ fprintf(stderr, "Erase successful, but not automatically formatting.\n");
+ fprintf(stderr, "File system type %s not supported.\n", pType);
+ return;
+ }
+ fprintf(stderr, "Formatting is not supported for filesystem with type '%s'.\n", pType);
+ return;
+ }
+
+ pSz = strtoll(pSize, (char **)NULL, 16);
+
+ fd = fileno(tmpfile());
+ if (fs_generator_generate(gen, fd, pSz)) {
+ close(fd);
+ fprintf(stderr, "Cannot generate image.\n");
+ return;
+ }
+
+ if (load_buf_fd(usb, fd, &buf)) {
+ fprintf(stderr, "Cannot read image.\n");
+ close(fd);
+ return;
+ }
+ flash_buf(partition, &buf);
+
+ return;
+
+
+failed:
+ if (skip_if_not_supported) {
+ fprintf(stderr, "Erase successful, but not automatically formatting.\n");
+ if (errMsg)
+ fprintf(stderr, "%s", errMsg);
+ }
+ fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+}
+
int main(int argc, char **argv)
{
int wants_wipe = 0;
@@ -882,13 +978,13 @@
unsigned sz;
int status;
int c;
- int r;
const struct option longopts[] = {
{"base", required_argument, 0, 'b'},
{"kernel_offset", required_argument, 0, 'k'},
{"page_size", required_argument, 0, 'n'},
{"ramdisk_offset", required_argument, 0, 'r'},
+ {"tags_offset", required_argument, 0, 't'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
@@ -896,8 +992,7 @@
serial = getenv("ANDROID_SERIAL");
while (1) {
- int option_index = 0;
- c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
+ c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, NULL);
if (c < 0) {
break;
}
@@ -938,6 +1033,9 @@
case 'r':
ramdisk_offset = strtoul(optarg, 0, 16);
break;
+ case 't':
+ tags_offset = strtoul(optarg, 0, 16);
+ break;
case 's':
serial = optarg;
break;
@@ -989,18 +1087,42 @@
} else if(!strcmp(*argv, "erase")) {
require(2);
- if (fb_format_supported(usb, argv[1])) {
+ if (fb_format_supported(usb, argv[1], NULL)) {
fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
}
fb_queue_erase(argv[1]);
skip(2);
- } else if(!strcmp(*argv, "format")) {
+ } else if(!strncmp(*argv, "format", strlen("format"))) {
+ char *overrides;
+ char *type_override = NULL;
+ char *size_override = NULL;
require(2);
+ /*
+ * Parsing for: "format[:[type][:[size]]]"
+ * Some valid things:
+ * - select ontly the size, and leave default fs type:
+ * format::0x4000000 userdata
+ * - default fs type and size:
+ * format userdata
+ * format:: userdata
+ */
+ overrides = strchr(*argv, ':');
+ if (overrides) {
+ overrides++;
+ size_override = strchr(overrides, ':');
+ if (size_override) {
+ size_override[0] = '\0';
+ size_override++;
+ }
+ type_override = overrides;
+ }
+ if (type_override && !type_override[0]) type_override = NULL;
+ if (size_override && !size_override[0]) size_override = NULL;
if (erase_first && needs_erase(argv[1])) {
fb_queue_erase(argv[1]);
}
- fb_queue_format(argv[1], 0);
+ fb_perform_format(argv[1], 0, type_override, size_override);
skip(2);
} else if(!strcmp(*argv, "signature")) {
require(2);
@@ -1088,12 +1210,13 @@
if (wants_wipe) {
fb_queue_erase("userdata");
- fb_queue_format("userdata", 1);
+ fb_perform_format("userdata", 1, NULL, NULL);
fb_queue_erase("cache");
- fb_queue_format("cache", 1);
+ fb_perform_format("cache", 1, NULL, NULL);
}
if (wants_reboot) {
fb_queue_reboot();
+ fb_queue_wait_for_disconnect();
} else if (wants_reboot_bootloader) {
fb_queue_command("reboot-bootloader", "rebooting into bootloader");
fb_queue_wait_for_disconnect();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 976c397..fc5d4f4 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -45,11 +45,11 @@
/* engine.c - high level command queue engine */
int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
-int fb_format_supported(usb_handle *usb, const char *partition);
+int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override);
void fb_queue_flash(const char *ptn, void *data, unsigned sz);
void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
void fb_queue_erase(const char *ptn);
-void fb_queue_format(const char *ptn, int skip_if_not_supported);
+void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz);
void fb_queue_require(const char *prod, const char *var, int invert,
unsigned nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname);
diff --git a/fastboot/fs.c b/fastboot/fs.c
new file mode 100644
index 0000000..cd4b880
--- /dev/null
+++ b/fastboot/fs.c
@@ -0,0 +1,56 @@
+#include "fastboot.h"
+#include "make_ext4fs.h"
+#include "fs.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sparse/sparse.h>
+#include <unistd.h>
+
+#ifdef USE_MINGW
+#include <fcntl.h>
+#else
+#include <sys/mman.h>
+#endif
+
+
+
+static int generate_ext4_image(int fd, long long partSize)
+{
+ make_ext4fs_sparse_fd(fd, partSize, NULL, NULL);
+
+ return 0;
+}
+
+static const struct fs_generator {
+
+ char *fs_type; //must match what fastboot reports for partition type
+ int (*generate)(int fd, long long partSize); //returns 0 or error value
+
+} generators[] = {
+
+ { "ext4", generate_ext4_image}
+
+};
+
+const struct fs_generator* fs_get_generator(const char *fs_type)
+{
+ unsigned i;
+
+ for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
+ if (!strcmp(generators[i].fs_type, fs_type))
+ return generators + i;
+
+ return NULL;
+}
+
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
+{
+ return gen->generate(tmpFileNo, partSize);
+}
diff --git a/fastboot/fs.h b/fastboot/fs.h
new file mode 100644
index 0000000..8444081
--- /dev/null
+++ b/fastboot/fs.h
@@ -0,0 +1,12 @@
+#ifndef _FS_H_
+#define _FS_H_
+
+#include <stdint.h>
+
+struct fs_generator;
+
+const struct fs_generator* fs_get_generator(const char *fs_type);
+int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
+
+#endif
+
diff --git a/fastboot/protocol.c b/fastboot/protocol.c
index a0e0fd4..84e9837 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.c
@@ -110,7 +110,6 @@
char *response)
{
int cmdsize = strlen(cmd);
- int r;
if(response) {
response[0] = 0;
@@ -189,8 +188,6 @@
static int _command_send_no_data(usb_handle *usb, const char *cmd,
char *response)
{
- int r;
-
return _command_start(usb, cmd, 0, response);
}
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index f2ce226..a45f9f8 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -125,9 +125,6 @@
unsigned i;
unsigned e;
- struct stat st;
- int result;
-
if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
return -1;
dev = (void*) ptr;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 07f7be2..0d13863 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -152,7 +152,7 @@
}
int usb_write(usb_handle* handle, const void* data, int len) {
- unsigned long time_out = 500 + len * 8;
+ unsigned long time_out = 5000;
unsigned long written = 0;
unsigned count = 0;
int ret;
@@ -178,7 +178,7 @@
count += written;
len -= written;
- data += written;
+ data = (const char *)data + written;
if (len == 0)
return count;
@@ -194,7 +194,7 @@
}
int usb_read(usb_handle *handle, void* data, int len) {
- unsigned long time_out = 500 + len * 8;
+ unsigned long time_out = 0;
unsigned long read = 0;
int ret;
@@ -212,7 +212,7 @@
DBG("usb_read got: %ld, expected: %d, errno: %d\n", read, xfer, errno);
if (ret) {
return read;
- } else if (errno != ERROR_SEM_TIMEOUT) {
+ } else {
// assume ERROR_INVALID_HANDLE indicates we are disconnected
if (errno == ERROR_INVALID_HANDLE)
usb_kick(handle);
diff --git a/fastboot/usbtest.c b/fastboot/usbtest.c
index b8fb9e2..e6e2b37 100644
--- a/fastboot/usbtest.c
+++ b/fastboot/usbtest.c
@@ -88,14 +88,14 @@
int test_null(usb_handle *usb)
{
- int i;
+ unsigned i;
unsigned char buf[4096];
memset(buf, 0xee, 4096);
long long t0, t1;
t0 = NOW();
for(i = 0; i < arg_count; i++) {
- if(usb_write(usb, buf, arg_size) != arg_size) {
+ if(usb_write(usb, buf, arg_size) != (int)arg_size) {
fprintf(stderr,"write failed (%s)\n", strerror(errno));
return -1;
}
@@ -107,13 +107,13 @@
int test_zero(usb_handle *usb)
{
- int i;
+ unsigned i;
unsigned char buf[4096];
long long t0, t1;
t0 = NOW();
for(i = 0; i < arg_count; i++) {
- if(usb_read(usb, buf, arg_size) != arg_size) {
+ if(usb_read(usb, buf, arg_size) != (int)arg_size) {
fprintf(stderr,"read failed (%s)\n", strerror(errno));
return -1;
}
@@ -130,11 +130,11 @@
int (*test)(usb_handle *usb);
const char *help;
} tests[] = {
- { "list", printifc, 0, "list interfaces" },
+ { "list", printifc, NULL, "list interfaces" },
{ "send", match_null, test_null, "send to null interface" },
{ "recv", match_zero, test_zero, "recv from zero interface" },
- { "loop", match_loop, 0, "exercise loopback interface" },
- {},
+ { "loop", match_loop, NULL, "exercise loopback interface" },
+ { NULL, NULL, NULL, NULL },
};
int usage(void)
diff --git a/fastbootd/transport.c b/fastbootd/transport.c
index ce8f9d0..9a16fd7 100644
--- a/fastbootd/transport.c
+++ b/fastbootd/transport.c
@@ -55,7 +55,7 @@
ftruncate(fd, len);
buffer = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (buffer == NULL) {
+ if (buffer == MAP_FAILED) {
D(ERR, "mmap(%zu) failed: %d %s", len, errno, strerror(errno));
goto err;
}
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 165ebd4..7cffc37 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -11,6 +11,7 @@
LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
@@ -31,5 +32,7 @@
LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_EXECUTABLE)
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 45bbfdc..f86fc6a 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -162,7 +162,6 @@
p = strtok_r(NULL, ",", &savep);
}
-out:
if (fs_options && fs_options[0]) {
/* remove the last trailing comma from the list of options */
fs_options[strlen(fs_options) - 1] = '\0';
@@ -181,7 +180,6 @@
const char *delim = " \t";
char *save_ptr, *p;
struct fstab *fstab = NULL;
- struct fstab_rec *recs;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 40bc2ec..c9a2a9b 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -85,7 +85,6 @@
static int verify_table(char *signature, char *table, int table_length)
{
- int fd;
RSAPublicKey *key;
uint8_t hash_buf[SHA_DIGEST_SIZE];
int retval = -1;
diff --git a/gpttool/Android.mk b/gpttool/Android.mk
index b8f9844..64ad945 100644
--- a/gpttool/Android.mk
+++ b/gpttool/Android.mk
@@ -5,6 +5,7 @@
LOCAL_SRC_FILES := gpttool.c
LOCAL_STATIC_LIBRARIES := libz
+LOCAL_CFLAGS := -Werror
LOCAL_MODULE := gpttool
diff --git a/gpttool/gpttool.c b/gpttool/gpttool.c
index d3f08fe..398362f 100644
--- a/gpttool/gpttool.c
+++ b/gpttool/gpttool.c
@@ -1,5 +1,4 @@
-/* system/core/gpttool/gpttool.c
-**
+/*
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,18 @@
** limitations under the License.
*/
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include <string.h>
-#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <zlib.h>
#include <linux/fs.h>
-#include <sys/stat.h>
-
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
@@ -252,11 +251,9 @@
int main(int argc, char **argv)
{
struct ptable ptbl;
- struct efi_entry *entry;
struct efi_header *hdr = &ptbl.header;
- struct stat s;
u32 n;
- u64 sz, blk;
+ u64 sz;
int fd;
const char *device;
int real_disk = 0;
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 9b84c3e..d30e771 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -126,7 +126,7 @@
KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
}
-#define UEVENT_MSG_LEN 1024
+#define UEVENT_MSG_LEN 2048
static void uevent_event(void) {
char msg[UEVENT_MSG_LEN+2];
char *cp;
diff --git a/include/android/log.h b/include/android/log.h
index 0ea4c29..1c171b7 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -98,8 +98,16 @@
*/
int __android_log_print(int prio, const char *tag, const char *fmt, ...)
#if defined(__GNUC__)
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format(gnu_printf, 3, 4)))
+#else
__attribute__ ((format(printf, 3, 4)))
#endif
+#else
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
;
/*
@@ -110,15 +118,23 @@
const char *fmt, va_list ap);
/*
- * Log an assertion failure and SIGTRAP the process to have a chance
- * to inspect it, if a debugger is attached. This uses the FATAL priority.
+ * Log an assertion failure and abort the process to have a chance
+ * to inspect it if a debugger is attached. This uses the FATAL priority.
*/
void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
+ const char *fmt, ...)
#if defined(__GNUC__)
__attribute__ ((noreturn))
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format(gnu_printf, 3, 4)))
+#else
__attribute__ ((format(printf, 3, 4)))
#endif
+#else
+ __attribute__ ((format(printf, 3, 4)))
+#endif
+#endif
;
#ifdef __cplusplus
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index 3c3a482..e07d322 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -47,6 +47,14 @@
// Forward declarations.
class BacktraceImpl;
+#if defined(__APPLE__)
+struct __darwin_ucontext;
+typedef __darwin_ucontext ucontext_t;
+#else
+struct ucontext;
+typedef ucontext ucontext_t;
+#endif
+
class Backtrace {
public:
// Create the correct Backtrace object based on what is to be unwound.
@@ -64,7 +72,7 @@
virtual ~Backtrace();
// Get the current stack trace and store in the backtrace_ structure.
- virtual bool Unwind(size_t num_ignore_frames);
+ virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL);
// Get the function name and offset into the function given the pc.
// If the string is empty, then no valid function name was found.
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 13083bd..c717f09 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -18,6 +18,7 @@
#define _BACKTRACE_BACKTRACE_MAP_H
#include <stdint.h>
+#include <sys/types.h>
#ifdef USE_MINGW
// MINGW does not define these constants.
#define PROT_NONE 0
diff --git a/include/corkscrew/backtrace.h b/include/corkscrew/backtrace.h
deleted file mode 100644
index 556ad04..0000000
--- a/include/corkscrew/backtrace.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* A stack unwinder. */
-
-#ifndef _CORKSCREW_BACKTRACE_H
-#define _CORKSCREW_BACKTRACE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <sys/types.h>
-#include <corkscrew/ptrace.h>
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-/*
- * Describes a single frame of a backtrace.
- */
-typedef struct {
- uintptr_t absolute_pc; /* absolute PC offset */
- uintptr_t stack_top; /* top of stack for this frame */
- size_t stack_size; /* size of this stack frame */
-} backtrace_frame_t;
-
-/*
- * Describes the symbols associated with a backtrace frame.
- */
-typedef struct {
- uintptr_t relative_pc; /* relative frame PC offset from the start of the library,
- or the absolute PC if the library is unknown */
- uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the
- library or 0 if the library is unknown */
- char* map_name; /* executable or library name, or NULL if unknown */
- char* symbol_name; /* symbol name, or NULL if unknown */
- char* demangled_name; /* demangled symbol name, or NULL if unknown */
-} backtrace_symbol_t;
-
-/*
- * Unwinds the call stack for the current thread of execution.
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- */
-ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-/*
- * Unwinds the call stack for a thread within this process.
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- *
- * The task is briefly suspended while the backtrace is being collected.
- */
-ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
- size_t ignore_depth, size_t max_depth);
-
-/*
- * Unwinds the call stack of a task within a remote process using ptrace().
- * Populates the backtrace array with the program counters from the call stack.
- * Returns the number of frames collected, or -1 if an error occurred.
- */
-ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-/*
- * Gets the symbols for each frame of a backtrace.
- * The symbols array must be big enough to hold one symbol record per frame.
- * The symbols must later be freed using free_backtrace_symbols.
- */
-void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
- backtrace_symbol_t* backtrace_symbols);
-
-/*
- * Gets the symbols for each frame of a backtrace from a remote process.
- * The symbols array must be big enough to hold one symbol record per frame.
- * The symbols must later be freed using free_backtrace_symbols.
- */
-void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
- const backtrace_frame_t* backtrace, size_t frames,
- backtrace_symbol_t* backtrace_symbols);
-
-/*
- * Frees the storage associated with backtrace symbols.
- */
-void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames);
-
-enum {
- // A hint for how big to make the line buffer for format_backtrace_line
- MAX_BACKTRACE_LINE_LENGTH = 800,
-};
-
-/**
- * Formats a line from a backtrace as a zero-terminated string into the specified buffer.
- */
-void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame,
- const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_H
diff --git a/include/corkscrew/demangle.h b/include/corkscrew/demangle.h
deleted file mode 100644
index 04b0225..0000000
--- a/include/corkscrew/demangle.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* C++ symbol name demangling. */
-
-#ifndef _CORKSCREW_DEMANGLE_H
-#define _CORKSCREW_DEMANGLE_H
-
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Demangles a C++ symbol name.
- * If name is NULL or if the name cannot be demangled, returns NULL.
- * Otherwise, returns a newly allocated string that contains the demangled name.
- *
- * The caller must free the returned string using free().
- */
-char* demangle_symbol_name(const char* name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_DEMANGLE_H
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
deleted file mode 100644
index 14bfad6..0000000
--- a/include/corkscrew/map_info.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Process memory map. */
-
-#ifndef _CORKSCREW_MAP_INFO_H
-#define _CORKSCREW_MAP_INFO_H
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct map_info {
- struct map_info* next;
- uintptr_t start;
- uintptr_t end;
- bool is_readable;
- bool is_writable;
- bool is_executable;
- void* data; // arbitrary data associated with the map by the user, initially NULL
- char name[];
-} map_info_t;
-
-/* Loads memory map from /proc/<tid>/maps. */
-map_info_t* load_map_info_list(pid_t tid);
-
-/* Frees memory map. */
-void free_map_info_list(map_info_t* milist);
-
-/* Finds the memory map that contains the specified address. */
-const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr);
-
-/* Returns true if the addr is in a readable map. */
-bool is_readable_map(const map_info_t* milist, uintptr_t addr);
-/* Returns true if the addr is in a writable map. */
-bool is_writable_map(const map_info_t* milist, uintptr_t addr);
-/* Returns true if the addr is in an executable map. */
-bool is_executable_map(const map_info_t* milist, uintptr_t addr);
-
-/* Acquires a reference to the memory map for this process.
- * The result is cached and refreshed automatically.
- * Make sure to release the map info when done. */
-map_info_t* acquire_my_map_info_list();
-
-/* Releases a reference to the map info for this process that was
- * previous acquired using acquire_my_map_info_list(). */
-void release_my_map_info_list(map_info_t* milist);
-
-/* Flushes the cached memory map so the next call to
- * acquire_my_map_info_list() gets fresh data. */
-void flush_my_map_info_list();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_MAP_INFO_H
diff --git a/include/corkscrew/ptrace.h b/include/corkscrew/ptrace.h
deleted file mode 100644
index 76276d8..0000000
--- a/include/corkscrew/ptrace.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Useful ptrace() utility functions. */
-
-#ifndef _CORKSCREW_PTRACE_H
-#define _CORKSCREW_PTRACE_H
-
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Stores information about a process that is used for several different
- * ptrace() based operations. */
-typedef struct {
- map_info_t* map_info_list;
-} ptrace_context_t;
-
-/* Describes how to access memory from a process. */
-typedef struct {
- pid_t tid;
- const map_info_t* map_info_list;
-} memory_t;
-
-#if __i386__
-/* ptrace() register context. */
-typedef struct pt_regs_x86 {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
- uint32_t esp;
- uint32_t xss;
-} pt_regs_x86_t;
-#endif
-
-#if __mips__
-/* ptrace() GET_REGS context. */
-typedef struct pt_regs_mips {
- uint64_t regs[32];
- uint64_t lo;
- uint64_t hi;
- uint64_t cp0_epc;
- uint64_t cp0_badvaddr;
- uint64_t cp0_status;
- uint64_t cp0_cause;
-} pt_regs_mips_t;
-#endif
-
-/*
- * Initializes a memory structure for accessing memory from this process.
- */
-void init_memory(memory_t* memory, const map_info_t* map_info_list);
-
-/*
- * Initializes a memory structure for accessing memory from another process
- * using ptrace().
- */
-void init_memory_ptrace(memory_t* memory, pid_t tid);
-
-/*
- * Reads a word of memory safely.
- * If the memory is local, ensures that the address is readable before dereferencing it.
- * Returns false and a value of 0xffffffff if the word could not be read.
- */
-bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value);
-
-/*
- * Reads a word of memory safely using ptrace().
- * Returns false and a value of 0xffffffff if the word could not be read.
- */
-bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value);
-
-/*
- * Loads information needed for examining a remote process using ptrace().
- * The caller must already have successfully attached to the process
- * using ptrace().
- *
- * The context can be used for any threads belonging to that process
- * assuming ptrace() is attached to them before performing the actual
- * unwinding. The context can continue to be used to decode backtraces
- * even after ptrace() has been detached from the process.
- */
-ptrace_context_t* load_ptrace_context(pid_t pid);
-
-/*
- * Frees a ptrace context.
- */
-void free_ptrace_context(ptrace_context_t* context);
-
-/*
- * Finds a symbol using ptrace.
- * Returns the containing map and information about the symbol, or
- * NULL if one or the other is not available.
- */
-void find_symbol_ptrace(const ptrace_context_t* context,
- uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_PTRACE_H
diff --git a/include/corkscrew/symbol_table.h b/include/corkscrew/symbol_table.h
deleted file mode 100644
index 4998750..0000000
--- a/include/corkscrew/symbol_table.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011 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 _CORKSCREW_SYMBOL_TABLE_H
-#define _CORKSCREW_SYMBOL_TABLE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- uintptr_t start;
- uintptr_t end;
- char* name;
-} symbol_t;
-
-typedef struct {
- symbol_t* symbols;
- size_t num_symbols;
-} symbol_table_t;
-
-/*
- * Loads a symbol table from a given file.
- * Returns NULL on error.
- */
-symbol_table_t* load_symbol_table(const char* filename);
-
-/*
- * Frees a symbol table.
- */
-void free_symbol_table(symbol_table_t* table);
-
-/*
- * Finds a symbol associated with an address in the symbol table.
- * Returns NULL if not found.
- */
-const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_SYMBOL_TABLE_H
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 4f90ef1..007a905 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -51,6 +51,8 @@
#include <cutils/atomic-x86.h>
#elif defined(__x86_64__)
#include <cutils/atomic-x86_64.h>
+#elif defined(__mips64)
+#include <cutils/atomic-mips64.h>
#elif defined(__mips__)
#include <cutils/atomic-mips.h>
#else
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
index f9d3e25..1ed833d 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -117,23 +117,6 @@
extern ANDROID_ATOMIC_INLINE int32_t
-android_atomic_swap(int32_t new_value, volatile int32_t *ptr)
-{
- int32_t prev, status;
- do {
- __asm__ __volatile__ (
- " move %[status], %[new_value]\n"
- " ll %[prev], (%[ptr])\n"
- " sc %[status], (%[ptr])\n"
- : [prev] "=&r" (prev), [status] "=&r" (status)
- : [ptr] "r" (ptr), [new_value] "r" (new_value)
- );
- } while (__builtin_expect(status == 0, 0));
- android_memory_barrier();
- return prev;
-}
-
-extern ANDROID_ATOMIC_INLINE int32_t
android_atomic_add(int32_t increment, volatile int32_t *ptr)
{
int32_t prev, status;
diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h
new file mode 100644
index 0000000..99bbe3a
--- /dev/null
+++ b/include/cutils/atomic-mips64.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 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 ANDROID_CUTILS_ATOMIC_MIPS64_H
+#define ANDROID_CUTILS_ATOMIC_MIPS64_H
+
+#include <stdint.h>
+
+#ifndef ANDROID_ATOMIC_INLINE
+#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))
+#endif
+
+extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void)
+{
+ __asm__ __volatile__ ("" : : : "memory");
+}
+
+#if ANDROID_SMP == 0
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+{
+ android_compiler_barrier();
+}
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+{
+ android_compiler_barrier();
+}
+#else
+extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
+{
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
+{
+ __asm__ __volatile__ ("sync" : : : "memory");
+}
+#endif
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
+{
+ int32_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
+{
+ int64_t value = *ptr;
+ android_memory_barrier();
+ return value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_release_load(volatile const int32_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_load64(volatile const int64_t *ptr)
+{
+ android_memory_barrier();
+ return *ptr;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
+{
+ *ptr = value;
+ android_memory_barrier();
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ *ptr = value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ do {
+ __asm__ __volatile__ (
+ " ll %[prev], (%[ptr])\n"
+ " li %[status], 1\n"
+ " bne %[prev], %[old], 9f\n"
+ " move %[status], %[new_value]\n"
+ " sc %[status], (%[ptr])\n"
+ "9:\n"
+ : [prev] "=&r" (prev), [status] "=&r" (status)
+ : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value)
+ );
+ } while (__builtin_expect(status == 0, 0));
+ return prev != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_acquire_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ int status = android_atomic_cas(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ int status = android_atomic_cas64(old_value, new_value, ptr);
+ android_memory_barrier();
+ return status;
+}
+
+extern ANDROID_ATOMIC_INLINE
+int android_atomic_release_cas(int32_t old_value,
+ int32_t new_value,
+ volatile int32_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
+ volatile int64_t *ptr)
+{
+ android_memory_barrier();
+ return android_atomic_cas64(old_value, new_value, ptr);
+}
+
+extern ANDROID_ATOMIC_INLINE
+int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ (
+ " ll %[prev], (%[ptr])\n"
+ " addu %[status], %[prev], %[inc]\n"
+ " sc %[status], (%[ptr])\n"
+ : [status] "=&r" (status), [prev] "=&r" (prev)
+ : [ptr] "r" (ptr), [inc] "Ir" (increment)
+ );
+ } while (__builtin_expect(status == 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_inc(volatile int32_t *addr)
+{
+ return android_atomic_add(1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_dec(volatile int32_t *addr)
+{
+ return android_atomic_add(-1, addr);
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_and(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ (
+ " ll %[prev], (%[ptr])\n"
+ " and %[status], %[prev], %[value]\n"
+ " sc %[status], (%[ptr])\n"
+ : [prev] "=&r" (prev), [status] "=&r" (status)
+ : [ptr] "r" (ptr), [value] "Ir" (value)
+ );
+ } while (__builtin_expect(status == 0, 0));
+ return prev;
+}
+
+extern ANDROID_ATOMIC_INLINE int32_t
+android_atomic_or(int32_t value, volatile int32_t *ptr)
+{
+ int32_t prev, status;
+ android_memory_barrier();
+ do {
+ __asm__ __volatile__ (
+ " ll %[prev], (%[ptr])\n"
+ " or %[status], %[prev], %[value]\n"
+ " sc %[status], (%[ptr])\n"
+ : [prev] "=&r" (prev), [status] "=&r" (status)
+ : [ptr] "r" (ptr), [value] "Ir" (value)
+ );
+ } while (__builtin_expect(status == 0, 0));
+ return prev;
+}
+
+#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */
diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h
index c26dc54..045830d 100644
--- a/include/cutils/bitops.h
+++ b/include/cutils/bitops.h
@@ -59,7 +59,7 @@
static inline int bitmask_ffz(unsigned int *bitmask, int num_bits)
{
int bit, result;
- unsigned int i;
+ size_t i;
for (i = 0; i < BITS_TO_WORDS(num_bits); i++) {
bit = ffs(~bitmask[i]);
@@ -77,7 +77,7 @@
static inline int bitmask_weight(unsigned int *bitmask, int num_bits)
{
- int i;
+ size_t i;
int weight = 0;
for (i = 0; i < BITS_TO_WORDS(num_bits); i++)
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index af80e2c..ae6bfc4 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -42,6 +42,7 @@
debugger_action_t action;
pid_t tid;
uintptr_t abort_msg_address;
+ int32_t original_si_code;
} debugger_msg_t;
/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index d1d4cf2..70f0b92 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -18,6 +18,7 @@
#define __CUTILS_FS_H
#include <sys/types.h>
+#include <unistd.h>
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
diff --git a/include/cutils/list.h b/include/cutils/list.h
index 945729a..4ba2cfd 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -44,10 +44,10 @@
#define list_for_each_reverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev)
-#define list_for_each_safe(node, next, list) \
- for (node = (list)->next, next = node->next; \
+#define list_for_each_safe(node, n, list) \
+ for (node = (list)->next, n = node->next; \
node != (list); \
- node = next, next = node->next)
+ node = n, n = node->next)
static inline void list_init(struct listnode *node)
{
@@ -63,6 +63,14 @@
head->prev = item;
}
+static inline void list_add_head(struct listnode *head, struct listnode *item)
+{
+ item->next = head->next;
+ item->prev = head;
+ head->next->prev = item;
+ head->next = item;
+}
+
static inline void list_remove(struct listnode *item)
{
item->next->prev = item->prev;
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 2c70165..798db8b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -20,6 +20,7 @@
#include <sys/cdefs.h>
#include <stddef.h>
#include <sys/system_properties.h>
+#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -44,6 +45,64 @@
*/
int property_get(const char *key, char *value, const char *default_value);
+/* property_get_bool: returns the value of key coerced into a
+** boolean. If the property is not set, then the default value is returned.
+**
+* The following is considered to be true (1):
+** "1", "true", "y", "yes", "on"
+**
+** The following is considered to be false (0):
+** "0", "false", "n", "no", "off"
+**
+** The conversion is whitespace-sensitive (e.g. " off" will not be false).
+**
+** If no property with this key is set (or the key is NULL) or the boolean
+** conversion fails, the default value is returned.
+**/
+int8_t property_get_bool(const char *key, int8_t default_value);
+
+/* property_get_int64: returns the value of key truncated and coerced into a
+** int64_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int64_t property_get_int64(const char *key, int64_t default_value);
+
+/* property_get_int32: returns the value of key truncated and coerced into an
+** int32_t. If the property is not set, then the default value is used.
+**
+** The numeric conversion is identical to strtoimax with the base inferred:
+** - All digits up to the first non-digit characters are read
+** - The longest consecutive prefix of digits is converted to a long
+**
+** Valid strings of digits are:
+** - An optional sign character + or -
+** - An optional prefix indicating the base (otherwise base 10 is assumed)
+** -- 0 prefix is octal
+** -- 0x / 0X prefix is hex
+**
+** Leading/trailing whitespace is ignored. Overflow/underflow will cause
+** numeric conversion to fail.
+**
+** If no property with this key is set (or the key is NULL) or the numeric
+** conversion fails, the default value is returned.
+**/
+int32_t property_get_int32(const char *key, int32_t default_value);
+
/* property_set: returns 0 on success, < 0 on failure
*/
int property_set(const char *key, const char *value);
diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h
index 19cae0c..daf43ec 100644
--- a/include/cutils/sockets.h
+++ b/include/cutils/sockets.h
@@ -86,6 +86,8 @@
extern int socket_loopback_client(int port, int type);
extern int socket_network_client(const char *host, int port, int type);
+extern int socket_network_client_timeout(const char *host, int port, int type,
+ int timeout);
extern int socket_loopback_server(int port, int type);
extern int socket_local_server(const char *name, int namespaceId, int type);
extern int socket_local_server_bind(int s, const char *name, int namespaceId);
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index dbd5e25..fd9bc6a 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <unistd.h>
@@ -68,7 +69,8 @@
#define ATRACE_TAG_RESOURCES (1<<13)
#define ATRACE_TAG_DALVIK (1<<14)
#define ATRACE_TAG_RS (1<<15)
-#define ATRACE_TAG_LAST ATRACE_TAG_RS
+#define ATRACE_TAG_BIONIC (1<<16)
+#define ATRACE_TAG_LAST ATRACE_TAG_BIONIC
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1LL<<63)
diff --git a/include/log/log.h b/include/log/log.h
index 5b76c1a..ace12d6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -491,7 +491,7 @@
#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
- ((void) 0) /* not implemented -- must combine len with string */
+ (void) __android_log_bswrite(_tag, _value);
#endif
/* TODO: something for LIST */
diff --git a/include/log/log_read.h b/include/log/log_read.h
index bd9de12..946711a 100644
--- a/include/log/log_read.h
+++ b/include/log/log_read.h
@@ -33,6 +33,9 @@
uint32_t tv_sec; // good to Feb 5 2106
uint32_t tv_nsec;
+ static const uint32_t tv_sec_max = 0xFFFFFFFFUL;
+ static const uint32_t tv_nsec_max = 999999999UL;
+
log_time(const timespec &T)
{
tv_sec = T.tv_sec;
@@ -64,7 +67,8 @@
// timespec
bool operator== (const timespec &T) const
{
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
+ return (tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
}
bool operator!= (const timespec &T) const
{
@@ -72,8 +76,9 @@
}
bool operator< (const timespec &T) const
{
- return (tv_sec < T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
+ return (tv_sec < static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
}
bool operator>= (const timespec &T) const
{
@@ -81,8 +86,9 @@
}
bool operator> (const timespec &T) const
{
- return (tv_sec > T.tv_sec)
- || ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
+ return (tv_sec > static_cast<uint32_t>(T.tv_sec))
+ || ((tv_sec == static_cast<uint32_t>(T.tv_sec))
+ && (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
}
bool operator<= (const timespec &T) const
{
diff --git a/include/log/logd.h b/include/log/logd.h
index 379c373..2e6f220 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -41,6 +41,7 @@
int __android_log_bwrite(int32_t tag, const void *payload, size_t len);
int __android_log_btwrite(int32_t tag, char type, const void *payload,
size_t len);
+int __android_log_bswrite(int32_t tag, const char *payload);
#ifdef __cplusplus
}
diff --git a/include/log/logger.h b/include/log/logger.h
index ed39c4f..53be1d3 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -62,9 +62,8 @@
/*
* The maximum size of the log entry payload that can be
- * written to the kernel logger driver. An attempt to write
- * more than this amount to /dev/log/* will result in a
- * truncated log entry.
+ * written to the logger. An attempt to write more than
+ * this amount will result in a truncated log entry.
*/
#define LOGGER_ENTRY_MAX_PAYLOAD 4076
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index d662107..d8e938e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -77,6 +77,7 @@
#define AID_SDCARD_AV 1034 /* external storage audio/video access */
#define AID_SDCARD_ALL 1035 /* access all users external storage */
#define AID_LOGD 1036 /* log daemon */
+#define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */
#define AID_SHELL 2000 /* adb and debug shell user */
#define AID_CACHE 2001 /* cache access */
@@ -93,6 +94,7 @@
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
+#define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
#define AID_MISC 9998 /* access to misc storage */
#define AID_NOBODY 9999
@@ -153,6 +155,7 @@
{ "sdcard_av", AID_SDCARD_AV, },
{ "sdcard_all", AID_SDCARD_ALL, },
{ "logd", AID_LOGD, },
+ { "shared_relro", AID_SHARED_RELRO, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
@@ -167,6 +170,7 @@
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
+ { "everybody", AID_EVERYBODY, },
{ "misc", AID_MISC, },
{ "nobody", AID_NOBODY, },
};
@@ -198,6 +202,7 @@
{ 00771, AID_SHELL, AID_SHELL, 0, "data/local" },
{ 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" },
{ 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" },
+ { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
@@ -239,7 +244,7 @@
/* the following five files are INTENTIONALLY set-uid, but they
* are NOT included on user builds. */
- { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/su" },
+ { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
diff --git a/include/system/audio.h b/include/system/audio.h
index aa7ac02..8838e71 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -434,6 +434,14 @@
static const audio_offload_info_t AUDIO_INFO_INITIALIZER = {
version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
size: sizeof(audio_offload_info_t),
+ sample_rate: 0,
+ channel_mask: 0,
+ format: AUDIO_FORMAT_DEFAULT,
+ stream_type: AUDIO_STREAM_VOICE_CALL,
+ bit_rate: 0,
+ duration_us: 0,
+ has_video: false,
+ is_streaming: false
};
static inline bool audio_is_output_device(audio_devices_t device)
@@ -471,12 +479,16 @@
static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
{
- device &= ~AUDIO_DEVICE_BIT_IN;
- if ((popcount(device) == 1) && (device & (AUDIO_DEVICE_OUT_ALL_SCO |
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)))
- return true;
- else
- return false;
+ if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL_SCO) == 0))
+ return true;
+ } else {
+ device &= ~AUDIO_DEVICE_BIT_IN;
+ if ((popcount(device) == 1) && ((device & ~AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) == 0))
+ return true;
+ }
+
+ return false;
}
static inline bool audio_is_usb_device(audio_devices_t device)
diff --git a/include/system/window.h b/include/system/window.h
index 588f9c6..31f202f 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -26,6 +26,13 @@
#include <system/graphics.h>
#include <unistd.h>
+#ifndef __UNUSED
+#define __UNUSED __attribute__((__unused__))
+#endif
+#ifndef __deprecated
+#define __deprecated __attribute__((__deprecated__))
+#endif
+
__BEGIN_DECLS
/*****************************************************************************/
@@ -89,10 +96,10 @@
// Implement the methods that sp<ANativeWindowBuffer> expects so that it
// can be used to automatically refcount ANativeWindowBuffer's.
- void incStrong(const void* id) const {
+ void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
- void decStrong(const void* id) const {
+ void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
@@ -352,10 +359,10 @@
/* Implement the methods that sp<ANativeWindow> expects so that it
can be used to automatically refcount ANativeWindow's. */
- void incStrong(const void* id) const {
+ void incStrong(const void* /*id*/) const {
common.incRef(const_cast<android_native_base_t*>(&common));
}
- void decStrong(const void* id) const {
+ void decStrong(const void* /*id*/) const {
common.decRef(const_cast<android_native_base_t*>(&common));
}
#endif
@@ -582,7 +589,7 @@
* android_native_window_t is deprecated.
*/
typedef struct ANativeWindow ANativeWindow;
-typedef struct ANativeWindow android_native_window_t;
+typedef struct ANativeWindow android_native_window_t __deprecated;
/*
* native_window_set_usage(..., usage)
@@ -603,13 +610,19 @@
/* deprecated. Always returns 0. Don't call. */
static inline int native_window_connect(
- struct ANativeWindow* window, int api) {
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_connect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
return 0;
}
/* deprecated. Always returns 0. Don't call. */
static inline int native_window_disconnect(
- struct ANativeWindow* window, int api) {
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) __deprecated;
+
+static inline int native_window_disconnect(
+ struct ANativeWindow* window __UNUSED, int api __UNUSED) {
return 0;
}
@@ -664,6 +677,10 @@
*/
static inline int native_window_set_active_rect(
struct ANativeWindow* window,
+ android_native_rect_t const * active_rect) __deprecated;
+
+static inline int native_window_set_active_rect(
+ struct ANativeWindow* window,
android_native_rect_t const * active_rect)
{
return native_window_set_post_transform_crop(window, active_rect);
@@ -691,6 +708,10 @@
*/
static inline int native_window_set_buffers_geometry(
struct ANativeWindow* window,
+ int w, int h, int format) __deprecated;
+
+static inline int native_window_set_buffers_geometry(
+ struct ANativeWindow* window,
int w, int h, int format)
{
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
diff --git a/include/utils/Functor.h b/include/utils/Functor.h
index e24ded4..09ea614 100644
--- a/include/utils/Functor.h
+++ b/include/utils/Functor.h
@@ -25,7 +25,7 @@
public:
Functor() {}
virtual ~Functor() {}
- virtual status_t operator ()(int what, void* data) { return NO_ERROR; }
+ virtual status_t operator ()(int /*what*/, void* /*data*/) { return NO_ERROR; }
};
}; // namespace android
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 053bfaf..9248ac9 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -56,7 +56,7 @@
bool next() {
mIndex = mCache.mTable->next(mIndex);
- return mIndex != -1;
+ return (ssize_t)mIndex != -1;
}
size_t index() const {
@@ -103,9 +103,13 @@
// Implementation is here, because it's fully templated
template <typename TKey, typename TValue>
-LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity),
- mNullValue(NULL), mTable(new BasicHashtable<TKey, Entry>), mYoungest(NULL), mOldest(NULL),
- mListener(NULL) {
+LruCache<TKey, TValue>::LruCache(uint32_t maxCapacity)
+ : mTable(new BasicHashtable<TKey, Entry>)
+ , mListener(NULL)
+ , mOldest(NULL)
+ , mYoungest(NULL)
+ , mMaxCapacity(maxCapacity)
+ , mNullValue(NULL) {
};
template<typename K, typename V>
diff --git a/init/Android.mk b/init/Android.mk
index 15a23be..489dc93 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -25,7 +25,7 @@
endif
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1
+LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
endif
# Enable ueventd logging
diff --git a/init/builtins.c b/init/builtins.c
index e2932d5..b32981e 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -33,7 +33,6 @@
#include <linux/loop.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
-#include <sys/system_properties.h>
#include <fs_mgr.h>
#include <selinux/selinux.h>
@@ -196,6 +195,8 @@
{
if (!(svc->flags & SVC_DISABLED)) {
service_start(svc, NULL);
+ } else {
+ svc->flags |= SVC_DISABLED_START;
}
}
@@ -238,6 +239,21 @@
return write_file("/proc/sys/kernel/domainname", args[1]);
}
+int do_enable(int nargs, char **args)
+{
+ struct service *svc;
+ svc = service_find_by_name(args[1]);
+ if (svc) {
+ svc->flags &= ~(SVC_DISABLED | SVC_RC_DISABLED);
+ if (svc->flags & SVC_DISABLED_START) {
+ service_start(svc, NULL);
+ }
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
int do_exec(int nargs, char **args)
{
return -1;
@@ -846,11 +862,24 @@
}
int do_loglevel(int nargs, char **args) {
- if (nargs == 2) {
- klog_set_level(atoi(args[1]));
- return 0;
+ int log_level;
+ char log_level_str[PROP_VALUE_MAX] = "";
+ if (nargs != 2) {
+ ERROR("loglevel: missing argument\n");
+ return -EINVAL;
}
- return -1;
+
+ if (expand_props(log_level_str, args[1], sizeof(log_level_str))) {
+ ERROR("loglevel: cannot expand '%s'\n", args[1]);
+ return -EINVAL;
+ }
+ log_level = atoi(log_level_str);
+ if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
+ ERROR("loglevel: invalid log level'%d'\n", log_level);
+ return -EINVAL;
+ }
+ klog_set_level(log_level);
+ return 0;
}
int do_load_persist_props(int nargs, char **args) {
@@ -861,6 +890,14 @@
return -1;
}
+int do_load_all_props(int nargs, char **args) {
+ if (nargs == 1) {
+ load_all_props();
+ return 0;
+ }
+ return -1;
+}
+
int do_wait(int nargs, char **args)
{
if (nargs == 2) {
diff --git a/init/devices.c b/init/devices.c
index 80c6d75..e27c311 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -15,6 +15,7 @@
*/
#include <errno.h>
+#include <fnmatch.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -77,6 +78,7 @@
unsigned int uid;
unsigned int gid;
unsigned short prefix;
+ unsigned short wildcard;
};
struct perm_node {
@@ -97,7 +99,8 @@
int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid, unsigned int gid,
- unsigned short prefix) {
+ unsigned short prefix,
+ unsigned short wildcard) {
struct perm_node *node = calloc(1, sizeof(*node));
if (!node)
return -ENOMEM;
@@ -116,6 +119,7 @@
node->dp.uid = uid;
node->dp.gid = gid;
node->dp.prefix = prefix;
+ node->dp.wildcard = wildcard;
if (attr)
list_add_tail(&sys_perms, &node->plist);
@@ -130,40 +134,62 @@
char buf[512];
struct listnode *node;
struct perms_ *dp;
- char *secontext;
- /* upaths omit the "/sys" that paths in this list
- * contain, so we add 4 when comparing...
- */
+ /* upaths omit the "/sys" that paths in this list
+ * contain, so we add 4 when comparing...
+ */
list_for_each(node, &sys_perms) {
dp = &(node_to_item(node, struct perm_node, plist))->dp;
if (dp->prefix) {
if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
continue;
+ } else if (dp->wildcard) {
+ if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
+ continue;
} else {
if (strcmp(upath, dp->name + 4))
continue;
}
if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
- return;
+ break;
sprintf(buf,"/sys%s/%s", upath, dp->attr);
INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
chown(buf, dp->uid, dp->gid);
chmod(buf, dp->perm);
- if (sehandle) {
- secontext = NULL;
- selabel_lookup(sehandle, &secontext, buf, 0);
- if (secontext) {
- setfilecon(buf, secontext);
- freecon(secontext);
- }
- }
+ }
+
+ // Now fixup SELinux file labels
+ int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
+ if ((len < 0) || ((size_t) len >= sizeof(buf))) {
+ // Overflow
+ return;
+ }
+ if (access(buf, F_OK) == 0) {
+ INFO("restorecon_recursive: %s\n", buf);
+ restorecon_recursive(buf);
}
}
-static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
+static bool perm_path_matches(const char *path, struct perms_ *dp)
+{
+ if (dp->prefix) {
+ if (strncmp(path, dp->name, strlen(dp->name)) == 0)
+ return true;
+ } else if (dp->wildcard) {
+ if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
+ return true;
+ } else {
+ if (strcmp(path, dp->name) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+static mode_t get_device_perm(const char *path, const char **links,
+ unsigned *uid, unsigned *gid)
{
mode_t perm;
struct listnode *node;
@@ -174,19 +200,30 @@
* override ueventd.rc
*/
list_for_each_reverse(node, &dev_perms) {
+ bool match = false;
+
perm_node = node_to_item(node, struct perm_node, plist);
dp = &perm_node->dp;
- if (dp->prefix) {
- if (strncmp(path, dp->name, strlen(dp->name)))
- continue;
+ if (perm_path_matches(path, dp)) {
+ match = true;
} else {
- if (strcmp(path, dp->name))
- continue;
+ if (links) {
+ int i;
+ for (i = 0; links[i]; i++) {
+ if (perm_path_matches(links[i], dp)) {
+ match = true;
+ break;
+ }
+ }
+ }
}
- *uid = dp->uid;
- *gid = dp->gid;
- return dp->perm;
+
+ if (match) {
+ *uid = dp->uid;
+ *gid = dp->gid;
+ return dp->perm;
+ }
}
/* Default if nothing found. */
*uid = 0;
@@ -196,7 +233,8 @@
static void make_device(const char *path,
const char *upath UNUSED,
- int block, int major, int minor)
+ int block, int major, int minor,
+ const char **links)
{
unsigned uid;
unsigned gid;
@@ -204,10 +242,10 @@
dev_t dev;
char *secontext = NULL;
- mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
+ mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
if (sehandle) {
- selabel_lookup(sehandle, &secontext, path, mode);
+ selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
setfscreatecon(secontext);
}
@@ -298,6 +336,37 @@
}
}
+/* Given a path that may start with a PCI device, populate the supplied buffer
+ * with the PCI domain/bus number and the peripheral ID and return 0.
+ * If it doesn't start with a PCI device, or there is some error, return -1 */
+static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
+{
+ const char *start, *end;
+
+ if (strncmp(path, "/devices/pci", 12))
+ return -1;
+
+ /* Beginning of the prefix is the initial "pci" after "/devices/" */
+ start = path + 9;
+
+ /* End of the prefix is two path '/' later, capturing the domain/bus number
+ * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
+ end = strchr(start, '/');
+ if (!end)
+ return -1;
+ end = strchr(end + 1, '/');
+ if (!end)
+ return -1;
+
+ /* Make sure we have enough room for the string plus null terminator */
+ if (end - start + 1 > buf_sz)
+ return -1;
+
+ strncpy(buf, start, end - start);
+ buf[end - start] = '\0';
+ return 0;
+}
+
#if LOG_UEVENTS
static inline suseconds_t get_usecs(void)
@@ -422,11 +491,12 @@
return NULL;
}
-static char **parse_platform_block_device(struct uevent *uevent)
+static char **get_block_device_symlinks(struct uevent *uevent)
{
const char *device;
struct platform_node *pdev;
char *slash;
+ const char *type;
int width;
char buf[256];
char link_path[256];
@@ -438,18 +508,24 @@
struct stat info;
pdev = find_platform_device(uevent->path);
- if (!pdev)
+ if (pdev) {
+ device = pdev->name;
+ type = "platform";
+ } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
+ device = buf;
+ type = "pci";
+ } else {
return NULL;
- device = pdev->name;
+ }
char **links = malloc(sizeof(char *) * 4);
if (!links)
return NULL;
memset(links, 0, sizeof(char *) * 4);
- INFO("found platform device %s\n", device);
+ INFO("found %s device %s\n", type, device);
- snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
+ snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
@@ -485,7 +561,7 @@
int i;
if(!strcmp(action, "add")) {
- make_device(devpath, path, block, major, minor);
+ make_device(devpath, path, block, major, minor, (const char **)links);
if (links) {
for (i = 0; links[i]; i++)
make_link(devpath, links[i]);
@@ -556,7 +632,7 @@
make_dir(base, 0755);
if (!strncmp(uevent->path, "/devices/", 9))
- links = parse_platform_block_device(uevent);
+ links = get_block_device_symlinks(uevent);
handle_device(uevent->action, devpath, uevent->path, 1,
uevent->major, uevent->minor, links);
@@ -699,7 +775,7 @@
static void handle_device_event(struct uevent *uevent)
{
- if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change"))
+ if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
fixup_sys_perms(uevent->path);
if (!strncmp(uevent->subsystem, "block", 5)) {
diff --git a/init/devices.h b/init/devices.h
index a84fa58..5d0fe88 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
extern void device_init(void);
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
- unsigned int gid, unsigned short prefix);
+ unsigned int gid, unsigned short prefix,
+ unsigned short wildcard);
int get_device_fd();
#endif /* _INIT_DEVICES_H */
diff --git a/init/init.c b/init/init.c
index 0884236..e4ac1cf 100644
--- a/init/init.c
+++ b/init/init.c
@@ -46,8 +46,6 @@
#include <private/android_filesystem_config.h>
#include <termios.h>
-#include <sys/system_properties.h>
-
#include "devices.h"
#include "init.h"
#include "log.h"
@@ -164,7 +162,7 @@
* state and immediately takes it out of the restarting
* state if it was in there
*/
- svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
+ svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
svc->time_started = 0;
/* running processes require no additional work -- if
@@ -364,7 +362,7 @@
{
/* The service is still SVC_RUNNING until its process exits, but if it has
* already exited it shoudn't attempt a restart yet. */
- svc->flags &= (~SVC_RESTARTING);
+ svc->flags &= ~(SVC_RESTARTING | SVC_DISABLED_START);
if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */
@@ -530,7 +528,8 @@
void execute_one_command(void)
{
- int ret;
+ int ret, i;
+ char cmd_str[256] = "";
if (!cur_action || !cur_command || is_last_command(cur_action, cur_command)) {
cur_action = action_remove_queue_head();
@@ -547,7 +546,17 @@
return;
ret = cur_command->func(cur_command->nargs, cur_command->args);
- INFO("command '%s' r=%d\n", cur_command->args[0], ret);
+ if (klog_get_level() >= KLOG_INFO_LEVEL) {
+ for (i = 0; i < cur_command->nargs; i++) {
+ strlcat(cmd_str, cur_command->args[i], sizeof(cmd_str));
+ if (i < cur_command->nargs - 1) {
+ strlcat(cmd_str, " ", sizeof(cmd_str));
+ }
+ }
+ INFO("command '%s' action=%s status=%d (%s:%d)\n",
+ cmd_str, cur_action ? cur_action->name : "", ret, cur_command->filename,
+ cur_command->line);
+ }
}
static int wait_for_coldboot_done_action(int nargs, char **args)
@@ -843,24 +852,21 @@
static const struct selinux_opt seopts_prop[] = {
{ SELABEL_OPT_PATH, "/property_contexts" },
+ { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
{ 0, NULL }
};
struct selabel_handle* selinux_android_prop_context_handle(void)
{
- int i = 0;
- struct selabel_handle* sehandle = NULL;
- while ((sehandle == NULL) && seopts_prop[i].value) {
- sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, &seopts_prop[i], 1);
- i++;
- }
-
+ int policy_index = selinux_android_use_data_policy() ? 1 : 0;
+ struct selabel_handle* sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
+ &seopts_prop[policy_index], 1);
if (!sehandle) {
ERROR("SELinux: Could not load property_contexts: %s\n",
strerror(errno));
return NULL;
}
- INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[i - 1].value);
+ INFO("SELinux: Loaded property contexts from %s\n", seopts_prop[policy_index].value);
return sehandle;
}
@@ -873,6 +879,7 @@
static bool selinux_is_disabled(void)
{
+#ifdef ALLOW_DISABLE_SELINUX
char tmp[PROP_VALUE_MAX];
if (access("/sys/fs/selinux", F_OK) != 0) {
@@ -886,12 +893,14 @@
/* SELinux is compiled into the kernel, but we've been told to disable it. */
return true;
}
+#endif
return false;
}
static bool selinux_is_enforcing(void)
{
+#ifdef ALLOW_DISABLE_SELINUX
char tmp[PROP_VALUE_MAX];
if (property_get("ro.boot.selinux", tmp) == 0) {
@@ -908,6 +917,7 @@
ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
}
+#endif
return true;
}
@@ -939,7 +949,7 @@
return 0;
}
-static int log_callback(int type, const char *fmt, ...)
+int log_callback(int type, const char *fmt, ...)
{
int level;
va_list ap;
@@ -1052,8 +1062,7 @@
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
- if (!is_charger)
- property_load_boot_defaults();
+ property_load_boot_defaults();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
@@ -1068,28 +1077,19 @@
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
- /* skip mounting filesystems in charger mode */
- if (!is_charger) {
- action_for_each_trigger("early-fs", action_add_queue_tail);
- action_for_each_trigger("fs", action_add_queue_tail);
- action_for_each_trigger("post-fs", action_add_queue_tail);
- action_for_each_trigger("post-fs-data", action_add_queue_tail);
- }
-
/* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
* wasn't ready immediately after wait_for_coldboot_done
*/
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
-
queue_builtin_action(property_service_init_action, "property_service_init");
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action(check_startup_action, "check_startup");
+ /* Don't mount filesystems or start core system services if in charger mode. */
if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
- action_for_each_trigger("early-boot", action_add_queue_tail);
- action_for_each_trigger("boot", action_add_queue_tail);
+ action_for_each_trigger("late-init", action_add_queue_tail);
}
/* run all property triggers based on current state of the properties */
diff --git a/init/init.h b/init/init.h
index 736b75b..a7615a3 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,10 +29,14 @@
struct listnode clist;
int (*func)(int nargs, char **args);
+
+ int line;
+ const char *filename;
+
int nargs;
char *args[1];
};
-
+
struct action {
/* node in list of all actions */
struct listnode alist;
@@ -43,7 +47,7 @@
unsigned hash;
const char *name;
-
+
struct listnode commands;
struct command *current;
};
@@ -74,6 +78,7 @@
so it can be restarted with its class */
#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */
#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */
+#define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
diff --git a/init/init_parser.c b/init/init_parser.c
index f49e698..6466db2 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -33,9 +33,6 @@
#include <cutils/iosched_policy.h>
#include <cutils/list.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
@@ -98,6 +95,7 @@
if (!strcmp(s, "omainname")) return K_domainname;
break;
case 'e':
+ if (!strcmp(s, "nable")) return K_enable;
if (!strcmp(s, "xec")) return K_exec;
if (!strcmp(s, "xport")) return K_export;
break;
@@ -119,6 +117,7 @@
case 'l':
if (!strcmp(s, "oglevel")) return K_loglevel;
if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
+ if (!strcmp(s, "oad_all_props")) return K_load_all_props;
break;
case 'm':
if (!strcmp(s, "kdir")) return K_mkdir;
@@ -582,6 +581,7 @@
cmd = calloc(1, sizeof(*cmd));
cmd->func = func;
cmd->args[0] = name;
+ cmd->nargs = 1;
list_add_tail(&act->commands, &cmd->clist);
list_add_tail(&action_list, &act->alist);
@@ -759,7 +759,7 @@
break;
case K_setenv: { /* name value */
struct svcenvinfo *ei;
- if (nargs < 2) {
+ if (nargs < 3) {
parse_error(state, "setenv option requires name and value arguments\n");
break;
}
@@ -868,6 +868,8 @@
}
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
+ cmd->line = state->line;
+ cmd->filename = state->filename;
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
list_add_tail(&act->commands, &cmd->clist);
diff --git a/init/keywords.h b/init/keywords.h
index 97fe50c..2d97e5b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -6,6 +6,7 @@
int do_class_stop(int nargs, char **args);
int do_class_reset(int nargs, char **args);
int do_domainname(int nargs, char **args);
+int do_enable(int nargs, char **args);
int do_exec(int nargs, char **args);
int do_export(int nargs, char **args);
int do_hostname(int nargs, char **args);
@@ -38,6 +39,7 @@
int do_chmod(int nargs, char **args);
int do_loglevel(int nargs, char **args);
int do_load_persist_props(int nargs, char **args);
+int do_load_all_props(int nargs, char **args);
int do_wait(int nargs, char **args);
#define __MAKE_KEYWORD_ENUM__
#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
@@ -55,6 +57,7 @@
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
+ KEYWORD(enable, COMMAND, 1, do_enable)
KEYWORD(exec, COMMAND, 1, do_exec)
KEYWORD(export, COMMAND, 2, do_export)
KEYWORD(group, OPTION, 0, 0)
@@ -99,6 +102,7 @@
KEYWORD(chmod, COMMAND, 2, do_chmod)
KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
+ KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
KEYWORD(ioprio, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
diff --git a/init/log.h b/init/log.h
index 0ba770f..e9cb65a 100644
--- a/init/log.h
+++ b/init/log.h
@@ -23,4 +23,6 @@
#define NOTICE(x...) KLOG_NOTICE("init", x)
#define INFO(x...) KLOG_INFO("init", x)
+extern int log_callback(int type, const char *fmt, ...);
+
#endif
diff --git a/init/property_service.c b/init/property_service.c
index eb19f93..d112699 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -38,7 +38,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/mman.h>
-#include <sys/atomics.h>
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
@@ -56,63 +55,6 @@
static int property_set_fd = -1;
-/* White list of permissions for setting property services. */
-struct {
- const char *prefix;
- unsigned int uid;
- unsigned int gid;
-} property_perms[] = {
- { "net.rmnet0.", AID_RADIO, 0 },
- { "net.gprs.", AID_RADIO, 0 },
- { "net.ppp", AID_RADIO, 0 },
- { "net.qmi", AID_RADIO, 0 },
- { "net.lte", AID_RADIO, 0 },
- { "net.cdma", AID_RADIO, 0 },
- { "ril.", AID_RADIO, 0 },
- { "gsm.", AID_RADIO, 0 },
- { "persist.radio", AID_RADIO, 0 },
- { "net.dns", AID_RADIO, 0 },
- { "sys.usb.config", AID_RADIO, 0 },
- { "net.", AID_SYSTEM, 0 },
- { "dev.", AID_SYSTEM, 0 },
- { "runtime.", AID_SYSTEM, 0 },
- { "hw.", AID_SYSTEM, 0 },
- { "sys.", AID_SYSTEM, 0 },
- { "sys.powerctl", AID_SHELL, 0 },
- { "service.", AID_SYSTEM, 0 },
- { "wlan.", AID_SYSTEM, 0 },
- { "gps.", AID_GPS, 0 },
- { "bluetooth.", AID_BLUETOOTH, 0 },
- { "dhcp.", AID_SYSTEM, 0 },
- { "dhcp.", AID_DHCP, 0 },
- { "debug.", AID_SYSTEM, 0 },
- { "debug.", AID_SHELL, 0 },
- { "log.", AID_SHELL, 0 },
- { "service.adb.root", AID_SHELL, 0 },
- { "service.adb.tcp.port", AID_SHELL, 0 },
- { "persist.sys.", AID_SYSTEM, 0 },
- { "persist.service.", AID_SYSTEM, 0 },
- { "persist.security.", AID_SYSTEM, 0 },
- { "persist.gps.", AID_GPS, 0 },
- { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
- { "selinux." , AID_SYSTEM, 0 },
- { NULL, 0, 0 }
-};
-
-/*
- * White list of UID that are allowed to start/stop services.
- * Currently there are no user apps that require.
- */
-struct {
- const char *service;
- unsigned int uid;
- unsigned int gid;
-} control_perms[] = {
- { "dumpstate",AID_SHELL, AID_LOG },
- { "ril-daemon",AID_RADIO, AID_RADIO },
- {NULL, 0, 0 }
-};
-
typedef struct {
size_t size;
int fd;
@@ -194,34 +136,10 @@
}
/*
- * Checks permissions for starting/stoping system services.
- * AID_SYSTEM and AID_ROOT are always allowed.
- *
- * Returns 1 if uid allowed, 0 otherwise.
- */
-static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
-
- int i;
- if (uid == AID_SYSTEM || uid == AID_ROOT)
- return check_control_mac_perms(name, sctx);
-
- /* Search the ACL */
- for (i = 0; control_perms[i].service; i++) {
- if (strcmp(control_perms[i].service, name) == 0) {
- if ((uid && control_perms[i].uid == uid) ||
- (gid && control_perms[i].gid == gid)) {
- return check_control_mac_perms(name, sctx);
- }
- }
- }
- return 0;
-}
-
-/*
* Checks permissions for setting system properties.
* Returns 1 if uid allowed, 0 otherwise.
*/
-static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
+static int check_perms(const char *name, char *sctx)
{
int i;
unsigned int app_id;
@@ -229,26 +147,7 @@
if(!strncmp(name, "ro.", 3))
name +=3;
- if (uid == 0)
- return check_mac_perms(name, sctx);
-
- app_id = multiuser_get_app_id(uid);
- if (app_id == AID_BLUETOOTH) {
- uid = app_id;
- }
-
- for (i = 0; property_perms[i].prefix; i++) {
- if (strncmp(property_perms[i].prefix, name,
- strlen(property_perms[i].prefix)) == 0) {
- if ((uid && property_perms[i].uid == uid) ||
- (gid && property_perms[i].gid == gid)) {
-
- return check_mac_perms(name, sctx);
- }
- }
- }
-
- return 0;
+ return check_mac_perms(name, sctx);
}
int __property_get(const char *name, char *value)
@@ -406,14 +305,14 @@
// Keep the old close-socket-early behavior when handling
// ctl.* properties.
close(s);
- if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
+ if (check_control_mac_perms(msg.value, source_ctx)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
}
} else {
- if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
+ if (check_perms(msg.name, source_ctx)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
ERROR("sys_prop: permission denied uid:%d name:%s\n",
@@ -557,7 +456,8 @@
|| (sb.st_gid != 0)
|| (sb.st_nlink != 1)) {
ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%d mode=%o)\n",
- entry->d_name, sb.st_uid, sb.st_gid, sb.st_nlink, sb.st_mode);
+ entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
+ sb.st_nlink, sb.st_mode);
close(fd);
continue;
}
@@ -620,10 +520,8 @@
load_persistent_properties();
}
-void start_property_service(void)
+void load_all_props(void)
{
- int fd;
-
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
@@ -632,6 +530,11 @@
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
+}
+
+void start_property_service(void)
+{
+ int fd;
fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
if(fd < 0) return;
diff --git a/init/property_service.h b/init/property_service.h
index 46cbd8f..730495e 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,6 +24,7 @@
extern void property_init(void);
extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
+extern void load_all_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
extern int __property_get(const char *name, char *value);
diff --git a/init/readme.txt b/init/readme.txt
index 42a09cb..613a9e9 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -178,6 +178,16 @@
domainname <name>
Set the domain name.
+enable <servicename>
+ Turns a disabled service into an enabled one as if the service did not
+ specify disabled.
+ If the service is supposed to be running, it will be started now.
+ Typically used when the bootloader sets a variable that indicates a specific
+ service should be started when needed. E.g.
+ on property:ro.boot.myfancyhardware=1
+ enable my_fancy_service_for_my_fancy_hardware
+
+
insmod <path>
Install the module at <path>
diff --git a/init/ueventd.c b/init/ueventd.c
index 662196d..833e4fd 100644
--- a/init/ueventd.c
+++ b/init/ueventd.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
+#include <selinux/selinux.h>
#include <private/android_filesystem_config.h>
@@ -76,6 +77,10 @@
}
#endif
+ union selinux_callback cb;
+ cb.func_log = log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
INFO("starting ueventd\n");
/* Respect hardware passed in through the kernel cmd line. Here we will look
@@ -122,6 +127,7 @@
uid_t uid;
gid_t gid;
int prefix = 0;
+ int wildcard = 0;
char *endptr;
int ret;
char *tmp = 0;
@@ -154,9 +160,13 @@
name = tmp;
} else {
int len = strlen(name);
- if (name[len - 1] == '*') {
+ char *wildcard_chr = strchr(name, '*');
+ if ((name[len - 1] == '*') &&
+ (wildcard_chr == (name + len - 1))) {
prefix = 1;
name[len - 1] = '\0';
+ } else if (wildcard_chr) {
+ wildcard = 1;
}
}
@@ -183,6 +193,6 @@
}
gid = ret;
- add_dev_perms(name, attr, perm, uid, gid, prefix);
+ add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
free(tmp);
}
diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk
index 3c80cc2..2f55645 100644
--- a/libbacktrace/Android.build.mk
+++ b/libbacktrace/Android.build.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE := $(module)
LOCAL_MODULE_TAGS := $(module_tag)
+LOCAL_MULTILIB := $($(module)_multilib)
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(LOCAL_PATH)/Android.mk \
@@ -60,7 +61,11 @@
$($(module)_ldlibs_$(build_type)) \
ifeq ($(build_type),target)
- include external/stlport/libstlport.mk
+ ifneq ($($(module)_libc++),)
+ include external/libcxx/libcxx.mk
+ else
+ include external/stlport/libstlport.mk
+ endif
include $(BUILD_$(build_target))
endif
@@ -68,6 +73,9 @@
ifeq ($(build_type),host)
# Only build if host builds are supported.
ifeq ($(build_host),true)
+ ifneq ($($(module)_libc++),)
+ include external/libcxx/libcxx.mk
+ endif
include $(BUILD_HOST_$(build_target))
endif
endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index fdcb162..c321369 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -46,10 +46,6 @@
libcutils \
libgccdemangle \
-# To enable using libunwind on each arch, add it to this list.
-libunwind_architectures := arm arm64 mips x86 x86_64
-
-ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
libbacktrace_src_files += \
UnwindCurrent.cpp \
UnwindMap.cpp \
@@ -68,24 +64,6 @@
libbacktrace_static_libraries_host := \
libcutils \
-else
-libbacktrace_src_files += \
- Corkscrew.cpp \
-
-libbacktrace_c_includes := \
- system/core/libcorkscrew \
-
-libbacktrace_shared_libraries := \
- libcorkscrew \
-
-libbacktrace_shared_libraries_target += \
- libdl \
-
-libbacktrace_ldlibs_host := \
- -ldl \
-
-endif
-
module := libbacktrace
module_tag := optional
build_type := target
@@ -94,6 +72,52 @@
build_type := host
include $(LOCAL_PATH)/Android.build.mk
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+libbacktrace_libc++_src_files := \
+ BacktraceImpl.cpp \
+ BacktraceMap.cpp \
+ BacktraceThread.cpp \
+ thread_utils.c \
+
+libbacktrace_libc++_shared_libraries_target := \
+ libcutils \
+ libgccdemangle \
+
+libbacktrace_libc++_src_files += \
+ UnwindCurrent.cpp \
+ UnwindMap.cpp \
+ UnwindPtrace.cpp \
+
+libbacktrace_libc++_c_includes := \
+ external/libunwind/include \
+
+libbacktrace_libc++_shared_libraries := \
+ libunwind \
+ libunwind-ptrace \
+
+libbacktrace_libc++_shared_libraries_host := \
+ liblog \
+
+libbacktrace_libc++_static_libraries_host := \
+ libcutils \
+
+libbacktrace_libc++_libc++ := true
+
+module := libbacktrace_libc++
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+libbacktrace_libc++_multilib := both
+include $(LOCAL_PATH)/Android.build.mk
+libbacktrace_libc++_multilib :=
+endif
+
#-------------------------------------------------------------------------
# The libbacktrace_test library needed by backtrace_test.
#-------------------------------------------------------------------------
@@ -118,11 +142,8 @@
-fno-builtin \
-O0 \
-g \
- -DGTEST_HAS_STD_STRING \
- -fstack-protector-all \
backtrace_test_cflags_target := \
- -DGTEST_OS_LINUX_ANDROID \
-DENABLE_PSS_TESTS \
backtrace_test_src_files := \
@@ -130,10 +151,8 @@
GetPss.cpp \
thread_utils.c \
-backtrace_test_ldlibs := \
- -lpthread \
-
backtrace_test_ldlibs_host := \
+ -lpthread \
-lrt \
backtrace_test_shared_libraries := \
@@ -143,6 +162,9 @@
backtrace_test_shared_libraries_target := \
libcutils \
+backtrace_test_static_libraries_host := \
+ libcutils \
+
module := backtrace_test
module_tag := debug
build_type := target
@@ -166,4 +188,23 @@
include $(BUILD_HOST_SHARED_LIBRARY)
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+#-------------------------------------------------------------------------
+# The libbacktrace library (libc++)
+#-------------------------------------------------------------------------
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbacktrace_libc++
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ BacktraceMap.cpp \
+
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # TARGET_BUILD_APPS
+
endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceImpl.cpp b/libbacktrace/BacktraceImpl.cpp
index 05007d9..405b042 100644
--- a/libbacktrace/BacktraceImpl.cpp
+++ b/libbacktrace/BacktraceImpl.cpp
@@ -19,6 +19,7 @@
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
+#include <ucontext.h>
#include <unistd.h>
#include <string>
@@ -55,8 +56,8 @@
}
}
-bool Backtrace::Unwind(size_t num_ignore_frames) {
- return impl_->Unwind(num_ignore_frames);
+bool Backtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ return impl_->Unwind(num_ignore_frames, ucontext);
}
extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
diff --git a/libbacktrace/BacktraceImpl.h b/libbacktrace/BacktraceImpl.h
index 7b31c38..d34ad05 100755
--- a/libbacktrace/BacktraceImpl.h
+++ b/libbacktrace/BacktraceImpl.h
@@ -26,7 +26,7 @@
public:
virtual ~BacktraceImpl() { }
- virtual bool Unwind(size_t num_ignore_frames) = 0;
+ virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
// The name returned is not demangled, Backtrace::GetFunctionName()
// takes care of demangling the name.
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 6eb290d..0056f4b 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -108,11 +108,11 @@
#if defined(__APPLE__)
// cmd is guaranteed to always be big enough to hold this string.
- sprintf(cmd, "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
+ snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
FILE* fp = popen(cmd, "r");
#else
// path is guaranteed to always be big enough to hold this string.
- sprintf(path, "/proc/%d/maps", pid_);
+ snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
FILE* fp = fopen(path, "r");
#endif
if (fp == NULL) {
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index 4cda19e..b47cd2a 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -16,10 +16,15 @@
#include <errno.h>
#include <inttypes.h>
+#include <limits.h>
+#include <linux/futex.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
#include <sys/types.h>
+#include <ucontext.h>
#include <cutils/atomic.h>
@@ -27,190 +32,179 @@
#include "BacktraceThread.h"
#include "thread_utils.h"
+static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) {
+ return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
+}
+
//-------------------------------------------------------------------------
// ThreadEntry implementation.
//-------------------------------------------------------------------------
-static ThreadEntry* g_list = NULL;
-static pthread_mutex_t g_entry_mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
+ThreadEntry* ThreadEntry::list_ = NULL;
+pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-ThreadEntry::ThreadEntry(
- BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames)
- : thread_intf(intf), pid(pid), tid(tid), next(NULL), prev(NULL),
- state(STATE_WAITING), num_ignore_frames(num_ignore_frames) {
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// creating a ThreadEntry object.
+ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
+ : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) {
+ // Add ourselves to the list.
+ if (ThreadEntry::list_) {
+ ThreadEntry::list_->prev_ = this;
+ }
+ ThreadEntry::list_ = this;
}
-ThreadEntry::~ThreadEntry() {
- pthread_mutex_lock(&g_entry_mutex);
- if (g_list == this) {
- g_list = next;
+ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
+ pthread_mutex_lock(&ThreadEntry::list_mutex_);
+ ThreadEntry* entry = list_;
+ while (entry != NULL) {
+ if (entry->Match(pid, tid)) {
+ break;
+ }
+ entry = entry->next_;
+ }
+
+ if (!entry) {
+ if (create) {
+ entry = new ThreadEntry(pid, tid);
+ }
} else {
- if (next) {
- next->prev = prev;
- }
- prev->next = next;
+ entry->ref_count_++;
}
- pthread_mutex_unlock(&g_entry_mutex);
-
- next = NULL;
- prev = NULL;
-}
-
-ThreadEntry* ThreadEntry::AddThreadToUnwind(
- BacktraceThreadInterface* intf, pid_t pid, pid_t tid, size_t num_ignore_frames) {
- ThreadEntry* entry = new ThreadEntry(intf, pid, tid, num_ignore_frames);
-
- pthread_mutex_lock(&g_entry_mutex);
- ThreadEntry* cur_entry = g_list;
- while (cur_entry != NULL) {
- if (cur_entry->Match(pid, tid)) {
- // There is already an entry for this pid/tid, this is bad.
- BACK_LOGW("Entry for pid %d tid %d already exists.", pid, tid);
-
- pthread_mutex_unlock(&g_entry_mutex);
- return NULL;
- }
- cur_entry = cur_entry->next;
- }
-
- // Add the entry to the list.
- entry->next = g_list;
- if (g_list) {
- g_list->prev = entry;
- }
- g_list = entry;
- pthread_mutex_unlock(&g_entry_mutex);
+ pthread_mutex_unlock(&ThreadEntry::list_mutex_);
return entry;
}
+void ThreadEntry::Remove(ThreadEntry* entry) {
+ pthread_mutex_unlock(&entry->mutex_);
+
+ pthread_mutex_lock(&ThreadEntry::list_mutex_);
+ if (--entry->ref_count_ == 0) {
+ delete entry;
+ }
+ pthread_mutex_unlock(&ThreadEntry::list_mutex_);
+}
+
+// Assumes that ThreadEntry::list_mutex_ has already been locked before
+// deleting a ThreadEntry object.
+ThreadEntry::~ThreadEntry() {
+ if (list_ == this) {
+ list_ = next_;
+ } else {
+ if (next_) {
+ next_->prev_ = prev_;
+ }
+ prev_->next_ = next_;
+ }
+
+ next_ = NULL;
+ prev_ = NULL;
+}
+
+void ThreadEntry::Wait(int value) {
+ timespec ts;
+ ts.tv_sec = 10;
+ ts.tv_nsec = 0;
+ errno = 0;
+ futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
+ if (errno != 0 && errno != EWOULDBLOCK) {
+ BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
+ }
+}
+
+void ThreadEntry::Wake() {
+ futex_++;
+ futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+}
+
+void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
+ // The only thing the unwinder cares about is the mcontext data.
+ memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
+}
+
//-------------------------------------------------------------------------
// BacktraceThread functions.
//-------------------------------------------------------------------------
-static void SignalHandler(int n __attribute__((unused)), siginfo_t* siginfo,
- void* sigcontext) {
- if (pthread_mutex_lock(&g_entry_mutex) == 0) {
- pid_t pid = getpid();
- pid_t tid = gettid();
- ThreadEntry* cur_entry = g_list;
- while (cur_entry) {
- if (cur_entry->Match(pid, tid)) {
- break;
- }
- cur_entry = cur_entry->next;
- }
- pthread_mutex_unlock(&g_entry_mutex);
- if (!cur_entry) {
- BACK_LOGW("Unable to find pid %d tid %d information", pid, tid);
- return;
- }
+static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
- if (android_atomic_acquire_cas(STATE_WAITING, STATE_DUMPING, &cur_entry->state) == 0) {
- cur_entry->thread_intf->ThreadUnwind(siginfo, sigcontext,
- cur_entry->num_ignore_frames);
- }
- android_atomic_release_store(STATE_DONE, &cur_entry->state);
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
+ ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
+ if (!entry) {
+ BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
+ return;
}
+
+ entry->CopyUcontextFromSigcontext(sigcontext);
+
+ // Indicate the ucontext is now valid.
+ entry->Wake();
+
+ // Pause the thread until the unwind is complete. This avoids having
+ // the thread run ahead causing problems.
+ entry->Wait(1);
+
+ ThreadEntry::Remove(entry);
}
-BacktraceThread::BacktraceThread(
- BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
- BacktraceMap* map)
- : BacktraceCurrent(impl, map), thread_intf_(thread_intf) {
+BacktraceThread::BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map)
+ : BacktraceCurrent(impl, map) {
tid_ = tid;
}
BacktraceThread::~BacktraceThread() {
}
-void BacktraceThread::FinishUnwind() {
- for (std::vector<backtrace_frame_data_t>::iterator it = frames_.begin();
- it != frames_.end(); ++it) {
- it->map = FindMap(it->pc);
-
- it->func_offset = 0;
- it->func_name = GetFunctionName(it->pc, &it->func_offset);
- }
-}
-
-bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
- entry->state = STATE_WAITING;
-
- if (tgkill(Pid(), Tid(), SIGURG) != 0) {
- BACK_LOGW("tgkill failed %s", strerror(errno));
- return false;
- }
-
- // Allow up to ten seconds for the dump to start.
- int wait_millis = 10000;
- int32_t state;
- while (true) {
- state = android_atomic_acquire_load(&entry->state);
- if (state != STATE_WAITING) {
- break;
- }
- if (wait_millis--) {
- usleep(1000);
- } else {
- break;
- }
- }
-
- bool cancelled = false;
- if (state == STATE_WAITING) {
- if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
- BACK_LOGW("Cancelled dump of thread %d", entry->tid);
- state = STATE_CANCEL;
- cancelled = true;
- } else {
- state = android_atomic_acquire_load(&entry->state);
- }
- }
-
- // Wait for at most ten seconds for the cancel or dump to finish.
- wait_millis = 10000;
- while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
- if (wait_millis--) {
- usleep(1000);
- } else {
- BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
- break;
- }
- }
- return !cancelled;
-}
-
-bool BacktraceThread::Unwind(size_t num_ignore_frames) {
- ThreadEntry* entry = ThreadEntry::AddThreadToUnwind(
- thread_intf_, Pid(), Tid(), num_ignore_frames);
- if (!entry) {
- return false;
+bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ if (ucontext) {
+ // Unwind using an already existing ucontext.
+ return impl_->Unwind(num_ignore_frames, ucontext);
}
// Prevent multiple threads trying to set the trigger action on different
// threads at the same time.
- bool retval = false;
- if (pthread_mutex_lock(&g_sigaction_mutex) == 0) {
- struct sigaction act, oldact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalHandler;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- sigemptyset(&act.sa_mask);
- if (sigaction(SIGURG, &act, &oldact) == 0) {
- retval = TriggerUnwindOnThread(entry);
- sigaction(SIGURG, &oldact, NULL);
- } else {
- BACK_LOGW("sigaction failed %s", strerror(errno));
- }
+ if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
+ BACK_LOGW("sigaction failed: %s", strerror(errno));
+ return false;
+ }
+
+ ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
+ entry->Lock();
+
+ struct sigaction act, oldact;
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = SignalHandler;
+ act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
+ sigemptyset(&act.sa_mask);
+ if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
+ BACK_LOGW("sigaction failed %s", strerror(errno));
+ entry->Unlock();
+ ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
- } else {
- BACK_LOGW("unable to acquire sigaction mutex.");
+ return false;
}
- if (retval) {
- FinishUnwind();
+ if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
+ BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
+ sigaction(THREAD_SIGNAL, &oldact, NULL);
+ entry->Unlock();
+ ThreadEntry::Remove(entry);
+ pthread_mutex_unlock(&g_sigaction_mutex);
+ return false;
}
- delete entry;
- return retval;
+ // Wait for the thread to get the ucontext.
+ entry->Wait(0);
+
+ // After the thread has received the signal, allow other unwinders to
+ // continue.
+ sigaction(THREAD_SIGNAL, &oldact, NULL);
+ pthread_mutex_unlock(&g_sigaction_mutex);
+
+ bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());
+
+ // Tell the signal handler to exit and release the entry.
+ entry->Wake();
+
+ return unwind_done;
}
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index 3412d58..ff3e9f3 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -18,73 +18,71 @@
#define _LIBBACKTRACE_BACKTRACE_THREAD_H
#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
#include <sys/types.h>
+#include <ucontext.h>
#include "BacktraceImpl.h"
-enum state_e {
- STATE_WAITING = 0,
- STATE_DUMPING,
- STATE_DONE,
- STATE_CANCEL,
-};
+// The signal used to cause a thread to dump the stack.
+#if defined(__GLIBC__)
+// GLIBC reserves __SIGRTMIN signals, so use SIGRTMIN to avoid errors.
+#define THREAD_SIGNAL SIGRTMIN
+#else
+#define THREAD_SIGNAL (__SIGRTMIN+1)
+#endif
-class BacktraceThreadInterface;
+class ThreadEntry {
+public:
+ static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
-struct ThreadEntry {
- ThreadEntry(
- BacktraceThreadInterface* impl, pid_t pid, pid_t tid,
- size_t num_ignore_frames);
+ static void Remove(ThreadEntry* entry);
+
+ void Wake();
+
+ void Wait(int);
+
+ void CopyUcontextFromSigcontext(void*);
+
+ inline void Lock() {
+ pthread_mutex_lock(&mutex_);
+ // Reset the futex value in case of multiple unwinds of the same thread.
+ futex_ = 0;
+ }
+
+ inline void Unlock() {
+ pthread_mutex_unlock(&mutex_);
+ }
+
+ inline ucontext_t* GetUcontext() { return &ucontext_; }
+
+private:
+ ThreadEntry(pid_t pid, pid_t tid);
~ThreadEntry();
- bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid && chk_tid == tid); }
+ bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid_ && chk_tid == tid_); }
- static ThreadEntry* AddThreadToUnwind(
- BacktraceThreadInterface* thread_intf, pid_t pid, pid_t tid,
- size_t num_ignored_frames);
+ pid_t pid_;
+ pid_t tid_;
+ int futex_;
+ int ref_count_;
+ pthread_mutex_t mutex_;
+ ThreadEntry* next_;
+ ThreadEntry* prev_;
+ ucontext_t ucontext_;
- BacktraceThreadInterface* thread_intf;
- pid_t pid;
- pid_t tid;
- ThreadEntry* next;
- ThreadEntry* prev;
- int32_t state;
- int num_ignore_frames;
-};
-
-// Interface class that does not contain any local storage, only defines
-// virtual functions to be defined by subclasses.
-class BacktraceThreadInterface {
-public:
- virtual ~BacktraceThreadInterface() { }
-
- virtual void ThreadUnwind(
- siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) = 0;
+ static ThreadEntry* list_;
+ static pthread_mutex_t list_mutex_;
};
class BacktraceThread : public BacktraceCurrent {
public:
- // impl and thread_intf should point to the same object, this allows
- // the compiler to catch if an implementation does not properly
- // subclass both.
- BacktraceThread(
- BacktraceImpl* impl, BacktraceThreadInterface* thread_intf, pid_t tid,
- BacktraceMap* map);
+ BacktraceThread(BacktraceImpl* impl, pid_t tid, BacktraceMap* map);
virtual ~BacktraceThread();
- virtual bool Unwind(size_t num_ignore_frames);
-
- virtual void ThreadUnwind(
- siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
- thread_intf_->ThreadUnwind(siginfo, sigcontext, num_ignore_frames);
- }
-
-private:
- virtual bool TriggerUnwindOnThread(ThreadEntry* entry);
-
- virtual void FinishUnwind();
-
- BacktraceThreadInterface* thread_intf_;
+ virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
};
#endif // _LIBBACKTRACE_BACKTRACE_THREAD_H
diff --git a/libbacktrace/Corkscrew.cpp b/libbacktrace/Corkscrew.cpp
deleted file mode 100644
index 773b0a2..0000000
--- a/libbacktrace/Corkscrew.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <backtrace/Backtrace.h>
-
-#include <string.h>
-
-#include <backtrace-arch.h>
-#include <corkscrew/backtrace.h>
-
-#ifndef __USE_GNU
-#define __USE_GNU
-#endif
-#include <dlfcn.h>
-
-#include "BacktraceLog.h"
-#include "Corkscrew.h"
-
-//-------------------------------------------------------------------------
-// CorkscrewMap functions.
-//-------------------------------------------------------------------------
-CorkscrewMap::CorkscrewMap(pid_t pid) : BacktraceMap(pid), map_info_(NULL) {
-}
-
-CorkscrewMap::~CorkscrewMap() {
- if (map_info_) {
- free_map_info_list(map_info_);
- map_info_ = NULL;
- }
-}
-
-bool CorkscrewMap::Build() {
- map_info_ = load_map_info_list(pid_);
-
- // Use the information in map_info_ to construct the BacktraceMap data
- // rather than reparsing /proc/self/maps.
- map_info_t* cur_map = map_info_;
- while (cur_map) {
- backtrace_map_t map;
- map.start = cur_map->start;
- map.end = cur_map->end;
- map.flags = 0;
- if (cur_map->is_readable) {
- map.flags |= PROT_READ;
- }
- if (cur_map->is_writable) {
- map.flags |= PROT_WRITE;
- }
- if (cur_map->is_executable) {
- map.flags |= PROT_EXEC;
- }
- map.name = cur_map->name;
-
- // The maps are in descending order, but we want them in ascending order.
- maps_.push_front(map);
-
- cur_map = cur_map->next;
- }
- return map_info_ != NULL;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCommon functions.
-//-------------------------------------------------------------------------
-bool CorkscrewCommon::GenerateFrameData(
- backtrace_frame_t* cork_frames, ssize_t num_frames) {
- if (num_frames < 0) {
- BACK_LOGW("libcorkscrew unwind failed.");
- return false;
- }
-
- std::vector<backtrace_frame_data_t>* frames = GetFrames();
- frames->resize(num_frames);
- size_t i = 0;
- for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
- it != frames->end(); ++it, ++i) {
- it->num = i;
- it->pc = cork_frames[i].absolute_pc;
- it->sp = cork_frames[i].stack_top;
- it->stack_size = cork_frames[i].stack_size;
- it->func_offset = 0;
-
- it->map = FindMap(it->pc);
- it->func_name = GetFunctionName(it->pc, &it->func_offset);
- }
- return true;
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewCurrent functions.
-//-------------------------------------------------------------------------
-CorkscrewCurrent::CorkscrewCurrent() {
-}
-
-CorkscrewCurrent::~CorkscrewCurrent() {
-}
-
-bool CorkscrewCurrent::Unwind(size_t num_ignore_frames) {
- backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
- ssize_t num_frames = unwind_backtrace(frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
- return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- *offset = 0;
-
- Dl_info info;
- const backtrace_map_t* map = FindMap(pc);
- if (map) {
- if (dladdr((const void*)pc, &info)) {
- if (info.dli_sname) {
- *offset = pc - map->start - (uintptr_t)info.dli_saddr + (uintptr_t)info.dli_fbase;
- return info.dli_sname;
- }
- } else {
- // dladdr(3) didn't find a symbol; maybe it's static? Look in the ELF file...
- symbol_table_t* symbol_table = load_symbol_table(map->name.c_str());
- if (symbol_table) {
- // First check if we can find the symbol using a relative pc.
- std::string name;
- const symbol_t* elf_symbol = find_symbol(symbol_table, pc - map->start);
- if (elf_symbol) {
- name = elf_symbol->name;
- *offset = pc - map->start - elf_symbol->start;
- } else if ((elf_symbol = find_symbol(symbol_table, pc)) != NULL) {
- // Found the symbol using the absolute pc.
- name = elf_symbol->name;
- *offset = pc - elf_symbol->start;
- }
- free_symbol_table(symbol_table);
- return name;
- }
- }
- }
- return "";
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewThread functions.
-//-------------------------------------------------------------------------
-CorkscrewThread::CorkscrewThread() {
-}
-
-CorkscrewThread::~CorkscrewThread() {
-}
-
-void CorkscrewThread::ThreadUnwind(
- siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames) {
- backtrace_frame_t cork_frames[MAX_BACKTRACE_FRAMES];
- CorkscrewMap* map = static_cast<CorkscrewMap*>(GetMap());
- ssize_t num_frames = unwind_backtrace_signal_arch(
- siginfo, sigcontext, map->GetMapInfo(), cork_frames,
- num_ignore_frames, MAX_BACKTRACE_FRAMES);
- if (num_frames > 0) {
- std::vector<backtrace_frame_data_t>* frames = GetFrames();
- frames->resize(num_frames);
- size_t i = 0;
- for (std::vector<backtrace_frame_data_t>::iterator it = frames->begin();
- it != frames->end(); ++it, ++i) {
- it->num = i;
- it->pc = cork_frames[i].absolute_pc;
- it->sp = cork_frames[i].stack_top;
- it->stack_size = cork_frames[i].stack_size;
- it->map = NULL;
- it->func_offset = 0;
- }
- }
-}
-
-//-------------------------------------------------------------------------
-// CorkscrewPtrace functions.
-//-------------------------------------------------------------------------
-CorkscrewPtrace::CorkscrewPtrace() : ptrace_context_(NULL) {
-}
-
-CorkscrewPtrace::~CorkscrewPtrace() {
- if (ptrace_context_) {
- free_ptrace_context(ptrace_context_);
- ptrace_context_ = NULL;
- }
-}
-
-bool CorkscrewPtrace::Unwind(size_t num_ignore_frames) {
- ptrace_context_ = load_ptrace_context(Tid());
-
- backtrace_frame_t frames[MAX_BACKTRACE_FRAMES];
- ssize_t num_frames = unwind_backtrace_ptrace(
- Tid(), ptrace_context_, frames, num_ignore_frames, MAX_BACKTRACE_FRAMES);
-
- return GenerateFrameData(frames, num_frames);
-}
-
-std::string CorkscrewPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- // Get information about a different process.
- const map_info_t* map_info;
- const symbol_t* symbol;
- find_symbol_ptrace(ptrace_context_, pc, &map_info, &symbol);
- char* symbol_name = NULL;
- if (symbol) {
- if (map_info) {
- *offset = pc - map_info->start - symbol->start;
- }
- symbol_name = symbol->name;
- return symbol_name;
- }
-
- return "";
-}
-
-//-------------------------------------------------------------------------
-// C++ object creation functions.
-//-------------------------------------------------------------------------
-Backtrace* CreateCurrentObj(BacktraceMap* map) {
- return new BacktraceCurrent(new CorkscrewCurrent(), map);
-}
-
-Backtrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) {
- return new BacktracePtrace(new CorkscrewPtrace(), pid, tid, map);
-}
-
-Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
- CorkscrewThread* thread_obj = new CorkscrewThread();
- return new BacktraceThread(thread_obj, thread_obj, tid, map);
-}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
- BacktraceMap* map = new CorkscrewMap(pid);
- if (!map->Build()) {
- delete map;
- return NULL;
- }
- return map;
-}
diff --git a/libbacktrace/Corkscrew.h b/libbacktrace/Corkscrew.h
deleted file mode 100644
index 1633398..0000000
--- a/libbacktrace/Corkscrew.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBBACKTRACE_CORKSCREW_H
-#define _LIBBACKTRACE_CORKSCREW_H
-
-#include <inttypes.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <corkscrew/backtrace.h>
-
-#include "BacktraceImpl.h"
-#include "BacktraceThread.h"
-
-class CorkscrewMap : public BacktraceMap {
-public:
- CorkscrewMap(pid_t pid);
- virtual ~CorkscrewMap();
-
- virtual bool Build();
-
- map_info_t* GetMapInfo() { return map_info_; }
-
-private:
- map_info_t* map_info_;
-};
-
-class CorkscrewCommon : public BacktraceImpl {
-public:
- bool GenerateFrameData(backtrace_frame_t* cork_frames, ssize_t num_frames);
-};
-
-class CorkscrewCurrent : public CorkscrewCommon {
-public:
- CorkscrewCurrent();
- virtual ~CorkscrewCurrent();
-
- virtual bool Unwind(size_t num_ignore_threads);
-
- virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-};
-
-class CorkscrewThread : public CorkscrewCurrent, public BacktraceThreadInterface {
-public:
- CorkscrewThread();
- virtual ~CorkscrewThread();
-
- virtual void ThreadUnwind(
- siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
-class CorkscrewPtrace : public CorkscrewCommon {
-public:
- CorkscrewPtrace();
- virtual ~CorkscrewPtrace();
-
- virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
-
- virtual bool Unwind(size_t num_ignore_threads);
-
-private:
- ptrace_context_t* ptrace_context_;
-};
-
-#endif // _LIBBACKTRACE_CORKSCREW_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 67d372a..b176aaf 100755
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <sys/ucontext.h>
#include <sys/types.h>
+#include <ucontext.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
@@ -24,6 +24,7 @@
#include <libunwind.h>
#include "BacktraceLog.h"
+#include "BacktraceThread.h"
#include "UnwindCurrent.h"
#include "UnwindMap.h"
@@ -36,15 +37,45 @@
UnwindCurrent::~UnwindCurrent() {
}
-bool UnwindCurrent::Unwind(size_t num_ignore_frames) {
- int ret = unw_getcontext(&context_);
- if (ret < 0) {
- BACK_LOGW("unw_getcontext failed %d", ret);
- return false;
+bool UnwindCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ if (!ucontext) {
+ int ret = unw_getcontext(&context_);
+ if (ret < 0) {
+ BACK_LOGW("unw_getcontext failed %d", ret);
+ return false;
+ }
+ }
+ else {
+ GetUnwContextFromUcontext(ucontext);
}
return UnwindFromContext(num_ignore_frames, false);
}
+void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
+ unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
+
+#if defined(__arm__)
+ unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
+ unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
+ unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
+ unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
+ unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
+ unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
+ unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
+ unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
+ unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
+ unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
+ unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
+ unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
+ unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
+ unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
+ unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
+ unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
+#else
+ unw_context->uc_mcontext = ucontext->uc_mcontext;
+#endif
+}
+
std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
*offset = 0;
char buf[512];
@@ -122,47 +153,6 @@
return true;
}
-void UnwindCurrent::ExtractContext(void* sigcontext) {
- unw_tdep_context_t* context = reinterpret_cast<unw_tdep_context_t*>(&context_);
- const ucontext_t* uc = reinterpret_cast<const ucontext_t*>(sigcontext);
-
-#if defined(__arm__)
- context->regs[0] = uc->uc_mcontext.arm_r0;
- context->regs[1] = uc->uc_mcontext.arm_r1;
- context->regs[2] = uc->uc_mcontext.arm_r2;
- context->regs[3] = uc->uc_mcontext.arm_r3;
- context->regs[4] = uc->uc_mcontext.arm_r4;
- context->regs[5] = uc->uc_mcontext.arm_r5;
- context->regs[6] = uc->uc_mcontext.arm_r6;
- context->regs[7] = uc->uc_mcontext.arm_r7;
- context->regs[8] = uc->uc_mcontext.arm_r8;
- context->regs[9] = uc->uc_mcontext.arm_r9;
- context->regs[10] = uc->uc_mcontext.arm_r10;
- context->regs[11] = uc->uc_mcontext.arm_fp;
- context->regs[12] = uc->uc_mcontext.arm_ip;
- context->regs[13] = uc->uc_mcontext.arm_sp;
- context->regs[14] = uc->uc_mcontext.arm_lr;
- context->regs[15] = uc->uc_mcontext.arm_pc;
-#else
- context->uc_mcontext = uc->uc_mcontext;
-#endif
-}
-
-//-------------------------------------------------------------------------
-// UnwindThread functions.
-//-------------------------------------------------------------------------
-UnwindThread::UnwindThread() {
-}
-
-UnwindThread::~UnwindThread() {
-}
-
-void UnwindThread::ThreadUnwind(
- siginfo_t* /*siginfo*/, void* sigcontext, size_t num_ignore_frames) {
- ExtractContext(sigcontext);
- UnwindFromContext(num_ignore_frames, true);
-}
-
//-------------------------------------------------------------------------
// C++ object creation function.
//-------------------------------------------------------------------------
@@ -171,6 +161,5 @@
}
Backtrace* CreateThreadObj(pid_t tid, BacktraceMap* map) {
- UnwindThread* thread_obj = new UnwindThread();
- return new BacktraceThread(thread_obj, thread_obj, tid, map);
+ return new BacktraceThread(new UnwindCurrent(), tid, map);
}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
index 41080c7..2375e6e 100644
--- a/libbacktrace/UnwindCurrent.h
+++ b/libbacktrace/UnwindCurrent.h
@@ -20,7 +20,6 @@
#include <string>
#include "BacktraceImpl.h"
-#include "BacktraceThread.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
@@ -30,25 +29,16 @@
UnwindCurrent();
virtual ~UnwindCurrent();
- virtual bool Unwind(size_t num_ignore_frames);
+ virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
bool UnwindFromContext(size_t num_ignore_frames, bool within_handler);
- void ExtractContext(void* sigcontext);
+ void GetUnwContextFromUcontext(const ucontext_t* context);
protected:
unw_context_t context_;
};
-class UnwindThread : public UnwindCurrent, public BacktraceThreadInterface {
-public:
- UnwindThread();
- virtual ~UnwindThread();
-
- virtual void ThreadUnwind(
- siginfo_t* siginfo, void* sigcontext, size_t num_ignore_frames);
-};
-
#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 1615518..4f9831b 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -15,6 +15,7 @@
*/
#include <pthread.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 5ca7e60..7ba8775 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -19,6 +19,7 @@
#include <sys/types.h>
#include <string.h>
+#include <ucontext.h>
#include <libunwind.h>
#include <libunwind-ptrace.h>
@@ -45,7 +46,12 @@
}
}
-bool UnwindPtrace::Unwind(size_t num_ignore_frames) {
+bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ if (ucontext) {
+ BACK_LOGW("Unwinding from a specified context not supported yet.");
+ return false;
+ }
+
addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
if (!addr_space_) {
BACK_LOGW("unw_create_addr_space failed.");
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
index 1e82117..2fb7967 100644
--- a/libbacktrace/UnwindPtrace.h
+++ b/libbacktrace/UnwindPtrace.h
@@ -28,7 +28,7 @@
UnwindPtrace();
virtual ~UnwindPtrace();
- virtual bool Unwind(size_t num_ignore_frames);
+ virtual bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext);
virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index a5e141b..ed6b211 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -33,6 +33,9 @@
#include <backtrace/BacktraceMap.h>
#include <UniquePtr.h>
+// For the THREAD_SIGNAL definition.
+#include "BacktraceThread.h"
+
#include <cutils/atomic.h>
#include <gtest/gtest.h>
@@ -460,9 +463,15 @@
// Wait up to 2 seconds for the tid to be set.
ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
+ // Make sure that the thread signal used is not visible when compiled for
+ // the target.
+#if !defined(__GLIBC__)
+ ASSERT_LT(THREAD_SIGNAL, SIGRTMIN);
+#endif
+
// Save the current signal action and make sure it is restored afterwards.
struct sigaction cur_action;
- ASSERT_TRUE(sigaction(SIGURG, NULL, &cur_action) == 0);
+ ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &cur_action) == 0);
UniquePtr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(backtrace.get() != NULL);
@@ -475,7 +484,7 @@
// Verify that the old action was restored.
struct sigaction new_action;
- ASSERT_TRUE(sigaction(SIGURG, NULL, &new_action) == 0);
+ ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
@@ -606,6 +615,49 @@
}
}
+TEST(libbacktrace, thread_multiple_dump_same_thread) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ thread_t runner;
+ runner.tid = 0;
+ runner.state = 0;
+ ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
+
+ // Wait for tids to be set.
+ ASSERT_TRUE(WaitForNonZero(&runner.state, 10));
+
+ // Start all of the dumpers at once, they will spin until they are signalled
+ // to begin their dump run.
+ int32_t dump_now = 0;
+ // Dump the same thread NUM_THREADS simultaneously.
+ std::vector<dump_thread_t> dumpers(NUM_THREADS);
+ for (size_t i = 0; i < NUM_THREADS; i++) {
+ dumpers[i].thread.tid = runner.tid;
+ dumpers[i].thread.state = 0;
+ dumpers[i].done = 0;
+ dumpers[i].now = &dump_now;
+
+ ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
+ }
+
+ // Start all of the dumpers going at once.
+ android_atomic_acquire_store(1, &dump_now);
+
+ for (size_t i = 0; i < NUM_THREADS; i++) {
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 100));
+
+ ASSERT_TRUE(dumpers[i].backtrace != NULL);
+ VerifyMaxDump(dumpers[i].backtrace);
+
+ delete dumpers[i].backtrace;
+ dumpers[i].backtrace = NULL;
+ }
+
+ // Tell the runner thread to exit its infinite loop.
+ android_atomic_acquire_store(0, &runner.state);
+}
+
// This test is for UnwindMaps that should share the same map cursor when
// multiple maps are created for the current process at the same time.
TEST(libbacktrace, simultaneous_maps) {
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
deleted file mode 100644
index 8f3b68c..0000000
--- a/libcorkscrew/Android.mk
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) 2011 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-generic_src_files := \
- backtrace.c \
- backtrace-helper.c \
- demangle.c \
- map_info.c \
- ptrace.c \
- symbol_table.c
-
-arm_src_files := \
- arch-arm/backtrace-arm.c \
- arch-arm/ptrace-arm.c
-
-x86_src_files := \
- arch-x86/backtrace-x86.c \
- arch-x86/ptrace-x86.c
-
-ifneq ($(TARGET_IS_64_BIT),true)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(generic_src_files)
-
-ifeq ($(TARGET_ARCH),arm)
-LOCAL_SRC_FILES += $(arm_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),x86)
-LOCAL_SRC_FILES += $(x86_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_SRC_FILES += \
- arch-mips/backtrace-mips.c \
- arch-mips/ptrace-mips.c
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-endif
-
-LOCAL_SHARED_LIBRARIES += libdl libcutils liblog libgccdemangle
-
-LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
-LOCAL_MODULE := libcorkscrew
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Build test.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.cpp
-LOCAL_CFLAGS += -Werror -fno-inline-small-functions
-LOCAL_SHARED_LIBRARIES := libcorkscrew
-LOCAL_MODULE := libcorkscrew_test
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-endif # TARGET_IS_64_BIT == false
-
-
-ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
-
-# Build libcorkscrew.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
-LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-LOCAL_STATIC_LIBRARIES += libcutils liblog
-LOCAL_LDLIBS += -ldl
-ifeq ($(HOST_OS),linux)
- LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
- LOCAL_LDLIBS += -lrt
-endif
-LOCAL_CFLAGS += -std=gnu99 -Werror -Wno-unused-parameter
-LOCAL_MODULE := libcorkscrew
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Build test.
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.cpp
-LOCAL_CFLAGS += -Werror
-LOCAL_SHARED_LIBRARIES := libcorkscrew
-LOCAL_MODULE := libcorkscrew_test
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_EXECUTABLE)
-
-endif # $(HOST_OS)-$(HOST_ARCH) == linux-x86
diff --git a/libcorkscrew/MODULE_LICENSE_APACHE2 b/libcorkscrew/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcorkscrew/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcorkscrew/NOTICE b/libcorkscrew/NOTICE
deleted file mode 100644
index becc120..0000000
--- a/libcorkscrew/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2011, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/libcorkscrew/arch-arm/backtrace-arm.c b/libcorkscrew/arch-arm/backtrace-arm.c
deleted file mode 100644
index 751efbf..0000000
--- a/libcorkscrew/arch-arm/backtrace-arm.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Backtracing functions for ARM.
- *
- * This implementation uses the exception unwinding tables provided by
- * the compiler to unwind call frames. Refer to the ARM Exception Handling ABI
- * documentation (EHABI) for more details about what's going on here.
- *
- * An ELF binary may contain an EXIDX section that provides an index to
- * the exception handling table of each function, sorted by program
- * counter address.
- *
- * This implementation also supports unwinding other processes via ptrace().
- * In that case, the EXIDX section is found by reading the ELF section table
- * structures using ptrace().
- *
- * Because the tables are used for exception handling, it can happen that
- * a given function will not have an exception handling table. In particular,
- * exceptions are assumed to only ever be thrown at call sites. Therefore,
- * by definition leaf functions will not have exception handling tables.
- * This may make unwinding impossible in some cases although we can still get
- * some idea of the call stack by examining the PC and LR registers.
- *
- * As we are only interested in backtrace information, we do not need
- * to perform all of the work of unwinding such as restoring register
- * state and running cleanup functions. Unwinding is performed virtually on
- * an abstract machine context consisting of just the ARM core registers.
- * Furthermore, we do not run generic "personality functions" because
- * we may not be in a position to execute arbitrary code, especially if
- * we are running in a signal handler or using ptrace()!
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../backtrace-arch.h"
-#include "../backtrace-helper.h"
-#include "../ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <stdlib.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <limits.h>
-#include <errno.h>
-#include <sys/ptrace.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-#include <ucontext.h>
-
-/* Unwind state. */
-typedef struct {
- uint32_t gregs[16];
-} unwind_state_t;
-
-static const int R_SP = 13;
-static const int R_LR = 14;
-static const int R_PC = 15;
-
-/* Special EXIDX value that indicates that a frame cannot be unwound. */
-static const uint32_t EXIDX_CANTUNWIND = 1;
-
-/* Get the EXIDX section start and size for the module that contains a
- * given program counter address.
- *
- * When the executable is statically linked, the EXIDX section can be
- * accessed by querying the values of the __exidx_start and __exidx_end
- * symbols.
- *
- * When the executable is dynamically linked, the linker exports a function
- * called dl_unwind_find_exidx that obtains the EXIDX section for a given
- * absolute program counter address.
- *
- * Bionic exports a helpful function called __gnu_Unwind_Find_exidx that
- * handles both cases, so we use that here.
- */
-typedef long unsigned int* _Unwind_Ptr;
-extern _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr pc, int *pcount);
-
-static uintptr_t find_exidx(uintptr_t pc, size_t* out_exidx_size) {
- int count;
- uintptr_t start = (uintptr_t)__gnu_Unwind_Find_exidx((_Unwind_Ptr)pc, &count);
- *out_exidx_size = count;
- return start;
-}
-
-/* Transforms a 31-bit place-relative offset to an absolute address.
- * We assume the most significant bit is clear. */
-static uintptr_t prel_to_absolute(uintptr_t place, uint32_t prel_offset) {
- return place + (((int32_t)(prel_offset << 1)) >> 1);
-}
-
-static uintptr_t get_exception_handler(const memory_t* memory,
- const map_info_t* map_info_list, uintptr_t pc) {
- if (!pc) {
- ALOGV("get_exception_handler: pc is zero, no handler");
- return 0;
- }
-
- uintptr_t exidx_start;
- size_t exidx_size;
- const map_info_t* mi;
- if (memory->tid < 0) {
- mi = NULL;
- exidx_start = find_exidx(pc, &exidx_size);
- } else {
- mi = find_map_info(map_info_list, pc);
- if (mi && mi->data) {
- const map_info_data_t* data = (const map_info_data_t*)mi->data;
- exidx_start = data->exidx_start;
- exidx_size = data->exidx_size;
- } else {
- exidx_start = 0;
- exidx_size = 0;
- }
- }
-
- uintptr_t handler = 0;
- int32_t handler_index = -1;
- if (exidx_start) {
- uint32_t low = 0;
- uint32_t high = exidx_size;
- while (low < high) {
- uint32_t index = (low + high) / 2;
- uintptr_t entry = exidx_start + index * 8;
- uint32_t entry_prel_pc;
- ALOGV("XXX low=%u, high=%u, index=%u", low, high, index);
- if (!try_get_word(memory, entry, &entry_prel_pc)) {
- break;
- }
- uintptr_t entry_pc = prel_to_absolute(entry, entry_prel_pc);
- ALOGV("XXX entry_pc=0x%08x", entry_pc);
- if (pc < entry_pc) {
- high = index;
- continue;
- }
- if (index + 1 < exidx_size) {
- uintptr_t next_entry = entry + 8;
- uint32_t next_entry_prel_pc;
- if (!try_get_word(memory, next_entry, &next_entry_prel_pc)) {
- break;
- }
- uintptr_t next_entry_pc = prel_to_absolute(next_entry, next_entry_prel_pc);
- ALOGV("XXX next_entry_pc=0x%08x", next_entry_pc);
- if (pc >= next_entry_pc) {
- low = index + 1;
- continue;
- }
- }
-
- uintptr_t entry_handler_ptr = entry + 4;
- uint32_t entry_handler;
- if (!try_get_word(memory, entry_handler_ptr, &entry_handler)) {
- break;
- }
- if (entry_handler & (1L << 31)) {
- handler = entry_handler_ptr; // in-place handler data
- } else if (entry_handler != EXIDX_CANTUNWIND) {
- handler = prel_to_absolute(entry_handler_ptr, entry_handler);
- }
- handler_index = index;
- break;
- }
- }
- if (mi) {
- ALOGV("get_exception_handler: pc=0x%08x, module='%s', module_start=0x%08x, "
- "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
- pc, mi->name, mi->start, exidx_start, exidx_size, handler, handler_index);
- } else {
- ALOGV("get_exception_handler: pc=0x%08x, "
- "exidx_start=0x%08x, exidx_size=%d, handler=0x%08x, handler_index=%d",
- pc, exidx_start, exidx_size, handler, handler_index);
- }
- return handler;
-}
-
-typedef struct {
- uintptr_t ptr;
- uint32_t word;
-} byte_stream_t;
-
-static bool try_next_byte(const memory_t* memory, byte_stream_t* stream, uint8_t* out_value) {
- uint8_t result;
- switch (stream->ptr & 3) {
- case 0:
- if (!try_get_word(memory, stream->ptr, &stream->word)) {
- *out_value = 0;
- return false;
- }
- *out_value = stream->word >> 24;
- break;
-
- case 1:
- *out_value = stream->word >> 16;
- break;
-
- case 2:
- *out_value = stream->word >> 8;
- break;
-
- default:
- *out_value = stream->word;
- break;
- }
-
- ALOGV("next_byte: ptr=0x%08x, value=0x%02x", stream->ptr, *out_value);
- stream->ptr += 1;
- return true;
-}
-
-static void set_reg(unwind_state_t* state, uint32_t reg, uint32_t value) {
- ALOGV("set_reg: reg=%d, value=0x%08x", reg, value);
- state->gregs[reg] = value;
-}
-
-static bool try_pop_registers(const memory_t* memory, unwind_state_t* state, uint32_t mask) {
- uint32_t sp = state->gregs[R_SP];
- bool sp_updated = false;
- for (int i = 0; i < 16; i++) {
- if (mask & (1 << i)) {
- uint32_t value;
- if (!try_get_word(memory, sp, &value)) {
- return false;
- }
- if (i == R_SP) {
- sp_updated = true;
- }
- set_reg(state, i, value);
- sp += 4;
- }
- }
- if (!sp_updated) {
- set_reg(state, R_SP, sp);
- }
- return true;
-}
-
-/* Executes a built-in personality routine as defined in the EHABI.
- * Returns true if unwinding should continue.
- *
- * The data for the built-in personality routines consists of a sequence
- * of unwinding instructions, followed by a sequence of scope descriptors,
- * each of which has a length and offset encoded using 16-bit or 32-bit
- * values.
- *
- * We only care about the unwinding instructions. They specify the
- * operations of an abstract machine whose purpose is to transform the
- * virtual register state (including the stack pointer) such that
- * the call frame is unwound and the PC register points to the call site.
- */
-static bool execute_personality_routine(const memory_t* memory,
- unwind_state_t* state, byte_stream_t* stream, int pr_index) {
- size_t size;
- switch (pr_index) {
- case 0: // Personality routine #0, short frame, descriptors have 16-bit scope.
- size = 3;
- break;
- case 1: // Personality routine #1, long frame, descriptors have 16-bit scope.
- case 2: { // Personality routine #2, long frame, descriptors have 32-bit scope.
- uint8_t size_byte;
- if (!try_next_byte(memory, stream, &size_byte)) {
- return false;
- }
- size = (uint32_t)size_byte * sizeof(uint32_t) + 2;
- break;
- }
- default: // Unknown personality routine. Stop here.
- return false;
- }
-
- bool pc_was_set = false;
- while (size--) {
- uint8_t op;
- if (!try_next_byte(memory, stream, &op)) {
- return false;
- }
- if ((op & 0xc0) == 0x00) {
- // "vsp = vsp + (xxxxxx << 2) + 4"
- set_reg(state, R_SP, state->gregs[R_SP] + ((op & 0x3f) << 2) + 4);
- } else if ((op & 0xc0) == 0x40) {
- // "vsp = vsp - (xxxxxx << 2) - 4"
- set_reg(state, R_SP, state->gregs[R_SP] - ((op & 0x3f) << 2) - 4);
- } else if ((op & 0xf0) == 0x80) {
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- uint32_t mask = (((uint32_t)op & 0x0f) << 12) | ((uint32_t)op2 << 4);
- if (mask) {
- // "Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}"
- if (!try_pop_registers(memory, state, mask)) {
- return false;
- }
- if (mask & (1 << R_PC)) {
- pc_was_set = true;
- }
- } else {
- // "Refuse to unwind"
- return false;
- }
- } else if ((op & 0xf0) == 0x90) {
- if (op != 0x9d && op != 0x9f) {
- // "Set vsp = r[nnnn]"
- set_reg(state, R_SP, state->gregs[op & 0x0f]);
- } else {
- // "Reserved as prefix for ARM register to register moves"
- // "Reserved as prefix for Intel Wireless MMX register to register moves"
- return false;
- }
- } else if ((op & 0xf8) == 0xa0) {
- // "Pop r4-r[4+nnn]"
- uint32_t mask = (0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0;
- if (!try_pop_registers(memory, state, mask)) {
- return false;
- }
- } else if ((op & 0xf8) == 0xa8) {
- // "Pop r4-r[4+nnn], r14"
- uint32_t mask = ((0x0ff0 >> (7 - (op & 0x07))) & 0x0ff0) | 0x4000;
- if (!try_pop_registers(memory, state, mask)) {
- return false;
- }
- } else if (op == 0xb0) {
- // "Finish"
- break;
- } else if (op == 0xb1) {
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
- // "Pop integer registers under mask {r3, r2, r1, r0}"
- if (!try_pop_registers(memory, state, op2)) {
- return false;
- }
- } else {
- // "Spare"
- return false;
- }
- } else if (op == 0xb2) {
- // "vsp = vsp + 0x204 + (uleb128 << 2)"
- uint32_t value = 0;
- uint32_t shift = 0;
- uint8_t op2;
- do {
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- value |= (op2 & 0x7f) << shift;
- shift += 7;
- } while (op2 & 0x80);
- set_reg(state, R_SP, state->gregs[R_SP] + (value << 2) + 0x204);
- } else if (op == 0xb3) {
- // "Pop VFP double-precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDX"
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 12);
- } else if ((op & 0xf8) == 0xb8) {
- // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDX"
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 12);
- } else if ((op & 0xf8) == 0xc0) {
- // "Intel Wireless MMX pop wR[10]-wR[10+nnn]"
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
- } else if (op == 0xc6) {
- // "Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]"
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
- } else if (op == 0xc7) {
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- if (op2 != 0x00 && (op2 & 0xf0) == 0x00) {
- // "Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0}"
- set_reg(state, R_SP, state->gregs[R_SP] + __builtin_popcount(op2) * 4);
- } else {
- // "Spare"
- return false;
- }
- } else if (op == 0xc8) {
- // "Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc]
- // saved (as if) by FSTMFD"
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
- } else if (op == 0xc9) {
- // "Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDD"
- uint8_t op2;
- if (!(size--) || !try_next_byte(memory, stream, &op2)) {
- return false;
- }
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op2 & 0x0f) * 8 + 8);
- } else if ((op == 0xf8) == 0xd0) {
- // "Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDD"
- set_reg(state, R_SP, state->gregs[R_SP] + (uint32_t)(op & 0x07) * 8 + 8);
- } else {
- // "Spare"
- return false;
- }
- }
- if (!pc_was_set) {
- set_reg(state, R_PC, state->gregs[R_LR]);
- }
- return true;
-}
-
-static bool try_get_half_word(const memory_t* memory, uint32_t pc, uint16_t* out_value) {
- uint32_t word;
- if (try_get_word(memory, pc & ~2, &word)) {
- *out_value = pc & 2 ? word >> 16 : word & 0xffff;
- return true;
- }
- return false;
-}
-
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc) {
- if (pc & 1) {
- /* Thumb mode - need to check whether the bl(x) has long offset or not.
- * Examples:
- *
- * arm blx in the middle of thumb:
- * 187ae: 2300 movs r3, #0
- * 187b0: f7fe ee1c blx 173ec
- * 187b4: 2c00 cmp r4, #0
- *
- * arm bl in the middle of thumb:
- * 187d8: 1c20 adds r0, r4, #0
- * 187da: f136 fd15 bl 14f208
- * 187de: 2800 cmp r0, #0
- *
- * pure thumb:
- * 18894: 189b adds r3, r3, r2
- * 18896: 4798 blx r3
- * 18898: b001 add sp, #4
- */
- uint16_t prev1, prev2;
- if (try_get_half_word(memory, pc - 5, &prev1)
- && ((prev1 & 0xf000) == 0xf000)
- && try_get_half_word(memory, pc - 3, &prev2)
- && ((prev2 & 0xe000) == 0xe000)) {
- pc -= 4; // long offset
- } else {
- pc -= 2;
- }
- } else {
- /* ARM mode, all instructions are 32bit. Yay! */
- pc -= 4;
- }
- return pc;
-}
-
-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;
-
- for (size_t index = 0; returned_frames < max_depth; index++) {
- uintptr_t pc = index ? rewind_pc_arch(memory, state->gregs[R_PC])
- : state->gregs[R_PC];
- backtrace_frame_t* frame = add_backtrace_entry(pc,
- backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
- if (frame) {
- frame->stack_top = state->gregs[R_SP];
- }
-
- uintptr_t handler = get_exception_handler(memory, map_info_list, pc);
- if (!handler) {
- // If there is no handler for the PC and this is the first frame,
- // then the program may have branched to an invalid address.
- // Try starting from the LR instead, otherwise stop unwinding.
- if (index == 0 && state->gregs[R_LR]
- && state->gregs[R_LR] != state->gregs[R_PC]) {
- set_reg(state, R_PC, state->gregs[R_LR]);
- continue;
- } else {
- break;
- }
- }
-
- byte_stream_t stream;
- stream.ptr = handler;
- uint8_t pr;
- if (!try_next_byte(memory, &stream, &pr)) {
- break;
- }
- if ((pr & 0xf0) != 0x80) {
- // The first word is a place-relative pointer to a generic personality
- // routine function. We don't support invoking such functions, so stop here.
- break;
- }
-
- // The first byte indicates the personality routine to execute.
- // Following bytes provide instructions to the personality routine.
- if (!execute_personality_routine(memory, state, &stream, pr & 0x0f)) {
- break;
- }
- if (frame && state->gregs[R_SP] > frame->stack_top) {
- frame->stack_size = state->gregs[R_SP] - frame->stack_top;
- }
- if (!state->gregs[R_PC]) {
- break;
- }
- }
-
- // Ran out of frames that we could unwind using handlers.
- // Add a final entry for the LR if it looks sane and call it good.
- if (returned_frames < max_depth
- && state->gregs[R_LR]
- && state->gregs[R_LR] != state->gregs[R_PC]
- && is_executable_map(map_info_list, state->gregs[R_LR])) {
- // We don't know where the stack for this extra frame starts so we
- // don't return any stack information for it.
- add_backtrace_entry(rewind_pc_arch(memory, state->gregs[R_LR]),
- backtrace, ignore_depth, max_depth, &ignored_frames, &returned_frames);
- }
- return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
- const map_info_t* map_info_list,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
- const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
- unwind_state_t state;
-
- state.gregs[0] = uc->uc_mcontext.arm_r0;
- state.gregs[1] = uc->uc_mcontext.arm_r1;
- state.gregs[2] = uc->uc_mcontext.arm_r2;
- state.gregs[3] = uc->uc_mcontext.arm_r3;
- state.gregs[4] = uc->uc_mcontext.arm_r4;
- state.gregs[5] = uc->uc_mcontext.arm_r5;
- state.gregs[6] = uc->uc_mcontext.arm_r6;
- state.gregs[7] = uc->uc_mcontext.arm_r7;
- state.gregs[8] = uc->uc_mcontext.arm_r8;
- state.gregs[9] = uc->uc_mcontext.arm_r9;
- state.gregs[10] = uc->uc_mcontext.arm_r10;
- state.gregs[11] = uc->uc_mcontext.arm_fp;
- state.gregs[12] = uc->uc_mcontext.arm_ip;
- state.gregs[13] = uc->uc_mcontext.arm_sp;
- state.gregs[14] = uc->uc_mcontext.arm_lr;
- state.gregs[15] = uc->uc_mcontext.arm_pc;
-
- memory_t memory;
- init_memory(&memory, map_info_list);
- return unwind_backtrace_common(&memory, map_info_list, &state,
- backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
- struct pt_regs regs;
- if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
- return -1;
- }
-
- unwind_state_t state;
- for (int i = 0; i < 16; i++) {
- state.gregs[i] = regs.uregs[i];
- }
-
- memory_t memory;
- init_memory_ptrace(&memory, tid);
- return unwind_backtrace_common(&memory, context->map_info_list, &state,
- backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-arm/ptrace-arm.c b/libcorkscrew/arch-arm/ptrace-arm.c
deleted file mode 100644
index a50844e..0000000
--- a/libcorkscrew/arch-arm/ptrace-arm.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <elf.h>
-#include <cutils/log.h>
-
-#ifndef PT_ARM_EXIDX
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-static void load_exidx_header(pid_t pid, map_info_t* mi,
- uintptr_t* out_exidx_start, size_t* out_exidx_size) {
- 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_ARM_EXIDX) {
- uint32_t elf_phdr_offset;
- uint32_t elf_phdr_filesz;
- if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
- &elf_phdr_offset)
- || !try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_filesz),
- &elf_phdr_filesz)) {
- break;
- }
- *out_exidx_start = mi->start + elf_phdr_offset;
- *out_exidx_size = elf_phdr_filesz / 8;
- ALOGV("Parsed EXIDX header info for %s: start=0x%08x, size=%d", mi->name,
- *out_exidx_start, *out_exidx_size);
- return;
- }
- }
- }
- *out_exidx_start = 0;
- *out_exidx_size = 0;
-}
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
- load_exidx_header(pid, mi, &data->exidx_start, &data->exidx_size);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data) {
-}
diff --git a/libcorkscrew/arch-mips/backtrace-mips.c b/libcorkscrew/arch-mips/backtrace-mips.c
deleted file mode 100644
index 832fb86..0000000
--- a/libcorkscrew/arch-mips/backtrace-mips.c
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Backtracing functions for mips
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#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>
-
-#include <sys/ucontext.h>
-
-/* For PTRACE_GETREGS */
-typedef struct {
- uint64_t regs[32];
- uint64_t lo;
- uint64_t hi;
- uint64_t epc;
- uint64_t badvaddr;
- uint64_t status;
- uint64_t cause;
-} user_regs_struct;
-
-enum {
- REG_ZERO = 0, REG_AT, REG_V0, REG_V1,
- REG_A0, REG_A1, REG_A2, REG_A3,
- REG_T0, REG_T1, REG_T2, REG_T3,
- REG_T4, REG_T5, REG_T6, REG_T7,
- REG_S0, REG_S1, REG_S2, REG_S3,
- REG_S4, REG_S5, REG_S6, REG_S7,
- REG_T8, REG_T9, REG_K0, REG_K1,
- REG_GP, REG_SP, REG_S8, REG_RA,
-};
-
-
-/* Unwind state. */
-typedef struct {
- uint32_t reg[DWARF_REGISTERS];
-} unwind_state_t;
-
-uintptr_t rewind_pc_arch(const memory_t* memory __attribute__((unused)), uintptr_t pc) {
- if (pc == 0)
- return pc;
- if ((pc & 1) == 0)
- return pc-8; /* jal/bal/jalr + branch delay slot */
- return pc;
-}
-
-/* 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;
-
- ptr += *cursor;
-
- if (ptr < lastptr || lastptr + 3 < ptr) {
- lastptr = (ptr >> 2) << 2;
- if (!try_get_word(memory, lastptr, &buf)) {
- return false;
- }
- }
- *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 mips.
- 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 mips.
- if (!try_get_uleb128(memory, ptr, ®, 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 mips.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = stack->regs[reg].rule;
- dstate->regs[reg].value = stack->regs[reg].value;
- ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value);
- break;
- case DW_CFA_undefined: // probably we don't have it on mips.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = 'u';
- dstate->regs[reg].value = 0;
- ALOGV("DW_CFA_undefined: r%d", reg);
- break;
- case DW_CFA_same_value: // probably we don't have it on mips.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = 's';
- dstate->regs[reg].value = 0;
- ALOGV("DW_CFA_same_value: r%d", reg);
- break;
- case DW_CFA_register: // probably we don't have it on mips.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- /* that's new register actually, not offset */
- if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
- if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) {
- 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, ®, 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, ®, 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 SP if it's not updated by dwarf rule we assume it's equal to CFA
- // for PC if it's not updated by dwarf rule we assume it's equal to RA
- if (reg == DWARF_SP) {
- ALOGV("get_old_register_value: adjusting sp to CFA: 0x%x", cfa);
- newstate->reg[reg] = cfa;
- } else if (reg == DWARF_PC) {
- ALOGV("get_old_register_value: adjusting PC to RA: 0x%x", newstate->reg[DWARF_RA]);
- newstate->reg[reg] = newstate->reg[DWARF_RA];
- } 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) {
- 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_SP) {
- cfa = state->reg[DWARF_SP] + dstate->cfa_off;
- } else if (dstate->cfa_reg == DWARF_FP) {
- cfa = state->reg[DWARF_FP] + dstate->cfa_off;
- } else {
- ALOGE("update_state: unexpected CFA register: %d", dstate->cfa_reg);
- return false;
- }
- ALOGV("update_state: new CFA: 0x%x", cfa);
-
- /* Update registers. Order is important to allow RA to propagate to PC */
- /* Getting FP. */
- if (!get_old_register_value(memory, cfa, dstate, DWARF_FP, state, &newstate)) return false;
- /* Getting SP. */
- if (!get_old_register_value(memory, cfa, dstate, DWARF_SP, state, &newstate)) return false;
- /* Getting RA. */
- if (!get_old_register_value(memory, cfa, dstate, DWARF_RA, state, &newstate)) return false;
- /* Getting PC. */
- if (!get_old_register_value(memory, cfa, dstate, DWARF_PC, state, &newstate)) return false;
-
- ALOGV("update_state: PC: 0x%x; restore PC: 0x%x", state->reg[DWARF_PC], newstate.reg[DWARF_PC]);
- ALOGV("update_state: RA: 0x%x; restore RA: 0x%x", state->reg[DWARF_RA], newstate.reg[DWARF_RA]);
- ALOGV("update_state: FP: 0x%x; restore FP: 0x%x", state->reg[DWARF_FP], newstate.reg[DWARF_FP]);
- ALOGV("update_state: SP: 0x%x; restore SP: 0x%x", state->reg[DWARF_SP], newstate.reg[DWARF_SP]);
-
- if (newstate.reg[DWARF_PC] == 0)
- return false;
-
- /* End backtrace if registers do not change */
- if ((state->reg[DWARF_PC] == newstate.reg[DWARF_PC]) &&
- (state->reg[DWARF_RA] == newstate.reg[DWARF_RA]) &&
- (state->reg[DWARF_FP] == newstate.reg[DWARF_FP]) &&
- (state->reg[DWARF_SP] == newstate.reg[DWARF_SP]))
- return false;
-
- *state = newstate;
- return true;
-}
-
-/* Execute CIE and FDE instructions for FDE found with find_fde. */
-static bool execute_fde(const memory_t* memory,
- 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_PC] >= dstate->loc) {
- if (!execute_dwarf(memory, fde, cie_info, dstate, &c, stack, &stack_ptr)) {
- return false;
- }
- ALOGV("PC: %x, LOC: %x", state->reg[DWARF_PC], dstate->loc);
- }
-
- return update_state(memory, state, dstate);
-}
-
-static bool heuristic_state_update(const memory_t* memory, unwind_state_t* state)
-{
- bool found_start = false;
- int maxcheck = 1024;
- int32_t stack_size = 0;
- int32_t ra_offset = 0;
- dwarf_state_t dwarf_state;
- dwarf_state_t* dstate = &dwarf_state;
-
- static struct {
- uint32_t insn;
- uint32_t mask;
- } frame0sig[] = {
- {0x3c1c0000, 0xffff0000}, /* lui gp,xxxx */
- {0x279c0000, 0xffff0000}, /* addiu gp,gp,xxxx */
- {0x039fe021, 0xffffffff}, /* addu gp,gp,ra */
- };
- const int nframe0sig = sizeof(frame0sig)/sizeof(frame0sig[0]);
- int f0 = nframe0sig;
- memset(dstate, 0, sizeof(dwarf_state_t));
-
- /* Search code backwards looking for function prologue */
- for (uint32_t pc = state->reg[DWARF_PC]-4; maxcheck-- > 0 && !found_start; pc -= 4) {
- uint32_t op;
- int32_t immediate;
-
- if (!try_get_word(memory, pc, &op))
- return false;
-
- // ALOGV("@0x%08x: 0x%08x\n", pc, op);
-
- // Check for frame 0 signature
- if ((op & frame0sig[f0].mask) == frame0sig[f0].insn) {
- if (f0 == 0)
- return false;
- f0--;
- }
- else {
- f0 = nframe0sig;
- }
-
- switch (op & 0xffff0000) {
- case 0x27bd0000: // addiu sp, imm
- // looking for stack being decremented
- immediate = (((int32_t)op) << 16) >> 16;
- if (immediate < 0) {
- stack_size = -immediate;
- ALOGV("@0x%08x: found stack adjustment=%d\n", pc, stack_size);
- }
- break;
- case 0x039f0000: // e021
-
- case 0xafbf0000: // sw ra, imm(sp)
- ra_offset = (((int32_t)op) << 16) >> 16;
- ALOGV("@0x%08x: found ra offset=%d\n", pc, ra_offset);
- break;
- case 0x3c1c0000: // lui gp
- ALOGV("@0x%08x: found function boundary", pc);
- found_start = true;
- break;
- default:
- break;
- }
- }
-
- dstate->cfa_reg = DWARF_SP;
- dstate->cfa_off = stack_size;
-
- if (ra_offset) {
- dstate->regs[DWARF_RA].rule = 'o';
- dstate->regs[DWARF_RA].value = -stack_size + ra_offset;
- }
-
- return update_state(memory, state, dstate);
-}
-
-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("PC: %x", state->reg[DWARF_PC]);
- ALOGV("RA: %x", state->reg[DWARF_RA]);
- ALOGV("FP: %x", state->reg[DWARF_FP]);
- ALOGV("SP: %x", state->reg[DWARF_SP]);
-
- for (size_t index = 0; returned_frames < max_depth; index++) {
- uintptr_t fde = find_fde(memory, map_info_list, state->reg[DWARF_PC]);
- backtrace_frame_t* frame = add_backtrace_entry(
- index ? rewind_pc_arch(memory, state->reg[DWARF_PC]) : state->reg[DWARF_PC],
- backtrace, ignore_depth, max_depth,
- &ignored_frames, &returned_frames);
- uint32_t stack_top = state->reg[DWARF_SP];
-
- if (fde) {
- /* Use FDE to update state */
- if (!execute_fde(memory, fde, state))
- break;
- }
- else {
- /* FDE is not found, update state heuristically */
- if (!heuristic_state_update(memory, state))
- break;
- }
-
- if (frame) {
- frame->stack_top = stack_top;
- if (stack_top < state->reg[DWARF_SP]) {
- frame->stack_size = state->reg[DWARF_SP] - stack_top;
- }
- }
- ALOGV("Stack: 0x%x ... 0x%x - %d bytes", frame->stack_top, state->reg[DWARF_SP], frame->stack_size);
- }
- return returned_frames;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
- const map_info_t* map_info_list,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
- const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
- unwind_state_t state;
- state.reg[DWARF_PC] = uc->uc_mcontext.pc;
- state.reg[DWARF_RA] = uc->uc_mcontext.gregs[REG_RA];
- state.reg[DWARF_FP] = uc->uc_mcontext.gregs[REG_S8];
- state.reg[DWARF_SP] = uc->uc_mcontext.gregs[REG_SP];
-
- ALOGV("unwind_backtrace_signal_arch: "
- "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
- ignore_depth, max_depth, state.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
- memory_t memory;
- init_memory(&memory, map_info_list);
- return unwind_backtrace_common(&memory, map_info_list,
- &state, backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-
- user_regs_struct regs;
- if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
- return -1;
- }
-
- unwind_state_t state;
- state.reg[DWARF_PC] = regs.epc;
- state.reg[DWARF_RA] = regs.regs[REG_RA];
- state.reg[DWARF_FP] = regs.regs[REG_S8];
- state.reg[DWARF_SP] = regs.regs[REG_SP];
-
- ALOGV("unwind_backtrace_ptrace_arch: "
- "ignore_depth=%d max_depth=%d pc=0x%08x sp=0x%08x ra=0x%08x\n",
- ignore_depth, max_depth, state.reg[DWARF_PC], state.reg[DWARF_SP], state.reg[DWARF_RA]);
-
- memory_t memory;
- init_memory_ptrace(&memory, tid);
- return unwind_backtrace_common(&memory, context->map_info_list,
- &state, backtrace, ignore_depth, max_depth);
-}
diff --git a/libcorkscrew/arch-mips/dwarf.h b/libcorkscrew/arch-mips/dwarf.h
deleted file mode 100644
index 8504ea0..0000000
--- a/libcorkscrew/arch-mips/dwarf.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * 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 mips */
-typedef enum
- {
- UNW_MIPS_R0,
- UNW_MIPS_R1,
- UNW_MIPS_R2,
- UNW_MIPS_R3,
- UNW_MIPS_R4,
- UNW_MIPS_R5,
- UNW_MIPS_R6,
- UNW_MIPS_R7,
- UNW_MIPS_R8,
- UNW_MIPS_R9,
- UNW_MIPS_R10,
- UNW_MIPS_R11,
- UNW_MIPS_R12,
- UNW_MIPS_R13,
- UNW_MIPS_R14,
- UNW_MIPS_R15,
- UNW_MIPS_R16,
- UNW_MIPS_R17,
- UNW_MIPS_R18,
- UNW_MIPS_R19,
- UNW_MIPS_R20,
- UNW_MIPS_R21,
- UNW_MIPS_R22,
- UNW_MIPS_R23,
- UNW_MIPS_R24,
- UNW_MIPS_R25,
- UNW_MIPS_R26,
- UNW_MIPS_R27,
- UNW_MIPS_R28,
- UNW_MIPS_R29,
- UNW_MIPS_R30,
- UNW_MIPS_R31,
-
- UNW_MIPS_PC = 34,
-
- /* FIXME: Other registers! */
-
- /* For MIPS, the CFA is the value of SP (r29) at the call site in the
- previous frame. */
- UNW_MIPS_CFA,
-
- UNW_TDEP_LASTREG,
-
- UNW_TDEP_LAST_REG = UNW_MIPS_R31,
-
- UNW_TDEP_IP = UNW_MIPS_R31,
- UNW_TDEP_SP = UNW_MIPS_R29,
- UNW_TDEP_EH = UNW_MIPS_R0 /* FIXME. */
-
- }
-mips_regnum_t;
-
-#define DWARF_REGISTERS UNW_TDEP_LASTREG
-
-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 mips
-} dwarf_state_t;
-
-/* DWARF registers we are caring about. */
-
-
-#define DWARF_SP UNW_MIPS_R29
-#define DWARF_RA UNW_MIPS_R31
-#define DWARF_PC UNW_MIPS_PC
-#define DWARF_FP UNW_MIPS_CFA /* FIXME is this correct? */
diff --git a/libcorkscrew/arch-mips/ptrace-mips.c b/libcorkscrew/arch-mips/ptrace-mips.c
deleted file mode 100644
index ba3b60a..0000000
--- a/libcorkscrew/arch-mips/ptrace-mips.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-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;
-
-
- try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff);
- ALOGV("reading 0x%08x elf_phoff:%x", mi->start + offsetof(Elf32_Ehdr, e_phoff), elf_phoff);
- try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize), &elf_phentsize_ehsize);
- ALOGV("reading 0x%08x elf_phentsize_ehsize:%x", 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);
- ALOGV("reading 0x%08x elf_shentsize_phnum:%x", mi->start + offsetof(Elf32_Ehdr, e_phnum), 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) {
- ALOGV("load_ptrace_map_info_data_arch");
- load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
-}
-
-void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),
- map_info_data_t* data __attribute__((unused))) {
- ALOGV("free_ptrace_map_info_data_arch");
-}
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
deleted file mode 100755
index df486de..0000000
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/*
- * Backtracing functions for x86.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#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>
-
-#if defined(__APPLE__)
-
-#define _XOPEN_SOURCE
-#include <ucontext.h>
-
-#else
-
-// glibc has its own renaming of the Linux kernel's structures.
-#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
-#include <ucontext.h>
-
-#endif
-
-/* Unwind state. */
-typedef struct {
- 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: 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. */
-}
-
-/* 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;
-
- ptr += *cursor;
-
- if (ptr < lastptr || lastptr + 3 < ptr) {
- lastptr = (ptr >> 2) << 2;
- if (!try_get_word(memory, lastptr, &buf)) {
- return false;
- }
- }
- *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, ®, 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, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_restore_extended: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = stack->regs[reg].rule;
- dstate->regs[reg].value = stack->regs[reg].value;
- ALOGV("DW_CFA_restore: r%d = %c(%d)", reg, dstate->regs[reg].rule, dstate->regs[reg].value);
- break;
- case DW_CFA_undefined: // probably we don't have it on x86.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = 'u';
- dstate->regs[reg].value = 0;
- ALOGV("DW_CFA_undefined: r%d", reg);
- break;
- case DW_CFA_same_value: // probably we don't have it on x86.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- if (reg >= DWARF_REGISTERS) {
- ALOGE("DW_CFA_undefined: r%d exceeds supported number of registers (%d)", reg, DWARF_REGISTERS);
- return false;
- }
- dstate->regs[reg].rule = 's';
- dstate->regs[reg].value = 0;
- ALOGV("DW_CFA_same_value: r%d", reg);
- break;
- case DW_CFA_register: // probably we don't have it on x86.
- if (!try_get_uleb128(memory, ptr, ®, cursor)) return false;
- /* that's new register actually, not offset */
- if (!try_get_uleb128(memory, ptr, &offset, cursor)) return false;
- if (reg >= DWARF_REGISTERS || offset >= DWARF_REGISTERS) {
- 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, ®, 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, ®, 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) {
- 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,
- 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);
-}
-
-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, 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;
-}
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)), void* sigcontext,
- const map_info_t* map_info_list,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
- const ucontext_t* uc = (const ucontext_t*)sigcontext;
-
- unwind_state_t state;
-#if defined(__APPLE__)
- state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
- state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
- state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
-#else
- 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];
-#endif
-
- memory_t memory;
- init_memory(&memory, map_info_list);
- return unwind_backtrace_common(&memory, map_info_list,
- &state, backtrace, ignore_depth, max_depth);
-}
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-#if defined(__APPLE__)
- return -1;
-#else
- pt_regs_x86_t regs;
- if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
- return -1;
- }
-
- unwind_state_t state;
- 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);
- return unwind_backtrace_common(&memory, context->map_info_list,
- &state, backtrace, ignore_depth, max_depth);
-#endif
-}
diff --git a/libcorkscrew/arch-x86/dwarf.h b/libcorkscrew/arch-x86/dwarf.h
deleted file mode 100755
index 962fc55..0000000
--- a/libcorkscrew/arch-x86/dwarf.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * 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
deleted file mode 100755
index 9c49b93..0000000
--- a/libcorkscrew/arch-x86/ptrace-x86.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "../ptrace-arch.h"
-
-#include <stddef.h>
-#include <elf.h>
-#include <cutils/log.h>
-
-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)),
- map_info_data_t* data __attribute__((unused))) {
-}
diff --git a/libcorkscrew/backtrace-arch.h b/libcorkscrew/backtrace-arch.h
deleted file mode 100644
index a46f80b..0000000
--- a/libcorkscrew/backtrace-arch.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_ARCH_H
-#define _CORKSCREW_BACKTRACE_ARCH_H
-
-#include "ptrace-arch.h"
-#include <corkscrew/backtrace.h>
-
-#include <signal.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Rewind the program counter by one instruction. */
-uintptr_t rewind_pc_arch(const memory_t* memory, uintptr_t pc);
-
-ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
- const map_info_t* map_info_list,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_ARCH_H
diff --git a/libcorkscrew/backtrace-helper.c b/libcorkscrew/backtrace-helper.c
deleted file mode 100644
index bf9d3f3..0000000
--- a/libcorkscrew/backtrace-helper.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-helper.h"
-
-#include <cutils/log.h>
-
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc, backtrace_frame_t* backtrace,
- size_t ignore_depth, size_t max_depth,
- size_t* ignored_frames, size_t* returned_frames) {
- if (*ignored_frames < ignore_depth) {
- *ignored_frames += 1;
- return NULL;
- }
- if (*returned_frames >= max_depth) {
- return NULL;
- }
- backtrace_frame_t* frame = &backtrace[*returned_frames];
- frame->absolute_pc = pc;
- frame->stack_top = 0;
- frame->stack_size = 0;
- *returned_frames += 1;
- return frame;
-}
diff --git a/libcorkscrew/backtrace-helper.h b/libcorkscrew/backtrace-helper.h
deleted file mode 100644
index 4d8a874..0000000
--- a/libcorkscrew/backtrace-helper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Backtrace helper functions. */
-
-#ifndef _CORKSCREW_BACKTRACE_HELPER_H
-#define _CORKSCREW_BACKTRACE_HELPER_H
-
-#include <corkscrew/backtrace.h>
-#include <sys/types.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Add a program counter to a backtrace if it will fit.
- * Returns the newly added frame, or NULL if none.
- */
-backtrace_frame_t* add_backtrace_entry(uintptr_t pc,
- backtrace_frame_t* backtrace,
- size_t ignore_depth, size_t max_depth,
- size_t* ignored_frames, size_t* returned_frames);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_BACKTRACE_HELPER_H
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
deleted file mode 100644
index f1dd61d..0000000
--- a/libcorkscrew/backtrace.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "backtrace-arch.h"
-#include "backtrace-helper.h"
-#include "ptrace-arch.h"
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-#include <corkscrew/ptrace.h>
-#include <corkscrew/demangle.h>
-
-#include <unistd.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <unwind.h>
-#include <cutils/log.h>
-#include <cutils/atomic.h>
-
-#define __USE_GNU // For dladdr(3) in glibc.
-#include <dlfcn.h>
-
-#if defined(__BIONIC__)
-
-// Bionic implements and exports gettid but only implements tgkill.
-extern int tgkill(int tgid, int tid, int sig);
-
-#elif defined(__APPLE__)
-
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-static pid_t gettid() {
- return syscall(SYS_thread_selfid);
-}
-
-#else
-
-// glibc doesn't implement or export either gettid or tgkill.
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-static pid_t gettid() {
- return syscall(__NR_gettid);
-}
-
-static int tgkill(int tgid, int tid, int sig) {
- return syscall(__NR_tgkill, tgid, tid, sig);
-}
-
-#endif
-
-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;
-
-static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) {
- backtrace_state_t* state = (backtrace_state_t*)arg;
- uintptr_t pc = _Unwind_GetIP(context);
- if (pc) {
- // TODO: Get information about the stack layout from the _Unwind_Context.
- // This will require a new architecture-specific function to query
- // the appropriate registers. Current callers of unwind_backtrace
- // don't need this information, so we won't bother collecting it just yet.
- add_backtrace_entry(rewind_pc_arch(&state->memory, pc), state->backtrace,
- state->ignore_depth, state->max_depth,
- &state->ignored_frames, &state->returned_frames);
- }
- return state->returned_frames < state->max_depth ? _URC_NO_REASON : _URC_END_OF_STACK;
-}
-
-ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
- ALOGV("Unwinding current thread %d.", gettid());
-
- map_info_t* milist = acquire_my_map_info_list();
-
- backtrace_state_t state;
- state.backtrace = backtrace;
- state.ignore_depth = ignore_depth;
- state.max_depth = max_depth;
- state.ignored_frames = 0;
- state.returned_frames = 0;
- init_memory(&state.memory, milist);
-
- _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
-
- release_my_map_info_list(milist);
-
- if (state.returned_frames) {
- return state.returned_frames;
- }
- return rc == _URC_END_OF_STACK ? 0 : -1;
-}
-
-#ifdef CORKSCREW_HAVE_ARCH
-static const int32_t STATE_DUMPING = -1;
-static const int32_t STATE_DONE = -2;
-static const int32_t STATE_CANCEL = -3;
-
-static pthread_mutex_t g_unwind_signal_mutex = PTHREAD_MUTEX_INITIALIZER;
-static volatile struct {
- int32_t tid_state;
- const map_info_t* map_info_list;
- backtrace_frame_t* backtrace;
- size_t ignore_depth;
- size_t max_depth;
- size_t returned_frames;
-} g_unwind_signal_state;
-
-static void unwind_backtrace_thread_signal_handler(int n __attribute__((unused)), siginfo_t* siginfo, void* sigcontext) {
- if (!android_atomic_acquire_cas(gettid(), STATE_DUMPING, &g_unwind_signal_state.tid_state)) {
- g_unwind_signal_state.returned_frames = unwind_backtrace_signal_arch(
- siginfo, sigcontext,
- g_unwind_signal_state.map_info_list,
- g_unwind_signal_state.backtrace,
- g_unwind_signal_state.ignore_depth,
- g_unwind_signal_state.max_depth);
- android_atomic_release_store(STATE_DONE, &g_unwind_signal_state.tid_state);
- } else {
- ALOGV("Received spurious SIGURG on thread %d that was intended for thread %d.",
- gettid(), android_atomic_acquire_load(&g_unwind_signal_state.tid_state));
- }
-}
-#endif
-
-ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
- size_t ignore_depth, size_t max_depth) {
- if (tid == gettid()) {
- return unwind_backtrace(backtrace, ignore_depth + 1, max_depth);
- }
-
- ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
-
- // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
- // mach_port_t or the pthread_t rather than the tid.
-#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
- struct sigaction act;
- struct sigaction oact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = unwind_backtrace_thread_signal_handler;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- sigemptyset(&act.sa_mask);
-
- pthread_mutex_lock(&g_unwind_signal_mutex);
- map_info_t* milist = acquire_my_map_info_list();
-
- ssize_t frames = -1;
- if (!sigaction(SIGURG, &act, &oact)) {
- g_unwind_signal_state.map_info_list = milist;
- g_unwind_signal_state.backtrace = backtrace;
- g_unwind_signal_state.ignore_depth = ignore_depth;
- g_unwind_signal_state.max_depth = max_depth;
- g_unwind_signal_state.returned_frames = 0;
- android_atomic_release_store(tid, &g_unwind_signal_state.tid_state);
-
- // Signal the specific thread that we want to dump.
- int32_t tid_state = tid;
- if (tgkill(getpid(), tid, SIGURG)) {
- ALOGV("Failed to send SIGURG to thread %d.", tid);
- } else {
- // Wait for the other thread to start dumping the stack, or time out.
- int wait_millis = 250;
- for (;;) {
- tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
- if (tid_state != tid) {
- break;
- }
- if (wait_millis--) {
- ALOGV("Waiting for thread %d to start dumping the stack...", tid);
- usleep(1000);
- } else {
- ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid);
- break;
- }
- }
- }
-
- // Try to cancel the dump if it has not started yet.
- if (tid_state == tid) {
- if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) {
- ALOGV("Canceled thread %d stack dump.", tid);
- tid_state = STATE_CANCEL;
- } else {
- tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
- }
- }
-
- // Wait indefinitely for the dump to finish or be canceled.
- // We cannot apply a timeout here because the other thread is accessing state that
- // is owned by this thread, such as milist. It should not take very
- // long to take the dump once started.
- while (tid_state == STATE_DUMPING) {
- ALOGV("Waiting for thread %d to finish dumping the stack...", tid);
- usleep(1000);
- tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
- }
-
- if (tid_state == STATE_DONE) {
- frames = g_unwind_signal_state.returned_frames;
- }
-
- sigaction(SIGURG, &oact, NULL);
- }
-
- release_my_map_info_list(milist);
- pthread_mutex_unlock(&g_unwind_signal_mutex);
- return frames;
-#else
- return -1;
-#endif
-}
-
-ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context,
- backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
-#ifdef CORKSCREW_HAVE_ARCH
- return unwind_backtrace_ptrace_arch(tid, context, backtrace, ignore_depth, max_depth);
-#else
- return -1;
-#endif
-}
-
-static void init_backtrace_symbol(backtrace_symbol_t* symbol, uintptr_t pc) {
- symbol->relative_pc = pc;
- symbol->relative_symbol_addr = 0;
- symbol->map_name = NULL;
- symbol->symbol_name = NULL;
- symbol->demangled_name = NULL;
-}
-
-void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames,
- backtrace_symbol_t* backtrace_symbols) {
- map_info_t* milist = acquire_my_map_info_list();
- for (size_t i = 0; i < frames; i++) {
- const backtrace_frame_t* frame = &backtrace[i];
- backtrace_symbol_t* symbol = &backtrace_symbols[i];
- init_backtrace_symbol(symbol, frame->absolute_pc);
-
- const map_info_t* mi = find_map_info(milist, frame->absolute_pc);
- if (mi) {
- symbol->relative_pc = frame->absolute_pc - mi->start;
- if (mi->name[0]) {
- symbol->map_name = strdup(mi->name);
- }
- Dl_info info;
- if (dladdr((const void*)frame->absolute_pc, &info) && info.dli_sname) {
- symbol->relative_symbol_addr = (uintptr_t)info.dli_saddr
- - (uintptr_t)info.dli_fbase;
- symbol->symbol_name = strdup(info.dli_sname);
- symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
- }
- }
- }
- release_my_map_info_list(milist);
-}
-
-void get_backtrace_symbols_ptrace(const ptrace_context_t* context,
- const backtrace_frame_t* backtrace, size_t frames,
- backtrace_symbol_t* backtrace_symbols) {
- for (size_t i = 0; i < frames; i++) {
- const backtrace_frame_t* frame = &backtrace[i];
- backtrace_symbol_t* symbol = &backtrace_symbols[i];
- init_backtrace_symbol(symbol, frame->absolute_pc);
-
- const map_info_t* mi;
- const symbol_t* s;
- find_symbol_ptrace(context, frame->absolute_pc, &mi, &s);
- if (mi) {
- symbol->relative_pc = frame->absolute_pc - mi->start;
- if (mi->name[0]) {
- symbol->map_name = strdup(mi->name);
- }
- }
- if (s) {
- symbol->relative_symbol_addr = s->start;
- symbol->symbol_name = strdup(s->name);
- symbol->demangled_name = demangle_symbol_name(symbol->symbol_name);
- }
- }
-}
-
-void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames) {
- for (size_t i = 0; i < frames; i++) {
- backtrace_symbol_t* symbol = &backtrace_symbols[i];
- free(symbol->map_name);
- free(symbol->symbol_name);
- free(symbol->demangled_name);
- init_backtrace_symbol(symbol, 0);
- }
-}
-
-void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame __attribute__((unused)),
- const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
- const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
- const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
- int fieldWidth = (bufferSize - 80) / 2;
- if (symbolName) {
- uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
- if (pc_offset) {
- snprintf(buffer, bufferSize, "#%02u pc %08x %.*s (%.*s+%u)",
- frameNumber, (unsigned int) symbol->relative_pc,
- fieldWidth, mapName, fieldWidth, symbolName, pc_offset);
- } else {
- snprintf(buffer, bufferSize, "#%02u pc %08x %.*s (%.*s)",
- frameNumber, (unsigned int) symbol->relative_pc,
- fieldWidth, mapName, fieldWidth, symbolName);
- }
- } else {
- snprintf(buffer, bufferSize, "#%02u pc %08x %.*s",
- frameNumber, (unsigned int) symbol->relative_pc,
- fieldWidth, mapName);
- }
-}
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
deleted file mode 100644
index 30ab1b0..0000000
--- a/libcorkscrew/demangle.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/demangle.h>
-
-#include <cutils/log.h>
-
-extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
- int *status);
-
-char* demangle_symbol_name(const char* name) {
-#if defined(__APPLE__)
- // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
- if (name != NULL && name[0] != '_') {
- return NULL;
- }
-#endif
- // __cxa_demangle handles NULL by returning NULL
- return __cxa_demangle(name, 0, 0, 0);
-}
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
deleted file mode 100644
index 93dffbf..0000000
--- a/libcorkscrew/map_info.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/map_info.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <cutils/log.h>
-#include <sys/time.h>
-
-#if defined(__APPLE__)
-
-// Mac OS vmmap(1) output:
-// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
-static map_info_t* parse_vmmap_line(const char* line) {
- unsigned long int start;
- unsigned long int end;
- char permissions[4];
- int name_pos;
- if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
- &start, &end, permissions, &name_pos) != 3) {
- return NULL;
- }
-
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
-
- map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len);
- if (mi != NULL) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = permissions[0] == 'r';
- mi->is_writable = permissions[1] == 'w';
- mi->is_executable = permissions[2] == 'x';
- mi->data = NULL;
- memcpy(mi->name, name, name_len);
- mi->name[name_len - 1] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-map_info_t* load_map_info_list(pid_t pid) {
- char cmd[1024];
- snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
- FILE* fp = popen(cmd, "r");
- if (fp == NULL) {
- return NULL;
- }
-
- char line[1024];
- map_info_t* milist = NULL;
- while (fgets(line, sizeof(line), fp) != NULL) {
- map_info_t* mi = parse_vmmap_line(line);
- if (mi != NULL) {
- mi->next = milist;
- milist = mi;
- }
- }
- pclose(fp);
- return milist;
-}
-
-#else
-
-// Linux /proc/<pid>/maps lines:
-// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
-// 012345678901234567890123456789012345678901234567890123456789
-// 0 1 2 3 4 5
-static map_info_t* parse_maps_line(const char* line)
-{
- unsigned long int start;
- unsigned long int end;
- char permissions[5];
- int name_pos;
- if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
- permissions, &name_pos) != 3) {
- return NULL;
- }
-
- while (isspace(line[name_pos])) {
- name_pos += 1;
- }
- const char* name = line + name_pos;
- size_t name_len = strlen(name);
- if (name_len && name[name_len - 1] == '\n') {
- name_len -= 1;
- }
-
- map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len + 1);
- if (mi) {
- mi->start = start;
- mi->end = end;
- mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
- mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
- mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
- mi->data = NULL;
- memcpy(mi->name, name, name_len);
- mi->name[name_len] = '\0';
- ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
- }
- return mi;
-}
-
-map_info_t* load_map_info_list(pid_t tid) {
- char path[PATH_MAX];
- char line[1024];
- FILE* fp;
- map_info_t* milist = NULL;
-
- snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
- fp = fopen(path, "r");
- if (fp) {
- while(fgets(line, sizeof(line), fp)) {
- map_info_t* mi = parse_maps_line(line);
- if (mi) {
- mi->next = milist;
- milist = mi;
- }
- }
- fclose(fp);
- }
- return milist;
-}
-
-#endif
-
-void free_map_info_list(map_info_t* milist) {
- while (milist) {
- map_info_t* next = milist->next;
- free(milist);
- milist = next;
- }
-}
-
-const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr) {
- const map_info_t* mi = milist;
- while (mi && !(addr >= mi->start && addr < mi->end)) {
- mi = mi->next;
- }
- return mi;
-}
-
-bool is_readable_map(const map_info_t* milist, uintptr_t addr) {
- const map_info_t* mi = find_map_info(milist, addr);
- return mi && mi->is_readable;
-}
-
-bool is_writable_map(const map_info_t* milist, uintptr_t addr) {
- const map_info_t* mi = find_map_info(milist, addr);
- return mi && mi->is_writable;
-}
-
-bool is_executable_map(const map_info_t* milist, uintptr_t addr) {
- const map_info_t* mi = find_map_info(milist, addr);
- return mi && mi->is_executable;
-}
-
-static pthread_mutex_t g_my_map_info_list_mutex = PTHREAD_MUTEX_INITIALIZER;
-static map_info_t* g_my_map_info_list = NULL;
-
-static const int64_t MAX_CACHE_AGE = 5 * 1000 * 1000000LL;
-
-typedef struct {
- uint32_t refs;
- int64_t timestamp;
-} my_map_info_data_t;
-
-static int64_t now_ns() {
-#if defined(HAVE_POSIX_CLOCKS)
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return t.tv_sec * 1000000000LL + t.tv_nsec;
-#else
- struct timeval t;
- gettimeofday(&t, NULL);
- return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
-#endif
-}
-
-static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
- if (!--data->refs) {
- ALOGV("Freed my_map_info_list %p.", milist);
- free(data);
- free_map_info_list(milist);
- }
-}
-
-map_info_t* acquire_my_map_info_list() {
- pthread_mutex_lock(&g_my_map_info_list_mutex);
-
- int64_t time = now_ns();
- if (g_my_map_info_list != NULL) {
- my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
- int64_t age = time - data->timestamp;
- if (age >= MAX_CACHE_AGE) {
- ALOGV("Invalidated my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
- dec_ref(g_my_map_info_list, data);
- g_my_map_info_list = NULL;
- } else {
- ALOGV("Reusing my_map_info_list %p, age=%lld.", g_my_map_info_list, age);
- }
- }
-
- if (g_my_map_info_list == NULL) {
- my_map_info_data_t* data = (my_map_info_data_t*)malloc(sizeof(my_map_info_data_t));
- g_my_map_info_list = load_map_info_list(getpid());
- if (g_my_map_info_list != NULL) {
- ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
- g_my_map_info_list->data = data;
- data->refs = 1;
- data->timestamp = time;
- } else {
- free(data);
- }
- }
-
- map_info_t* milist = g_my_map_info_list;
- if (milist) {
- my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
- data->refs += 1;
- }
-
- pthread_mutex_unlock(&g_my_map_info_list_mutex);
- return milist;
-}
-
-void release_my_map_info_list(map_info_t* milist) {
- if (milist) {
- pthread_mutex_lock(&g_my_map_info_list_mutex);
-
- my_map_info_data_t* data = (my_map_info_data_t*)milist->data;
- dec_ref(milist, data);
-
- pthread_mutex_unlock(&g_my_map_info_list_mutex);
- }
-}
-
-void flush_my_map_info_list() {
- pthread_mutex_lock(&g_my_map_info_list_mutex);
-
- if (g_my_map_info_list != NULL) {
- my_map_info_data_t* data = (my_map_info_data_t*) g_my_map_info_list->data;
- dec_ref(g_my_map_info_list, data);
- g_my_map_info_list = NULL;
- }
-
- pthread_mutex_unlock(&g_my_map_info_list_mutex);
-}
diff --git a/libcorkscrew/ptrace-arch.h b/libcorkscrew/ptrace-arch.h
deleted file mode 100755
index 0bcff63..0000000
--- a/libcorkscrew/ptrace-arch.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-/* Architecture dependent functions. */
-
-#ifndef _CORKSCREW_PTRACE_ARCH_H
-#define _CORKSCREW_PTRACE_ARCH_H
-
-#include <corkscrew/ptrace.h>
-#include <corkscrew/map_info.h>
-#include <corkscrew/symbol_table.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Custom extra data we stuff into map_info_t structures as part
- * of our ptrace_context_t. */
-typedef struct {
-#ifdef __arm__
- uintptr_t exidx_start;
- size_t exidx_size;
-#elif __mips__
- uintptr_t eh_frame_hdr;
-#elif __i386__
- uintptr_t eh_frame_hdr;
-#endif
- symbol_table_t* symbol_table;
-} map_info_data_t;
-
-void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data);
-void free_ptrace_map_info_data_arch(map_info_t* mi, map_info_data_t* data);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _CORKSCREW_PTRACE_ARCH_H
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
deleted file mode 100644
index be58f7f..0000000
--- a/libcorkscrew/ptrace.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include "ptrace-arch.h"
-#include <corkscrew/ptrace.h>
-
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/ptrace.h>
-#include <cutils/log.h>
-
-static const uint32_t ELF_MAGIC = 0x464C457f; // "ELF\0177"
-
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-
-#ifndef PAGE_MASK
-#define PAGE_MASK (~(PAGE_SIZE - 1))
-#endif
-
-void init_memory(memory_t* memory, const map_info_t* map_info_list) {
- memory->tid = -1;
- memory->map_info_list = map_info_list;
-}
-
-void init_memory_ptrace(memory_t* memory, pid_t tid) {
- memory->tid = tid;
- memory->map_info_list = NULL;
-}
-
-bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
- ALOGV("try_get_word: reading word at %p", (void*) ptr);
- if (ptr & 3) {
- ALOGV("try_get_word: invalid pointer %p", (void*) ptr);
- *out_value = 0xffffffffL;
- return false;
- }
- if (memory->tid < 0) {
- if (!is_readable_map(memory->map_info_list, ptr)) {
- ALOGV("try_get_word: pointer %p not in a readable map", (void*) ptr);
- *out_value = 0xffffffffL;
- return false;
- }
- *out_value = *(uint32_t*)ptr;
- return true;
- } else {
-#if defined(__APPLE__)
- ALOGV("no ptrace on Mac OS");
- return false;
-#else
- // ptrace() returns -1 and sets errno when the operation fails.
- // To disambiguate -1 from a valid result, we clear errno beforehand.
- errno = 0;
- *out_value = ptrace(PTRACE_PEEKTEXT, memory->tid, (void*)ptr, NULL);
- if (*out_value == 0xffffffffL && errno) {
- ALOGV("try_get_word: invalid pointer 0x%08x reading from tid %d, "
- "ptrace() errno=%d", ptr, memory->tid, errno);
- return false;
- }
- return true;
-#endif
- }
-}
-
-bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value) {
- memory_t memory;
- init_memory_ptrace(&memory, tid);
- return try_get_word(&memory, ptr, out_value);
-}
-
-static void load_ptrace_map_info_data(pid_t pid, map_info_t* mi) {
- if (mi->is_executable && mi->is_readable) {
- uint32_t elf_magic;
- if (try_get_word_ptrace(pid, mi->start, &elf_magic) && elf_magic == ELF_MAGIC) {
- map_info_data_t* data = (map_info_data_t*)calloc(1, sizeof(map_info_data_t));
- if (data) {
- mi->data = data;
- if (mi->name[0]) {
- data->symbol_table = load_symbol_table(mi->name);
- }
-#ifdef CORKSCREW_HAVE_ARCH
- load_ptrace_map_info_data_arch(pid, mi, data);
-#endif
- }
- }
- }
-}
-
-ptrace_context_t* load_ptrace_context(pid_t pid) {
- ptrace_context_t* context =
- (ptrace_context_t*)calloc(1, sizeof(ptrace_context_t));
- if (context) {
- context->map_info_list = load_map_info_list(pid);
- for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
- load_ptrace_map_info_data(pid, mi);
- }
- }
- return context;
-}
-
-static void free_ptrace_map_info_data(map_info_t* mi) {
- map_info_data_t* data = (map_info_data_t*)mi->data;
- if (data) {
- if (data->symbol_table) {
- free_symbol_table(data->symbol_table);
- }
-#ifdef CORKSCREW_HAVE_ARCH
- free_ptrace_map_info_data_arch(mi, data);
-#endif
- free(data);
- mi->data = NULL;
- }
-}
-
-void free_ptrace_context(ptrace_context_t* context) {
- for (map_info_t* mi = context->map_info_list; mi; mi = mi->next) {
- 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,
- uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol) {
- const map_info_t* mi = find_map_info(context->map_info_list, addr);
- const symbol_t* symbol = NULL;
- if (mi) {
- const map_info_data_t* data = (const map_info_data_t*)mi->data;
- if (data && data->symbol_table) {
- symbol = find_symbol(data->symbol_table, addr - mi->start);
- }
- }
- *out_map_info = mi;
- *out_symbol = symbol;
-}
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
deleted file mode 100644
index 982ccc8..0000000
--- a/libcorkscrew/symbol_table.c
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Corkscrew"
-//#define LOG_NDEBUG 0
-
-#include <corkscrew/symbol_table.h>
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <cutils/log.h>
-
-#if defined(__APPLE__)
-#else
-
-#include <elf.h>
-
-static bool is_elf(Elf32_Ehdr* e) {
- return (e->e_ident[EI_MAG0] == ELFMAG0 &&
- e->e_ident[EI_MAG1] == ELFMAG1 &&
- e->e_ident[EI_MAG2] == ELFMAG2 &&
- e->e_ident[EI_MAG3] == ELFMAG3);
-}
-
-#endif
-
-// Compare function for qsort
-static int qcompar(const void *a, const void *b) {
- const symbol_t* asym = (const symbol_t*)a;
- const symbol_t* bsym = (const symbol_t*)b;
- if (asym->start > bsym->start) return 1;
- if (asym->start < bsym->start) return -1;
- return 0;
-}
-
-// Compare function for bsearch
-static int bcompar(const void *key, const void *element) {
- uintptr_t addr = *(const uintptr_t*)key;
- const symbol_t* symbol = (const symbol_t*)element;
- if (addr < symbol->start) return -1;
- if (addr >= symbol->end) return 1;
- return 0;
-}
-
-symbol_table_t* load_symbol_table(const char *filename) {
- symbol_table_t* table = NULL;
-#if !defined(__APPLE__)
- ALOGV("Loading symbol table from '%s'.", filename);
-
- int fd = open(filename, O_RDONLY);
- if (fd < 0) {
- goto out;
- }
-
- struct stat sb;
- if (fstat(fd, &sb)) {
- goto out_close;
- }
-
- size_t length = sb.st_size;
- char* base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
- if (base == MAP_FAILED) {
- goto out_close;
- }
-
- // Parse the file header
- Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
- if (!is_elf(hdr)) {
- goto out_close;
- }
- Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
-
- // Search for the dynamic symbols section
- int sym_idx = -1;
- int dynsym_idx = -1;
- for (Elf32_Half i = 0; i < hdr->e_shnum; i++) {
- if (shdr[i].sh_type == SHT_SYMTAB) {
- sym_idx = i;
- }
- if (shdr[i].sh_type == SHT_DYNSYM) {
- dynsym_idx = i;
- }
- }
- if (dynsym_idx == -1 && sym_idx == -1) {
- goto out_unmap;
- }
-
- table = malloc(sizeof(symbol_table_t));
- if(!table) {
- goto out_unmap;
- }
- table->num_symbols = 0;
-
- Elf32_Sym *dynsyms = NULL;
- int dynnumsyms = 0;
- char *dynstr = NULL;
- if (dynsym_idx != -1) {
- dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
- dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
- int dynstr_idx = shdr[dynsym_idx].sh_link;
- dynstr = base + shdr[dynstr_idx].sh_offset;
- }
-
- Elf32_Sym *syms = NULL;
- int numsyms = 0;
- char *str = NULL;
- if (sym_idx != -1) {
- syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
- numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
- int str_idx = shdr[sym_idx].sh_link;
- str = base + shdr[str_idx].sh_offset;
- }
-
- int dynsymbol_count = 0;
- if (dynsym_idx != -1) {
- // Iterate through the dynamic symbol table, and count how many symbols
- // are actually defined
- for (int i = 0; i < dynnumsyms; i++) {
- if (dynsyms[i].st_shndx != SHN_UNDEF) {
- dynsymbol_count++;
- }
- }
- }
-
- size_t symbol_count = 0;
- if (sym_idx != -1) {
- // Iterate through the symbol table, and count how many symbols
- // are actually defined
- for (int i = 0; i < numsyms; i++) {
- if (syms[i].st_shndx != SHN_UNDEF
- && str[syms[i].st_name]
- && syms[i].st_value
- && syms[i].st_size) {
- symbol_count++;
- }
- }
- }
-
- // Now, create an entry in our symbol table structure for each symbol...
- table->num_symbols += symbol_count + dynsymbol_count;
- table->symbols = malloc(table->num_symbols * sizeof(symbol_t));
- if (!table->symbols) {
- free(table);
- table = NULL;
- goto out_unmap;
- }
-
- size_t symbol_index = 0;
- if (dynsym_idx != -1) {
- // ...and populate them
- for (int i = 0; i < dynnumsyms; i++) {
- if (dynsyms[i].st_shndx != SHN_UNDEF) {
- table->symbols[symbol_index].name = strdup(dynstr + dynsyms[i].st_name);
- table->symbols[symbol_index].start = dynsyms[i].st_value;
- table->symbols[symbol_index].end = dynsyms[i].st_value + dynsyms[i].st_size;
- ALOGV(" [%d] '%s' 0x%08x-0x%08x (DYNAMIC)",
- symbol_index, table->symbols[symbol_index].name,
- table->symbols[symbol_index].start, table->symbols[symbol_index].end);
- symbol_index += 1;
- }
- }
- }
-
- if (sym_idx != -1) {
- // ...and populate them
- for (int i = 0; i < numsyms; i++) {
- if (syms[i].st_shndx != SHN_UNDEF
- && str[syms[i].st_name]
- && syms[i].st_value
- && syms[i].st_size) {
- table->symbols[symbol_index].name = strdup(str + syms[i].st_name);
- table->symbols[symbol_index].start = syms[i].st_value;
- table->symbols[symbol_index].end = syms[i].st_value + syms[i].st_size;
- ALOGV(" [%d] '%s' 0x%08x-0x%08x",
- symbol_index, table->symbols[symbol_index].name,
- table->symbols[symbol_index].start, table->symbols[symbol_index].end);
- symbol_index += 1;
- }
- }
- }
-
- // Sort the symbol table entries, so they can be bsearched later
- qsort(table->symbols, table->num_symbols, sizeof(symbol_t), qcompar);
-
-out_unmap:
- munmap(base, length);
-
-out_close:
- close(fd);
-#endif
-
-out:
- return table;
-}
-
-void free_symbol_table(symbol_table_t* table) {
- if (table) {
- for (size_t i = 0; i < table->num_symbols; i++) {
- free(table->symbols[i].name);
- }
- free(table->symbols);
- free(table);
- }
-}
-
-const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr) {
- if (!table) return NULL;
- return (const symbol_t*)bsearch(&addr, table->symbols, table->num_symbols,
- sizeof(symbol_t), bcompar);
-}
diff --git a/libcorkscrew/test.cpp b/libcorkscrew/test.cpp
deleted file mode 100644
index 22dfa7d..0000000
--- a/libcorkscrew/test.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include <corkscrew/backtrace.h>
-#include <corkscrew/symbol_table.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-int do_backtrace(float /* just to test demangling */) {
- const size_t MAX_DEPTH = 32;
- backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
- ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
- fprintf(stderr, "frame_count=%d\n", (int) frame_count);
- if (frame_count <= 0) {
- return frame_count;
- }
-
- backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
- get_backtrace_symbols(frames, frame_count, backtrace_symbols);
-
- for (size_t i = 0; i < (size_t) frame_count; ++i) {
- char line[MAX_BACKTRACE_LINE_LENGTH];
- format_backtrace_line(i, &frames[i], &backtrace_symbols[i],
- line, MAX_BACKTRACE_LINE_LENGTH);
- if (backtrace_symbols[i].symbol_name != NULL) {
- // get_backtrace_symbols found the symbol's name with dladdr(3).
- fprintf(stderr, " %s\n", line);
- } else {
- // We don't have a symbol. Maybe this is a static symbol, and
- // we can look it up?
- symbol_table_t* symbols = NULL;
- if (backtrace_symbols[i].map_name != NULL) {
- symbols = load_symbol_table(backtrace_symbols[i].map_name);
- }
- const symbol_t* symbol = NULL;
- if (symbols != NULL) {
- symbol = find_symbol(symbols, frames[i].absolute_pc);
- }
- if (symbol != NULL) {
- int offset = frames[i].absolute_pc - symbol->start;
- fprintf(stderr, " %s (%s%+d)\n", line, symbol->name, offset);
- } else {
- fprintf(stderr, " %s (\?\?\?)\n", line);
- }
- free_symbol_table(symbols);
- }
- }
-
- free_backtrace_symbols(backtrace_symbols, frame_count);
- free(backtrace_symbols);
- free(frames);
- return frame_count;
-}
-
-struct C {
- int g(int i);
-};
-
-__attribute__ ((noinline)) int C::g(int i) {
- if (i == 0) {
- return do_backtrace(0.1);
- }
- return g(i - 1);
-}
-
-extern "C" __attribute__ ((noinline)) int f() {
- C c;
- return c.g(5);
-}
-
-int main() {
- flush_my_map_info_list();
- f();
-
- flush_my_map_info_list();
- f();
-
- return 0;
-}
diff --git a/libctest/Android.mk b/libctest/Android.mk
deleted file mode 100644
index 815fabb..0000000
--- a/libctest/Android.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libctest
-LOCAL_SRC_FILES := ctest.c
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libctest/NOTICE b/libctest/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libctest/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/libctest/ctest.c b/libctest/ctest.c
deleted file mode 100644
index ee6331f..0000000
--- a/libctest/ctest.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2007 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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctest/ctest.h>
-
-#define MAX_TESTS 255
-
-/** Semi-random number used to identify assertion errors. */
-#define ASSERTION_ERROR 42
-
-typedef void TestCase();
-
-/** A suite of tests. */
-typedef struct {
- int size;
- const char* testNames[MAX_TESTS];
- TestCase* tests[MAX_TESTS];
- int currentTest;
- FILE* out;
-} TestSuite;
-
-/** Gets the test suite. Creates it if necessary. */
-static TestSuite* getTestSuite() {
- static TestSuite* suite = NULL;
-
- if (suite != NULL) {
- return suite;
- }
-
- suite = calloc(1, sizeof(TestSuite));
- assert(suite != NULL);
-
- suite->out = tmpfile();
- assert(suite->out != NULL);
-
- return suite;
-}
-
-void addNamedTest(const char* name, TestCase* test) {
- TestSuite* testSuite = getTestSuite();
- assert(testSuite->size <= MAX_TESTS);
-
- int index = testSuite->size;
- testSuite->testNames[index] = name;
- testSuite->tests[index] = test;
-
- testSuite->size++;
-}
-
-/** Prints failures to stderr. */
-static void printFailures(int failures) {
- TestSuite* suite = getTestSuite();
-
- fprintf(stderr, "FAILURE! %d of %d tests failed. Failures:\n",
- failures, suite->size);
-
- // Copy test output to stdout.
- rewind(suite->out);
- char buffer[512];
- size_t read;
- while ((read = fread(buffer, sizeof(char), 512, suite->out)) > 0) {
- // TODO: Make sure we actually wrote 'read' bytes.
- fwrite(buffer, sizeof(char), read, stderr);
- }
-}
-
-/** Runs a single test case. */
-static int runCurrentTest() {
- TestSuite* suite = getTestSuite();
-
- pid_t pid = fork();
- if (pid == 0) {
- // Child process. Runs test case.
- suite->tests[suite->currentTest]();
-
- // Exit successfully.
- exit(0);
- } else if (pid < 0) {
- fprintf(stderr, "Fork failed.");
- exit(1);
- } else {
- // Parent process. Wait for child.
- int status;
- waitpid(pid, &status, 0);
-
- if (!WIFEXITED(status)) {
- return -1;
- }
-
- return WEXITSTATUS(status);
- }
-}
-
-void runTests() {
- TestSuite* suite = getTestSuite();
-
- int failures = 0;
- for (suite->currentTest = 0; suite->currentTest < suite->size;
- suite->currentTest++) {
- // Flush stdout before forking.
- fflush(stdout);
-
- int result = runCurrentTest();
-
- if (result != 0) {
- printf("X");
-
- failures++;
-
- // Handle errors other than assertions.
- if (result != ASSERTION_ERROR) {
- // TODO: Report file name.
- fprintf(suite->out, "Process failed: [%s] status: %d\n",
- suite->testNames[suite->currentTest], result);
- fflush(suite->out);
- }
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- if (failures > 0) {
- printFailures(failures);
- } else {
- printf("SUCCESS! %d tests ran successfully.\n", suite->size);
- }
-}
-
-void assertTrueWithSource(int value, const char* file, int line, char* message) {
- if (!value) {
- TestSuite* suite = getTestSuite();
-
- fprintf(suite->out, "Assertion failed: [%s:%d] %s: %s\n", file, line,
- suite->testNames[suite->currentTest], message);
- fflush(suite->out);
-
- // Exit the process for this test case.
- exit(ASSERTION_ERROR);
- }
-}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 635695a..933a77b 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -27,13 +27,6 @@
hashmap.c \
atomic.c.arm \
native_handle.c \
- socket_inaddr_any_server.c \
- socket_local_client.c \
- socket_local_server.c \
- socket_loopback_client.c \
- socket_loopback_server.c \
- socket_network_client.c \
- sockets.c \
config_utils.c \
cpu_info.c \
load_file.c \
@@ -47,9 +40,6 @@
iosched_policy.c \
str_parms.c \
-commonHostSources := \
- ashmem-host.c
-
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
# which are also hard or even impossible to port to native Win32
@@ -67,7 +57,18 @@
ifneq ($(WINDOWS_HOST_ONLY),1)
commonSources += \
fs.c \
- multiuser.c
+ multiuser.c \
+ socket_inaddr_any_server.c \
+ socket_local_client.c \
+ socket_local_server.c \
+ socket_loopback_client.c \
+ socket_loopback_server.c \
+ socket_network_client.c \
+ sockets.c \
+
+ commonHostSources += \
+ ashmem-host.c
+
endif
@@ -75,9 +76,13 @@
# ========================================================
LOCAL_MODULE := libcutils
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_LDLIBS := -lpthread
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(hostSmpFlag)
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_MULTILIB := both
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -86,9 +91,12 @@
include $(CLEAR_VARS)
LOCAL_MODULE := lib64cutils
LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_LDLIBS := -lpthread
LOCAL_STATIC_LIBRARIES := lib64log
LOCAL_CFLAGS += $(hostSmpFlag) -m64
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_STATIC_LIBRARY)
# Tests for host
@@ -96,9 +104,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := tst_str_parms
LOCAL_CFLAGS += -DTEST_STR_PARMS
+ifneq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -Werror
+endif
LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_EXECUTABLE)
@@ -112,30 +124,40 @@
ashmem-dev.c \
debugger.c \
klog.c \
+ memory.c \
partition_utils.c \
properties.c \
qtaguid.c \
trace.c \
- uevent.c
+ uevent.c \
-ifeq ($(TARGET_ARCH),arm)
- LOCAL_SRC_FILES += arch-arm/memset32.S
-else # !arm
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32
- LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c
- else # !x86
- ifeq ($(TARGET_ARCH),mips)
- LOCAL_SRC_FILES += arch-mips/android_memset.c
- else # !mips
- LOCAL_SRC_FILES += memory.c
- endif # !mips
- endif # !x86
-endif # !arm
+LOCAL_SRC_FILES_arm += \
+ arch-arm/memset32.S \
+
+LOCAL_SRC_FILES_arm64 += \
+ arch-arm64/android_memset.S \
+
+LOCAL_SRC_FILES_mips += \
+ arch-mips/android_memset.c \
+
+LOCAL_SRC_FILES_x86 += \
+ arch-x86/android_memset16.S \
+ arch-x86/android_memset32.S \
+
+LOCAL_SRC_FILES_x86_64 += \
+ arch-x86_64/android_memset16_SSE2-atom.S \
+ arch-x86_64/android_memset32_SSE2-atom.S \
+
+LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
+LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32
LOCAL_C_INCLUDES := $(libcutils_c_includes)
LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag)
+LOCAL_CFLAGS += $(targetSmpFlag) -Werror
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -144,16 +166,18 @@
# liblog symbols present in libcutils.
LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS += $(targetSmpFlag)
+LOCAL_CFLAGS += $(targetSmpFlag) -Werror
LOCAL_C_INCLUDES := $(libcutils_c_includes)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := tst_str_parms
-LOCAL_CFLAGS += -DTEST_STR_PARMS
+LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror
LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_EXECUTABLE)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index b7895fa..5d98295 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -57,7 +57,7 @@
mount_dir[255] = 0;
mount_type[255] = 0;
mount_opts[255] = 0;
- if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw")) {
+ if ((match == 6) && !strncmp(mount_dev, "/dev/block", 10) && strstr(mount_opts, "rw,")) {
found_rw_fs = 1;
break;
}
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
android_memset32:
.fnstart
- .save {lr}
+ .cfi_startproc
str lr, [sp, #-4]!
+ .cfi_def_cfa_offset 4
+ .cfi_rel_offset lr, 0
/* align the destination to a cache-line */
mov r12, r1
@@ -89,5 +91,8 @@
strmih lr, [r0], #2
ldr lr, [sp], #4
+ .cfi_def_cfa_offset 0
+ .cfi_restore lr
bx lr
+ .cfi_endproc
.fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
new file mode 100644
index 0000000..9a83a68
--- /dev/null
+++ b/libcutils/arch-arm64/android_memset.S
@@ -0,0 +1,211 @@
+/* Copyright (c) 2012, Linaro Limited
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Linaro nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64
+ * Unaligned accesses
+ *
+ */
+
+/* By default we assume that the DC instruction can be used to zero
+ data blocks more efficiently. In some circumstances this might be
+ unsafe, for example in an asymmetric multiprocessor environment with
+ different DC clear lengths (neither the upper nor lower lengths are
+ safe to use). */
+
+#define dst x0
+#define count x2
+#define tmp1 x3
+#define tmp1w w3
+#define tmp2 x4
+#define tmp2w w4
+#define zva_len_x x5
+#define zva_len w5
+#define zva_bits_x x6
+
+#define A_l x1
+#define A_lw w1
+#define tmp3w w9
+
+#define ENTRY(f) \
+ .text; \
+ .globl f; \
+ .align 0; \
+ .type f, %function; \
+ f: \
+ .cfi_startproc \
+
+#define END(f) \
+ .cfi_endproc; \
+ .size f, .-f; \
+
+ENTRY(android_memset16)
+ ands A_lw, A_lw, #0xffff
+ b.eq .Lzero_mem
+ orr A_lw, A_lw, A_lw, lsl #16
+ b .Lexpand_to_64
+END(android_memset16)
+
+ENTRY(android_memset32)
+ cmp A_lw, #0
+ b.eq .Lzero_mem
+.Lexpand_to_64:
+ orr A_l, A_l, A_l, lsl #32
+.Ltail_maybe_long:
+ cmp count, #64
+ b.ge .Lnot_short
+.Ltail_maybe_tiny:
+ cmp count, #15
+ b.le .Ltail15tiny
+.Ltail63:
+ ands tmp1, count, #0x30
+ b.eq .Ltail15
+ add dst, dst, tmp1
+ cmp tmp1w, #0x20
+ b.eq 1f
+ b.lt 2f
+ stp A_l, A_l, [dst, #-48]
+1:
+ stp A_l, A_l, [dst, #-32]
+2:
+ stp A_l, A_l, [dst, #-16]
+
+.Ltail15:
+ and count, count, #15
+ add dst, dst, count
+ stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */
+ ret
+
+.Ltail15tiny:
+ /* Set up to 15 bytes. Does not assume earlier memory
+ being set. */
+ tbz count, #3, 1f
+ str A_l, [dst], #8
+1:
+ tbz count, #2, 1f
+ str A_lw, [dst], #4
+1:
+ tbz count, #1, 1f
+ strh A_lw, [dst], #2
+1:
+ ret
+
+ /* Critical loop. Start at a new cache line boundary. Assuming
+ * 64 bytes per line, this ensures the entire loop is in one line. */
+ .p2align 6
+.Lnot_short:
+ neg tmp2, dst
+ ands tmp2, tmp2, #15
+ b.eq 2f
+ /* Bring DST to 128-bit (16-byte) alignment. We know that there's
+ * more than that to set, so we simply store 16 bytes and advance by
+ * the amount required to reach alignment. */
+ sub count, count, tmp2
+ stp A_l, A_l, [dst]
+ add dst, dst, tmp2
+ /* There may be less than 63 bytes to go now. */
+ cmp count, #63
+ b.le .Ltail63
+2:
+ sub dst, dst, #16 /* Pre-bias. */
+ sub count, count, #64
+1:
+ stp A_l, A_l, [dst, #16]
+ stp A_l, A_l, [dst, #32]
+ stp A_l, A_l, [dst, #48]
+ stp A_l, A_l, [dst, #64]!
+ subs count, count, #64
+ b.ge 1b
+ tst count, #0x3f
+ add dst, dst, #16
+ b.ne .Ltail63
+ ret
+
+ /* For zeroing memory, check to see if we can use the ZVA feature to
+ * zero entire 'cache' lines. */
+.Lzero_mem:
+ mov A_l, #0
+ cmp count, #63
+ b.le .Ltail_maybe_tiny
+ neg tmp2, dst
+ ands tmp2, tmp2, #15
+ b.eq 1f
+ sub count, count, tmp2
+ stp A_l, A_l, [dst]
+ add dst, dst, tmp2
+ cmp count, #63
+ b.le .Ltail63
+1:
+ /* For zeroing small amounts of memory, it's not worth setting up
+ * the line-clear code. */
+ cmp count, #128
+ b.lt .Lnot_short
+ mrs tmp1, dczid_el0
+ tbnz tmp1, #4, .Lnot_short
+ mov tmp3w, #4
+ and zva_len, tmp1w, #15 /* Safety: other bits reserved. */
+ lsl zva_len, tmp3w, zva_len
+
+.Lzero_by_line:
+ /* Compute how far we need to go to become suitably aligned. We're
+ * already at quad-word alignment. */
+ cmp count, zva_len_x
+ b.lt .Lnot_short /* Not enough to reach alignment. */
+ sub zva_bits_x, zva_len_x, #1
+ neg tmp2, dst
+ ands tmp2, tmp2, zva_bits_x
+ b.eq 1f /* Already aligned. */
+ /* Not aligned, check that there's enough to copy after alignment. */
+ sub tmp1, count, tmp2
+ cmp tmp1, #64
+ ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */
+ b.lt .Lnot_short
+ /* We know that there's at least 64 bytes to zero and that it's safe
+ * to overrun by 64 bytes. */
+ mov count, tmp1
+2:
+ stp A_l, A_l, [dst]
+ stp A_l, A_l, [dst, #16]
+ stp A_l, A_l, [dst, #32]
+ subs tmp2, tmp2, #64
+ stp A_l, A_l, [dst, #48]
+ add dst, dst, #64
+ b.ge 2b
+ /* We've overrun a bit, so adjust dst downwards. */
+ add dst, dst, tmp2
+1:
+ sub count, count, zva_len_x
+3:
+ dc zva, dst
+ add dst, dst, zva_len_x
+ subs count, count, zva_len_x
+ b.ge 3b
+ ands count, count, zva_bits_x
+ b.ne .Ltail_maybe_long
+ ret
+END(android_memset32)
diff --git a/libcutils/arch-x86/cache_wrapper.S b/libcutils/arch-x86/cache_wrapper.S
index 508fdd3..9eee25c 100644
--- a/libcutils/arch-x86/cache_wrapper.S
+++ b/libcutils/arch-x86/cache_wrapper.S
@@ -17,8 +17,15 @@
* Contributed by: Intel Corporation
*/
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */
+#else
/* Values are optimized for Atom */
-#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */
-#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */
+#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */
+#endif
+
#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2)
#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2)
diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
new file mode 100644
index 0000000..48a10ed
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S
@@ -0,0 +1,564 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label) .L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n) .p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc .cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc .cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name) \
+ .type name, @function; \
+ .globl name; \
+ .p2align 4; \
+name: \
+ cfi_startproc
+#endif
+
+#ifndef END
+# define END(name) \
+ cfi_endproc; \
+ .size name, .-name
+#endif
+
+#define JMPTBL(I, B) I - B
+
+/* Branch to an entry in a jump table. TABLE is a jump table with
+ relative offsets. INDEX is a register contains the index into the
+ jump table. SCALE is the scale of INDEX. */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+ lea TABLE(%rip), %r11; \
+ movslq (%r11, INDEX, SCALE), INDEX; \
+ lea (%r11, INDEX), INDEX; \
+ jmp *INDEX
+
+ .section .text.sse2,"ax",@progbits
+ ALIGN (4)
+ENTRY (android_memset16) // Address in rdi
+ shr $1, %rdx // Count in rdx
+ movzwl %si, %ecx
+ /* Fill the whole ECX with pattern. */
+ shl $16, %esi
+ or %esi, %ecx // Pattern in ecx
+
+ cmp $32, %rdx
+ jae L(32wordsormore)
+
+L(write_less32words):
+ lea (%rdi, %rdx, 2), %rdi
+ BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
+
+ .pushsection .rodata.sse2,"a",@progbits
+ ALIGN (2)
+L(table_less32words):
+ .int JMPTBL (L(write_0words), L(table_less32words))
+ .int JMPTBL (L(write_1words), L(table_less32words))
+ .int JMPTBL (L(write_2words), L(table_less32words))
+ .int JMPTBL (L(write_3words), L(table_less32words))
+ .int JMPTBL (L(write_4words), L(table_less32words))
+ .int JMPTBL (L(write_5words), L(table_less32words))
+ .int JMPTBL (L(write_6words), L(table_less32words))
+ .int JMPTBL (L(write_7words), L(table_less32words))
+ .int JMPTBL (L(write_8words), L(table_less32words))
+ .int JMPTBL (L(write_9words), L(table_less32words))
+ .int JMPTBL (L(write_10words), L(table_less32words))
+ .int JMPTBL (L(write_11words), L(table_less32words))
+ .int JMPTBL (L(write_12words), L(table_less32words))
+ .int JMPTBL (L(write_13words), L(table_less32words))
+ .int JMPTBL (L(write_14words), L(table_less32words))
+ .int JMPTBL (L(write_15words), L(table_less32words))
+ .int JMPTBL (L(write_16words), L(table_less32words))
+ .int JMPTBL (L(write_17words), L(table_less32words))
+ .int JMPTBL (L(write_18words), L(table_less32words))
+ .int JMPTBL (L(write_19words), L(table_less32words))
+ .int JMPTBL (L(write_20words), L(table_less32words))
+ .int JMPTBL (L(write_21words), L(table_less32words))
+ .int JMPTBL (L(write_22words), L(table_less32words))
+ .int JMPTBL (L(write_23words), L(table_less32words))
+ .int JMPTBL (L(write_24words), L(table_less32words))
+ .int JMPTBL (L(write_25words), L(table_less32words))
+ .int JMPTBL (L(write_26words), L(table_less32words))
+ .int JMPTBL (L(write_27words), L(table_less32words))
+ .int JMPTBL (L(write_28words), L(table_less32words))
+ .int JMPTBL (L(write_29words), L(table_less32words))
+ .int JMPTBL (L(write_30words), L(table_less32words))
+ .int JMPTBL (L(write_31words), L(table_less32words))
+ .popsection
+
+ ALIGN (4)
+L(write_28words):
+ movl %ecx, -56(%rdi)
+ movl %ecx, -52(%rdi)
+L(write_24words):
+ movl %ecx, -48(%rdi)
+ movl %ecx, -44(%rdi)
+L(write_20words):
+ movl %ecx, -40(%rdi)
+ movl %ecx, -36(%rdi)
+L(write_16words):
+ movl %ecx, -32(%rdi)
+ movl %ecx, -28(%rdi)
+L(write_12words):
+ movl %ecx, -24(%rdi)
+ movl %ecx, -20(%rdi)
+L(write_8words):
+ movl %ecx, -16(%rdi)
+ movl %ecx, -12(%rdi)
+L(write_4words):
+ movl %ecx, -8(%rdi)
+ movl %ecx, -4(%rdi)
+L(write_0words):
+ ret
+
+ ALIGN (4)
+L(write_29words):
+ movl %ecx, -58(%rdi)
+ movl %ecx, -54(%rdi)
+L(write_25words):
+ movl %ecx, -50(%rdi)
+ movl %ecx, -46(%rdi)
+L(write_21words):
+ movl %ecx, -42(%rdi)
+ movl %ecx, -38(%rdi)
+L(write_17words):
+ movl %ecx, -34(%rdi)
+ movl %ecx, -30(%rdi)
+L(write_13words):
+ movl %ecx, -26(%rdi)
+ movl %ecx, -22(%rdi)
+L(write_9words):
+ movl %ecx, -18(%rdi)
+ movl %ecx, -14(%rdi)
+L(write_5words):
+ movl %ecx, -10(%rdi)
+ movl %ecx, -6(%rdi)
+L(write_1words):
+ mov %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(write_30words):
+ movl %ecx, -60(%rdi)
+ movl %ecx, -56(%rdi)
+L(write_26words):
+ movl %ecx, -52(%rdi)
+ movl %ecx, -48(%rdi)
+L(write_22words):
+ movl %ecx, -44(%rdi)
+ movl %ecx, -40(%rdi)
+L(write_18words):
+ movl %ecx, -36(%rdi)
+ movl %ecx, -32(%rdi)
+L(write_14words):
+ movl %ecx, -28(%rdi)
+ movl %ecx, -24(%rdi)
+L(write_10words):
+ movl %ecx, -20(%rdi)
+ movl %ecx, -16(%rdi)
+L(write_6words):
+ movl %ecx, -12(%rdi)
+ movl %ecx, -8(%rdi)
+L(write_2words):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(write_31words):
+ movl %ecx, -62(%rdi)
+ movl %ecx, -58(%rdi)
+L(write_27words):
+ movl %ecx, -54(%rdi)
+ movl %ecx, -50(%rdi)
+L(write_23words):
+ movl %ecx, -46(%rdi)
+ movl %ecx, -42(%rdi)
+L(write_19words):
+ movl %ecx, -38(%rdi)
+ movl %ecx, -34(%rdi)
+L(write_15words):
+ movl %ecx, -30(%rdi)
+ movl %ecx, -26(%rdi)
+L(write_11words):
+ movl %ecx, -22(%rdi)
+ movl %ecx, -18(%rdi)
+L(write_7words):
+ movl %ecx, -14(%rdi)
+ movl %ecx, -10(%rdi)
+L(write_3words):
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(32wordsormore):
+ shl $1, %rdx
+ test $0x01, %edi
+ jz L(aligned2bytes)
+ mov %ecx, (%rdi)
+ mov %ecx, -4(%rdi, %rdx)
+ sub $2, %rdx
+ add $1, %rdi
+ rol $8, %ecx
+L(aligned2bytes):
+ /* Fill xmm0 with the pattern. */
+ movd %ecx, %xmm0
+ pshufd $0, %xmm0, %xmm0
+
+ testl $0xf, %edi
+ jz L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned. */
+ movdqu %xmm0, (%rdi)
+ mov %rdi, %rsi
+ and $-16, %rdi
+ add $16, %rdi
+ sub %rdi, %rsi
+ add %rsi, %rdx
+
+ ALIGN (4)
+L(aligned_16):
+ cmp $128, %rdx
+ jge L(128bytesormore)
+
+L(aligned_16_less128bytes):
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore):
+ cmp $SHARED_CACHE_SIZE, %rdx
+ jg L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_normal)
+
+L(128bytesless_normal):
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore_nt):
+ sub $128, %rdx
+ movntdq %xmm0, (%rdi)
+ movntdq %xmm0, 0x10(%rdi)
+ movntdq %xmm0, 0x20(%rdi)
+ movntdq %xmm0, 0x30(%rdi)
+ movntdq %xmm0, 0x40(%rdi)
+ movntdq %xmm0, 0x50(%rdi)
+ movntdq %xmm0, 0x60(%rdi)
+ movntdq %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_nt)
+
+ sfence
+ add %rdx, %rdi
+ shr $1, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ .pushsection .rodata.sse2,"a",@progbits
+ ALIGN (2)
+L(table_16_128bytes):
+ .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
+ .popsection
+
+ ALIGN (4)
+L(aligned_16_112bytes):
+ movdqa %xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+ movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+ movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+ movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+ movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+ movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+ movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+ ret
+
+ ALIGN (4)
+L(aligned_16_114bytes):
+ movdqa %xmm0, -114(%rdi)
+L(aligned_16_98bytes):
+ movdqa %xmm0, -98(%rdi)
+L(aligned_16_82bytes):
+ movdqa %xmm0, -82(%rdi)
+L(aligned_16_66bytes):
+ movdqa %xmm0, -66(%rdi)
+L(aligned_16_50bytes):
+ movdqa %xmm0, -50(%rdi)
+L(aligned_16_34bytes):
+ movdqa %xmm0, -34(%rdi)
+L(aligned_16_18bytes):
+ movdqa %xmm0, -18(%rdi)
+L(aligned_16_2bytes):
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_116bytes):
+ movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+ movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+ movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+ movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+ movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+ movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+ movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_118bytes):
+ movdqa %xmm0, -118(%rdi)
+L(aligned_16_102bytes):
+ movdqa %xmm0, -102(%rdi)
+L(aligned_16_86bytes):
+ movdqa %xmm0, -86(%rdi)
+L(aligned_16_70bytes):
+ movdqa %xmm0, -70(%rdi)
+L(aligned_16_54bytes):
+ movdqa %xmm0, -54(%rdi)
+L(aligned_16_38bytes):
+ movdqa %xmm0, -38(%rdi)
+L(aligned_16_22bytes):
+ movdqa %xmm0, -22(%rdi)
+L(aligned_16_6bytes):
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_120bytes):
+ movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+ movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+ movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+ movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+ movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+ movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+ movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+ movq %xmm0, -8(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_122bytes):
+ movdqa %xmm0, -122(%rdi)
+L(aligned_16_106bytes):
+ movdqa %xmm0, -106(%rdi)
+L(aligned_16_90bytes):
+ movdqa %xmm0, -90(%rdi)
+L(aligned_16_74bytes):
+ movdqa %xmm0, -74(%rdi)
+L(aligned_16_58bytes):
+ movdqa %xmm0, -58(%rdi)
+L(aligned_16_42bytes):
+ movdqa %xmm0, -42(%rdi)
+L(aligned_16_26bytes):
+ movdqa %xmm0, -26(%rdi)
+L(aligned_16_10bytes):
+ movq %xmm0, -10(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_124bytes):
+ movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+ movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+ movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+ movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+ movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+ movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+ movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+ movq %xmm0, -12(%rdi)
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_126bytes):
+ movdqa %xmm0, -126(%rdi)
+L(aligned_16_110bytes):
+ movdqa %xmm0, -110(%rdi)
+L(aligned_16_94bytes):
+ movdqa %xmm0, -94(%rdi)
+L(aligned_16_78bytes):
+ movdqa %xmm0, -78(%rdi)
+L(aligned_16_62bytes):
+ movdqa %xmm0, -62(%rdi)
+L(aligned_16_46bytes):
+ movdqa %xmm0, -46(%rdi)
+L(aligned_16_30bytes):
+ movdqa %xmm0, -30(%rdi)
+L(aligned_16_14bytes):
+ movq %xmm0, -14(%rdi)
+ movl %ecx, -6(%rdi)
+ movw %cx, -2(%rdi)
+ ret
+
+END (android_memset16)
diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
new file mode 100644
index 0000000..4bdea8e
--- /dev/null
+++ b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#include "cache.h"
+
+#ifndef L
+# define L(label) .L##label
+#endif
+
+#ifndef ALIGN
+# define ALIGN(n) .p2align n
+#endif
+
+#ifndef cfi_startproc
+# define cfi_startproc .cfi_startproc
+#endif
+
+#ifndef cfi_endproc
+# define cfi_endproc .cfi_endproc
+#endif
+
+#ifndef ENTRY
+# define ENTRY(name) \
+ .type name, @function; \
+ .globl name; \
+ .p2align 4; \
+name: \
+ cfi_startproc
+#endif
+
+#ifndef END
+# define END(name) \
+ cfi_endproc; \
+ .size name, .-name
+#endif
+
+#define JMPTBL(I, B) I - B
+
+/* Branch to an entry in a jump table. TABLE is a jump table with
+ relative offsets. INDEX is a register contains the index into the
+ jump table. SCALE is the scale of INDEX. */
+#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
+ lea TABLE(%rip), %r11; \
+ movslq (%r11, INDEX, SCALE), INDEX; \
+ lea (%r11, INDEX), INDEX; \
+ jmp *INDEX
+
+ .section .text.sse2,"ax",@progbits
+ ALIGN (4)
+ENTRY (android_memset32) // Address in rdi
+ shr $2, %rdx // Count in rdx
+ movl %esi, %ecx // Pattern in ecx
+
+ cmp $16, %rdx
+ jae L(16dbwordsormore)
+
+L(write_less16dbwords):
+ lea (%rdi, %rdx, 4), %rdi
+ BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
+
+ .pushsection .rodata.sse2,"a",@progbits
+ ALIGN (2)
+L(table_less16dbwords):
+ .int JMPTBL (L(write_0dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_1dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_2dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_3dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_4dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_5dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_6dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_7dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_8dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_9dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_10dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_11dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_12dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_13dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_14dbwords), L(table_less16dbwords))
+ .int JMPTBL (L(write_15dbwords), L(table_less16dbwords))
+ .popsection
+
+ ALIGN (4)
+L(write_15dbwords):
+ movl %ecx, -60(%rdi)
+L(write_14dbwords):
+ movl %ecx, -56(%rdi)
+L(write_13dbwords):
+ movl %ecx, -52(%rdi)
+L(write_12dbwords):
+ movl %ecx, -48(%rdi)
+L(write_11dbwords):
+ movl %ecx, -44(%rdi)
+L(write_10dbwords):
+ movl %ecx, -40(%rdi)
+L(write_9dbwords):
+ movl %ecx, -36(%rdi)
+L(write_8dbwords):
+ movl %ecx, -32(%rdi)
+L(write_7dbwords):
+ movl %ecx, -28(%rdi)
+L(write_6dbwords):
+ movl %ecx, -24(%rdi)
+L(write_5dbwords):
+ movl %ecx, -20(%rdi)
+L(write_4dbwords):
+ movl %ecx, -16(%rdi)
+L(write_3dbwords):
+ movl %ecx, -12(%rdi)
+L(write_2dbwords):
+ movl %ecx, -8(%rdi)
+L(write_1dbwords):
+ movl %ecx, -4(%rdi)
+L(write_0dbwords):
+ ret
+
+ ALIGN (4)
+L(16dbwordsormore):
+ test $3, %edi
+ jz L(aligned4bytes)
+ mov %ecx, (%rdi)
+ mov %ecx, -4(%rdi, %rdx, 4)
+ sub $1, %rdx
+ rol $24, %ecx
+ add $1, %rdi
+ test $3, %edi
+ jz L(aligned4bytes)
+ ror $8, %ecx
+ add $1, %rdi
+ test $3, %edi
+ jz L(aligned4bytes)
+ ror $8, %ecx
+ add $1, %rdi
+L(aligned4bytes):
+ shl $2, %rdx
+
+ /* Fill xmm0 with the pattern. */
+ movd %ecx, %xmm0
+ pshufd $0, %xmm0, %xmm0
+
+ testl $0xf, %edi
+ jz L(aligned_16)
+/* RDX > 32 and RDI is not 16 byte aligned. */
+ movdqu %xmm0, (%rdi)
+ mov %rdi, %rsi
+ and $-16, %rdi
+ add $16, %rdi
+ sub %rdi, %rsi
+ add %rsi, %rdx
+
+ ALIGN (4)
+L(aligned_16):
+ cmp $128, %rdx
+ jge L(128bytesormore)
+
+L(aligned_16_less128bytes):
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore):
+ cmp $SHARED_CACHE_SIZE, %rdx
+ jg L(128bytesormore_nt)
+
+L(128bytesormore_normal):
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jl L(128bytesless_normal)
+
+ sub $128, %rdx
+ movdqa %xmm0, (%rdi)
+ movdqa %xmm0, 0x10(%rdi)
+ movdqa %xmm0, 0x20(%rdi)
+ movdqa %xmm0, 0x30(%rdi)
+ movdqa %xmm0, 0x40(%rdi)
+ movdqa %xmm0, 0x50(%rdi)
+ movdqa %xmm0, 0x60(%rdi)
+ movdqa %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_normal)
+
+L(128bytesless_normal):
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ ALIGN (4)
+L(128bytesormore_nt):
+ sub $128, %rdx
+ movntdq %xmm0, (%rdi)
+ movntdq %xmm0, 0x10(%rdi)
+ movntdq %xmm0, 0x20(%rdi)
+ movntdq %xmm0, 0x30(%rdi)
+ movntdq %xmm0, 0x40(%rdi)
+ movntdq %xmm0, 0x50(%rdi)
+ movntdq %xmm0, 0x60(%rdi)
+ movntdq %xmm0, 0x70(%rdi)
+ lea 128(%rdi), %rdi
+ cmp $128, %rdx
+ jge L(128bytesormore_nt)
+
+ sfence
+ add %rdx, %rdi
+ shr $2, %rdx
+ BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
+
+ .pushsection .rodata.sse2,"a",@progbits
+ ALIGN (2)
+L(table_16_128bytes):
+ .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
+ .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
+ .popsection
+
+ ALIGN (4)
+L(aligned_16_112bytes):
+ movdqa %xmm0, -112(%rdi)
+L(aligned_16_96bytes):
+ movdqa %xmm0, -96(%rdi)
+L(aligned_16_80bytes):
+ movdqa %xmm0, -80(%rdi)
+L(aligned_16_64bytes):
+ movdqa %xmm0, -64(%rdi)
+L(aligned_16_48bytes):
+ movdqa %xmm0, -48(%rdi)
+L(aligned_16_32bytes):
+ movdqa %xmm0, -32(%rdi)
+L(aligned_16_16bytes):
+ movdqa %xmm0, -16(%rdi)
+L(aligned_16_0bytes):
+ ret
+
+ ALIGN (4)
+L(aligned_16_116bytes):
+ movdqa %xmm0, -116(%rdi)
+L(aligned_16_100bytes):
+ movdqa %xmm0, -100(%rdi)
+L(aligned_16_84bytes):
+ movdqa %xmm0, -84(%rdi)
+L(aligned_16_68bytes):
+ movdqa %xmm0, -68(%rdi)
+L(aligned_16_52bytes):
+ movdqa %xmm0, -52(%rdi)
+L(aligned_16_36bytes):
+ movdqa %xmm0, -36(%rdi)
+L(aligned_16_20bytes):
+ movdqa %xmm0, -20(%rdi)
+L(aligned_16_4bytes):
+ movl %ecx, -4(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_120bytes):
+ movdqa %xmm0, -120(%rdi)
+L(aligned_16_104bytes):
+ movdqa %xmm0, -104(%rdi)
+L(aligned_16_88bytes):
+ movdqa %xmm0, -88(%rdi)
+L(aligned_16_72bytes):
+ movdqa %xmm0, -72(%rdi)
+L(aligned_16_56bytes):
+ movdqa %xmm0, -56(%rdi)
+L(aligned_16_40bytes):
+ movdqa %xmm0, -40(%rdi)
+L(aligned_16_24bytes):
+ movdqa %xmm0, -24(%rdi)
+L(aligned_16_8bytes):
+ movq %xmm0, -8(%rdi)
+ ret
+
+ ALIGN (4)
+L(aligned_16_124bytes):
+ movdqa %xmm0, -124(%rdi)
+L(aligned_16_108bytes):
+ movdqa %xmm0, -108(%rdi)
+L(aligned_16_92bytes):
+ movdqa %xmm0, -92(%rdi)
+L(aligned_16_76bytes):
+ movdqa %xmm0, -76(%rdi)
+L(aligned_16_60bytes):
+ movdqa %xmm0, -60(%rdi)
+L(aligned_16_44bytes):
+ movdqa %xmm0, -44(%rdi)
+L(aligned_16_28bytes):
+ movdqa %xmm0, -28(%rdi)
+L(aligned_16_12bytes):
+ movq %xmm0, -12(%rdi)
+ movl %ecx, -4(%rdi)
+ ret
+
+END (android_memset32)
diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h
new file mode 100644
index 0000000..ab5dd2f
--- /dev/null
+++ b/libcutils/arch-x86_64/cache.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Contributed by: Intel Corporation
+ */
+
+#if defined(__slm__)
+/* Values are optimized for Silvermont */
+#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */
+#else
+/* Values are optimized for Atom */
+#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */
+#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */
+#endif
+
+#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2)
+#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2)
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index f03e130..4ac4f57 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -19,96 +19,102 @@
* an ashmem-enabled kernel. See ashmem-dev.c for the real ashmem-based version.
*/
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
#include <errno.h>
-#include <time.h>
+#include <fcntl.h>
#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
#include <cutils/ashmem.h>
-int ashmem_create_region(const char *ignored, size_t size)
-{
- static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- char name[64];
- unsigned int retries = 0;
- pid_t pid = getpid();
- int fd;
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
- srand(time(NULL) + pid);
-
-retry:
- /* not beautiful, its just wolf-like loop unrolling */
- snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
- pid,
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
- txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
-
- /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
- fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd == -1) {
- /* unlikely, but if we failed because `name' exists, retry */
- if (errno == EEXIST && ++retries < 6)
- goto retry;
- return -1;
- }
-
- /* truncate the file to `len' bytes */
- if (ftruncate(fd, size) == -1)
- goto error;
-
- if (unlink(name) == -1)
- goto error;
-
- return fd;
-error:
- close(fd);
- return -1;
+static pthread_once_t seed_initialized = PTHREAD_ONCE_INIT;
+static void initialize_random() {
+ srand(time(NULL) + getpid());
}
-int ashmem_set_prot_region(int fd, int prot)
+int ashmem_create_region(const char *ignored __unused, size_t size)
{
- return 0;
+ static const char txt[] = "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char name[64];
+ unsigned int retries = 0;
+ pid_t pid = getpid();
+ int fd;
+ if (pthread_once(&seed_initialized, &initialize_random) != 0) {
+ return -1;
+ }
+ do {
+ /* not beautiful, its just wolf-like loop unrolling */
+ snprintf(name, sizeof(name), "/tmp/android-ashmem-%d-%c%c%c%c%c%c%c%c",
+ pid,
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))],
+ txt[(int) ((sizeof(txt) - 1) * (rand() / (RAND_MAX + 1.0)))]);
+
+ /* open O_EXCL & O_CREAT: we are either the sole owner or we fail */
+ fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
+ if (fd == -1) {
+ /* unlikely, but if we failed because `name' exists, retry */
+ if (errno != EEXIST || ++retries >= 6) {
+ return -1;
+ }
+ }
+ } while (fd == -1);
+ /* truncate the file to `len' bytes */
+ if (ftruncate(fd, size) != -1 && unlink(name) != -1) {
+ return fd;
+ }
+ close(fd);
+ return -1;
}
-int ashmem_pin_region(int fd, size_t offset, size_t len)
+int ashmem_set_prot_region(int fd __unused, int prot __unused)
{
- return ASHMEM_NOT_PURGED;
+ return 0;
}
-int ashmem_unpin_region(int fd, size_t offset, size_t len)
+int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_IS_UNPINNED;
+ return ASHMEM_NOT_PURGED;
+}
+
+int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
+{
+ return ASHMEM_IS_UNPINNED;
}
int ashmem_get_size_region(int fd)
{
- struct stat buf;
- int result;
+ struct stat buf;
+ int result;
- result = fstat(fd, &buf);
- if (result == -1) {
- return -1;
- }
+ result = fstat(fd, &buf);
+ if (result == -1) {
+ return -1;
+ }
- // Check if this is an "ashmem" region.
- // TODO: This is very hacky, and can easily break. We need some reliable indicator.
- if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
- errno = ENOTTY;
- return -1;
- }
+ // Check if this is an "ashmem" region.
+ // TODO: This is very hacky, and can easily break. We need some reliable indicator.
+ if (!(buf.st_nlink == 0 && S_ISREG(buf.st_mode))) {
+ errno = ENOTTY;
+ return -1;
+ }
- return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
+ return (int)buf.st_size; // TODO: care about overflow (> 2GB file)?
}
diff --git a/libcutils/cpu_info.c b/libcutils/cpu_info.c
index 23dda8a..21fa1dc 100644
--- a/libcutils/cpu_info.c
+++ b/libcutils/cpu_info.c
@@ -1,5 +1,4 @@
-/* libs/cutils/cpu_info.c
-**
+/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,11 +14,12 @@
** limitations under the License.
*/
-#include <cutils/cpu_info.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <cutils/cpu_info.h>
+
// we cache the serial number here.
// this is also used as a fgets() line buffer when we are reading /proc/cpuinfo
static char serial_number[100] = { 0 };
@@ -31,7 +31,6 @@
FILE* file;
char* chp, *end;
char* whitespace;
- int length;
// read serial number from /proc/cpuinfo
file = fopen("proc/cpuinfo", "r");
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 7d907fc..056de5d 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <cutils/debugger.h>
@@ -28,9 +29,9 @@
}
debugger_msg_t msg;
+ memset(&msg, 0, sizeof(msg));
msg.tid = tid;
msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
- msg.abort_msg_address = 0;
int result = 0;
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
@@ -62,9 +63,9 @@
}
debugger_msg_t msg;
+ memset(&msg, 0, sizeof(msg));
msg.tid = tid;
msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
- msg.abort_msg_address = 0;
int result = 0;
if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
diff --git a/libcutils/dlmalloc_stubs.c b/libcutils/dlmalloc_stubs.c
index c327a55..2db473d 100644
--- a/libcutils/dlmalloc_stubs.c
+++ b/libcutils/dlmalloc_stubs.c
@@ -14,21 +14,22 @@
* limitations under the License.
*/
-#include "../../../bionic/libc/bionic/dlmalloc.h"
-#include "cutils/log.h"
+#include "log/log.h"
+
+#define UNUSED __attribute__((__unused__))
/*
* Stubs for functions defined in bionic/libc/bionic/dlmalloc.c. These
* are used in host builds, as the host libc will not contain these
* functions.
*/
-void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
- void* arg)
+void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*) UNUSED,
+ void* arg UNUSED)
{
ALOGW("Called host unimplemented stub: dlmalloc_inspect_all");
}
-int dlmalloc_trim(size_t unused)
+int dlmalloc_trim(size_t unused UNUSED)
{
ALOGW("Called host unimplemented stub: dlmalloc_trim");
return 0;
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 5d90a01..a6da9ca 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -1,5 +1,4 @@
/*
-**
** Copyright 2007-2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,50 +14,41 @@
** limitations under the License.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
#include <fcntl.h>
-
-#ifdef HAVE_SCHED_H
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <cutils/iosched_policy.h>
#ifdef HAVE_ANDROID_OS
-/* #include <linux/ioprio.h> */
-extern int ioprio_set(int which, int who, int ioprio);
-extern int ioprio_get(int which, int who);
+#include <linux/ioprio.h>
+#include <sys/syscall.h>
+#define __android_unused
+#else
+#define __android_unused __attribute__((__unused__))
#endif
-enum {
- WHO_PROCESS = 1,
- WHO_PGRP,
- WHO_USER,
-};
-
-#define CLASS_SHIFT 13
-#define IOPRIO_NORM 4
-
-int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio) {
+int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) {
#ifdef HAVE_ANDROID_OS
- if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) {
+ if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) {
return -1;
}
#endif
return 0;
}
-int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio) {
+int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) {
#ifdef HAVE_ANDROID_OS
int rc;
- if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) {
+ if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) {
return -1;
}
- *clazz = (rc >> CLASS_SHIFT);
+ *clazz = (rc >> IOPRIO_CLASS_SHIFT);
*ioprio = (rc & 0xff);
#else
*clazz = IoSchedClass_NONE;
@@ -66,5 +56,3 @@
#endif
return 0;
}
-
-#endif /* HAVE_SCHED_H */
diff --git a/libcutils/partition_utils.c b/libcutils/partition_utils.c
index 10539fa..823b162 100644
--- a/libcutils/partition_utils.c
+++ b/libcutils/partition_utils.c
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-#include <sys/types.h>
-#include <unistd.h>
#include <fcntl.h>
-#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mount.h> /* for BLKGETSIZE */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include <cutils/properties.h>
static int only_one_char(char *buf, int len, char c)
@@ -39,7 +40,7 @@
int partition_wiped(char *source)
{
char buf[4096];
- int fd, ret, wiped;
+ int fd, ret;
if ((fd = open(source, O_RDONLY)) < 0) {
return 0;
diff --git a/libcutils/process_name.c b/libcutils/process_name.c
index a6ab951..9c3dfb8 100644
--- a/libcutils/process_name.c
+++ b/libcutils/process_name.c
@@ -14,25 +14,27 @@
* limitations under the License.
*/
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#if defined(HAVE_PRCTL)
+#include <sys/prctl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include <cutils/process_name.h>
#ifdef HAVE_ANDROID_OS
#include <cutils/properties.h>
#endif
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
#define PROCESS_NAME_DEVICE "/sys/qemu_trace/process_name"
static const char* process_name = "unknown";
+#ifdef HAVE_ANDROID_OS
static int running_in_emulator = -1;
+#endif
void set_process_name(const char* new_name) {
#ifdef HAVE_ANDROID_OS
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -15,17 +15,95 @@
*/
#define LOG_TAG "properties"
+// #define LOG_NDEBUG 0
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <errno.h>
#include <assert.h>
#include <cutils/properties.h>
+#include <stdbool.h>
+#include <inttypes.h>
#include "loghack.h"
+int8_t property_get_bool(const char *key, int8_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ int8_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+
+ int len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n') {
+ result = false;
+ } else if (ch == '1' || ch == 'y') {
+ result = true;
+ }
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+// Convert string property to int (default if fails); return default value if out of bounds
+static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
+ intmax_t default_value) {
+ if (!key) {
+ return default_value;
+ }
+
+ intmax_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char *end = NULL;
+
+ int len = property_get(key, buf, "");
+ if (len > 0) {
+ int tmp = errno;
+ errno = 0;
+
+ // Infer base automatically
+ result = strtoimax(buf, &end, /*base*/0);
+ if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
+ // Over or underflow
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value);
+ } else if (result < lower_bound || result > upper_bound) {
+ // Out of range of requested bounds
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value);
+ } else if (end == buf) {
+ // Numeric conversion failed
+ result = default_value;
+ ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
+ __FUNCTION__, key, default_value);
+ }
+
+ errno = tmp;
+ }
+
+ return result;
+}
+
+int64_t property_get_int64(const char *key, int64_t default_value) {
+ return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value);
+}
+
+int32_t property_get_int32(const char *key, int32_t default_value) {
+ return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value);
+}
+
#ifdef HAVE_LIBC_SYSTEM_PROPERTIES
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
@@ -44,10 +122,13 @@
if(len > 0) {
return len;
}
-
if(default_value) {
len = strlen(default_value);
- memcpy(value, default_value, len + 1);
+ if (len >= PROPERTY_VALUE_MAX) {
+ len = PROPERTY_VALUE_MAX - 1;
+ }
+ memcpy(value, default_value, len);
+ value[len] = '\0';
}
return len;
}
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 899a7b4..00e211c 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -1,5 +1,4 @@
-/* libcutils/qtaguid.c
-**
+/*
** Copyright 2011, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -146,7 +145,7 @@
int qtaguid_deleteTagData(int tag, uid_t uid) {
char lineBuf[CTRL_MAX_INPUT_LEN];
- int fd, cnt = 0, res = 0;
+ int cnt = 0, res = 0;
uint64_t kTag = (uint64_t)tag << 32;
ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid);
@@ -164,8 +163,6 @@
}
int qtaguid_setPacifier(int on) {
- int param_fd;
- int res;
const char *value;
value = on ? "Y" : "N";
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index d20d217..9f092d6 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -1,6 +1,4 @@
-
-/* libs/cutils/sched_policy.c
-**
+/*
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,14 +16,17 @@
#define LOG_TAG "SchedPolicy"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
#include <cutils/sched_policy.h>
-#include <cutils/log.h>
+#include <log/log.h>
+
+#define UNUSED __attribute__((__unused__))
/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
* Call this any place a SchedPolicy is used as an input parameter.
@@ -331,12 +332,12 @@
/* Stubs for non-Android targets. */
-int set_sched_policy(int tid, SchedPolicy policy)
+int set_sched_policy(int tid UNUSED, SchedPolicy policy UNUSED)
{
return 0;
}
-int get_sched_policy(int tid, SchedPolicy *policy)
+int get_sched_policy(int tid UNUSED, SchedPolicy *policy)
{
*policy = SP_SYSTEM_DEFAULT;
return 0;
diff --git a/libcutils/socket_inaddr_any_server.c b/libcutils/socket_inaddr_any_server.c
index 7d5dab4..6c849de 100644
--- a/libcutils/socket_inaddr_any_server.c
+++ b/libcutils/socket_inaddr_any_server.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_inaddr_any_server.c
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +14,11 @@
** limitations under the License.
*/
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
@@ -30,13 +27,14 @@
#include <netinet/in.h>
#endif
+#include <cutils/sockets.h>
+
#define LISTEN_BACKLOG 4
/* open listen() port on any interface */
int socket_inaddr_any_server(int port, int type)
{
struct sockaddr_in addr;
- size_t alen;
int s, n;
memset(&addr, 0, sizeof(addr));
@@ -48,7 +46,7 @@
if(s < 0) return -1;
n = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c
index 5310516..ddcc2da 100644
--- a/libcutils/socket_local_client.c
+++ b/libcutils/socket_local_client.c
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
+
+#include <cutils/sockets.h>
#ifdef HAVE_WINSOCK
@@ -128,7 +128,6 @@
{
struct sockaddr_un addr;
socklen_t alen;
- size_t namelen;
int err;
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
diff --git a/libcutils/socket_loopback_client.c b/libcutils/socket_loopback_client.c
index cb82c5e..9aed7b7 100644
--- a/libcutils/socket_loopback_client.c
+++ b/libcutils/socket_loopback_client.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_loopback_client.c
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +14,11 @@
** limitations under the License.
*/
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
#ifndef HAVE_WINSOCK
#include <sys/socket.h>
@@ -30,6 +27,8 @@
#include <netinet/in.h>
#endif
+#include <cutils/sockets.h>
+
/* Connect to port on the loopback IP interface. type is
* SOCK_STREAM or SOCK_DGRAM.
* return is a file descriptor or -1 on error
@@ -37,7 +36,6 @@
int socket_loopback_client(int port, int type)
{
struct sockaddr_in addr;
- socklen_t alen;
int s;
memset(&addr, 0, sizeof(addr));
diff --git a/libcutils/socket_loopback_server.c b/libcutils/socket_loopback_server.c
index 3208488..71afce7 100644
--- a/libcutils/socket_loopback_server.c
+++ b/libcutils/socket_loopback_server.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_loopback_server.c
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,13 +14,11 @@
** limitations under the License.
*/
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
#define LISTEN_BACKLOG 4
@@ -32,11 +29,12 @@
#include <netinet/in.h>
#endif
+#include <cutils/sockets.h>
+
/* open listen() port on loopback interface */
int socket_loopback_server(int port, int type)
{
struct sockaddr_in addr;
- size_t alen;
int s, n;
memset(&addr, 0, sizeof(addr));
@@ -48,7 +46,7 @@
if(s < 0) return -1;
n = 1;
- setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &n, sizeof(n));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
diff --git a/libcutils/socket_network_client.c b/libcutils/socket_network_client.c
index a64006c..4826033 100644
--- a/libcutils/socket_network_client.c
+++ b/libcutils/socket_network_client.c
@@ -1,5 +1,4 @@
-/* libs/cutils/socket_network_client.c
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,22 +14,20 @@
** limitations under the License.
*/
-#include <cutils/sockets.h>
-
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <stddef.h>
-#ifndef HAVE_WINSOCK
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
-#endif
+#include <cutils/sockets.h>
/* Connect to port on the IP interface. type is
* SOCK_STREAM or SOCK_DGRAM.
@@ -38,28 +35,92 @@
*/
int socket_network_client(const char *host, int port, int type)
{
+ return socket_network_client_timeout(host, port, type, 0);
+}
+
+/* Connect to port on the IP interface. type is SOCK_STREAM or SOCK_DGRAM.
+ * timeout in seconds return is a file descriptor or -1 on error
+ */
+int socket_network_client_timeout(const char *host, int port, int type, int timeout)
+{
struct hostent *hp;
struct sockaddr_in addr;
socklen_t alen;
int s;
+ int flags = 0, error = 0, ret = 0;
+ fd_set rset, wset;
+ socklen_t len = sizeof(error);
+ struct timeval ts;
+
+ ts.tv_sec = timeout;
+ ts.tv_usec = 0;
hp = gethostbyname(host);
- if(hp == 0) return -1;
-
+ if (hp == 0) return -1;
+
memset(&addr, 0, sizeof(addr));
addr.sin_family = hp->h_addrtype;
addr.sin_port = htons(port);
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
s = socket(hp->h_addrtype, type, 0);
- if(s < 0) return -1;
+ if (s < 0) return -1;
- if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if ((flags = fcntl(s, F_GETFL, 0)) < 0) {
+ close(s);
+ return -1;
+ }
+
+ if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
+ close(s);
+ return -1;
+ }
+
+ if ((ret = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) {
+ if (errno != EINPROGRESS) {
+ close(s);
+ return -1;
+ }
+ }
+
+ if (ret == 0)
+ goto done;
+
+ FD_ZERO(&rset);
+ FD_SET(s, &rset);
+ wset = rset;
+
+ if ((ret = select(s + 1, &rset, &wset, NULL, (timeout) ? &ts : NULL)) < 0) {
+ close(s);
+ return -1;
+ }
+ if (ret == 0) { // we had a timeout
+ errno = ETIMEDOUT;
+ close(s);
+ return -1;
+ }
+
+ if (FD_ISSET(s, &rset) || FD_ISSET(s, &wset)) {
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+ close(s);
+ return -1;
+ }
+ } else {
+ close(s);
+ return -1;
+ }
+
+ if (error) { // check if we had a socket error
+ errno = error;
+ close(s);
+ return -1;
+ }
+
+done:
+ if (fcntl(s, F_SETFL, flags) < 0) {
close(s);
return -1;
}
return s;
-
}
-
diff --git a/libcutils/sockets.c b/libcutils/sockets.c
index b5a1b3d..15ede2b 100644
--- a/libcutils/sockets.c
+++ b/libcutils/sockets.c
@@ -14,15 +14,18 @@
* limitations under the License.
*/
-#include <cutils/log.h>
#include <cutils/sockets.h>
+#include <log/log.h>
#ifdef HAVE_ANDROID_OS
/* For the socket trust (credentials) check */
#include <private/android_filesystem_config.h>
+#define __android_unused
+#else
+#define __android_unused __attribute__((__unused__))
#endif
-bool socket_peer_is_trusted(int fd)
+bool socket_peer_is_trusted(int fd __android_unused)
{
#ifdef HAVE_ANDROID_OS
struct ucred cr;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 953b91d..2e3ce9f 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -25,10 +25,9 @@
#include <string.h>
#include <cutils/hashmap.h>
-#include <cutils/log.h>
#include <cutils/memory.h>
-
#include <cutils/str_parms.h>
+#include <log/log.h>
#define UNUSED __attribute__((unused))
@@ -374,8 +373,6 @@
int main(void)
{
- struct str_parms *str_parms;
-
test_str_parms_str("");
test_str_parms_str(";");
test_str_parms_str("=");
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
new file mode 100644
index 0000000..8e65310
--- /dev/null
+++ b/libcutils/tests/Android.mk
@@ -0,0 +1,48 @@
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+test_src_files := \
+ MemsetTest.cpp \
+ PropertiesTest.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ liblog \
+ libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcutils_test_static
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SRC_FILES := $(test_src_files)
+LOCAL_STATIC_LIBRARIES := \
+ libc \
+ libcutils \
+ liblog \
+ libstlport_static \
+ libutils \
+
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+include $(BUILD_NATIVE_TEST)
diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp
new file mode 100644
index 0000000..45efc51
--- /dev/null
+++ b/libcutils/tests/MemsetTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <cutils/memory.h>
+#include <gtest/gtest.h>
+
+#define FENCEPOST_LENGTH 8
+
+#define MAX_TEST_SIZE (64*1024)
+// Choose values that have no repeating byte values.
+#define MEMSET16_PATTERN 0xb139
+#define MEMSET32_PATTERN 0x48193a27
+
+enum test_e {
+ MEMSET16 = 0,
+ MEMSET32,
+};
+
+static int g_memset16_aligns[][2] = {
+ { 2, 0 },
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+
+ { 4, 2 },
+
+ { 8, 2 },
+ { 8, 4 },
+ { 8, 6 },
+
+ { 128, 2 },
+ { 128, 4 },
+ { 128, 6 },
+ { 128, 8 },
+ { 128, 10 },
+ { 128, 12 },
+ { 128, 14 },
+ { 128, 16 },
+};
+
+static int g_memset32_aligns[][2] = {
+ { 4, 0 },
+ { 8, 0 },
+ { 16, 0 },
+ { 32, 0 },
+ { 64, 0 },
+ { 128, 0 },
+
+ { 8, 4 },
+
+ { 128, 4 },
+ { 128, 8 },
+ { 128, 12 },
+ { 128, 16 },
+};
+
+static size_t GetIncrement(size_t len, size_t min_incr) {
+ if (len >= 4096) {
+ return 1024;
+ } else if (len >= 1024) {
+ return 256;
+ }
+ return min_incr;
+}
+
+// Return a pointer into the current buffer with the specified alignment.
+static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
+ uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
+ if (alignment > 0) {
+ // When setting the alignment, set it to exactly the alignment chosen.
+ // The pointer returned will be guaranteed not to be aligned to anything
+ // more than that.
+ ptr += alignment - (ptr & (alignment - 1));
+ ptr |= alignment | or_mask;
+ }
+
+ return reinterpret_cast<void*>(ptr);
+}
+
+static void SetFencepost(uint8_t *buffer) {
+ for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+ buffer[i] = 0xde;
+ buffer[i+1] = 0xad;
+ }
+}
+
+static void VerifyFencepost(uint8_t *buffer) {
+ for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
+ if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
+ uint8_t expected_value;
+ if (buffer[i] == 0xde) {
+ i++;
+ expected_value = 0xad;
+ } else {
+ expected_value = 0xde;
+ }
+ ASSERT_EQ(expected_value, buffer[i]);
+ }
+ }
+}
+
+void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
+ size_t min_incr = 4;
+ if (test_type == MEMSET16) {
+ min_incr = 2;
+ value |= value << 16;
+ }
+ uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)];
+ for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
+ expected_buf[i] = value;
+ }
+
+ // Allocate one large buffer with lots of extra space so that we can
+ // guarantee that all possible alignments will fit.
+ uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE];
+ uint8_t *buf_align;
+ for (size_t i = 0; i < num_aligns; i++) {
+ size_t incr = min_incr;
+ for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
+ incr = GetIncrement(len, min_incr);
+
+ buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
+ buf+FENCEPOST_LENGTH, align[i][0], align[i][1]));
+
+ SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
+ SetFencepost(&buf_align[len]);
+
+ memset(buf_align, 0xff, len);
+ if (test_type == MEMSET16) {
+ android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
+ } else {
+ android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
+ }
+ ASSERT_EQ(0, memcmp(expected_buf, buf_align, len))
+ << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
+
+ VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
+ VerifyFencepost(&buf_align[len]);
+ }
+ }
+ delete expected_buf;
+ delete buf;
+}
+
+TEST(libcutils, android_memset16_non_zero) {
+ RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset16_zero) {
+ RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_non_zero) {
+ RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
+
+TEST(libcutils, android_memset32_zero) {
+ RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
+}
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
new file mode 100644
index 0000000..659821c
--- /dev/null
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Properties_test"
+#include <utils/Log.h>
+#include <gtest/gtest.h>
+
+#include <cutils/properties.h>
+#include <limits.h>
+#include <string>
+#include <sstream>
+#include <iostream>
+
+namespace android {
+
+#define STRINGIFY_INNER(x) #x
+#define STRINGIFY(x) STRINGIFY_INNER(x)
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+#define ASSERT_OK(x) ASSERT_EQ(0, (x))
+#define EXPECT_OK(x) EXPECT_EQ(0, (x))
+
+#define PROPERTY_TEST_KEY "libcutils.test.key"
+#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>"
+
+template <typename T>
+static std::string HexString(T value) {
+ std::stringstream ss;
+ ss << "0x" << std::hex << std::uppercase << value;
+ return ss.str();
+}
+
+template <typename T>
+static ::testing::AssertionResult AssertEqualHex(const char *mExpr,
+ const char *nExpr,
+ T m,
+ T n) {
+ if (m == n) {
+ return ::testing::AssertionSuccess();
+ }
+
+ return ::testing::AssertionFailure()
+ << mExpr << " and " << nExpr << " (expected: " << HexString(m) <<
+ ", actual: " << HexString(n) << ") are not equal";
+}
+
+class PropertiesTest : public testing::Test {
+public:
+ PropertiesTest() : mValue() {}
+protected:
+ virtual void SetUp() {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ }
+
+ virtual void TearDown() {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ }
+
+ char mValue[PROPERTY_VALUE_MAX];
+
+ template <typename T>
+ static std::string ToString(T value) {
+ std::stringstream ss;
+ ss << value;
+
+ return ss.str();
+ }
+
+ // Return length of property read; value is written into mValue
+ int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) {
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'";
+ return property_get(PROPERTY_TEST_KEY, mValue, defaultValue);
+ }
+
+ void ResetValue(unsigned char c = 0xFF) {
+ for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+ mValue[i] = (char) c;
+ }
+ }
+};
+
+TEST_F(PropertiesTest, SetString) {
+
+ // Null key -> unsuccessful set
+ {
+ // Null key -> fails
+ EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT));
+ }
+
+ // Null value -> returns default value
+ {
+ // Null value -> OK , and it clears the value
+ EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL));
+ ResetValue();
+
+ // Since the value is null, default value will be returned
+ int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
+ EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
+ }
+
+ // Trivial case => get returns what was set
+ {
+ int len = SetAndGetProperty("hello_world");
+ EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
+ EXPECT_STREQ("hello_world", mValue);
+ ResetValue();
+ }
+
+ // Set to empty string => get returns default always
+ {
+ const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
+ int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+ EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
+ EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
+ ResetValue();
+ }
+
+ // Set to max length => get returns what was set
+ {
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+
+ int len = SetAndGetProperty(maxLengthString.c_str());
+ EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key";
+ EXPECT_STREQ(maxLengthString.c_str(), mValue);
+ ResetValue();
+ }
+
+ // Set to max length + 1 => set fails
+ {
+ const char* VALID_TEST_VALUE = "VALID_VALUE";
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE));
+
+ std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+ // Expect that the value set fails since it's too long
+ EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
+ int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+
+ EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
+ EXPECT_STREQ(VALID_TEST_VALUE, mValue);
+ ResetValue();
+ }
+}
+
+TEST_F(PropertiesTest, GetString) {
+
+ // Try to use a default value that's too long => set fails
+ {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+ std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+ std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
+
+ // Expect that the value is truncated since it's too long (by 1)
+ int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
+ EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+ EXPECT_STREQ(maxLengthString.c_str(), mValue);
+ ResetValue();
+ }
+}
+
+TEST_F(PropertiesTest, GetBool) {
+ /**
+ * TRUE
+ */
+ const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+ EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
+ }
+
+ /**
+ * FALSE
+ */
+ const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+ EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
+ }
+
+ /**
+ * NEITHER
+ */
+ const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ",
+ "+1", " 1 ", " true", " true ", " y ", " yes", "yes ",
+ "+0", "-0", "00", " 00 ", " false", "false ",
+ };
+ for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
+
+ // The default value should always be used
+ bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
+ EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'";
+
+ val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
+ EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'";
+ }
+}
+
+TEST_F(PropertiesTest, GetInt64) {
+ const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD);
+
+ const std::string longMaxString = ToString(INT64_MAX);
+ const std::string longStringOverflow = longMaxString + "0";
+
+ const std::string longMinString = ToString(INT64_MIN);
+ const std::string longStringUnderflow = longMinString + "0";
+
+ const char* setValues[] = {
+ // base 10
+ "1", "2", "12345", "-1", "-2", "-12345",
+ // base 16
+ "0xFF", "0x0FF", "0xC0FFEE",
+ // base 8
+ "0", "01234", "07",
+ // corner cases
+ " 2", "2 ", "+0", "-0", " +0 ", longMaxString.c_str(), longMinString.c_str(),
+ // failing cases
+ NULL, "", " ", " ", "hello", " true ", "y",
+ longStringOverflow.c_str(), longStringUnderflow.c_str(),
+ };
+
+ int64_t getValues[] = {
+ // base 10
+ 1, 2, 12345, -1, -2, -12345,
+ // base 16
+ 0xFF, 0x0FF, 0xC0FFEE,
+ // base 8
+ 0, 01234, 07,
+ // corner cases
+ 2, 2, 0, 0, 0, INT64_MAX, INT64_MIN,
+ // failing cases
+ DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+ DEFAULT_VALUE, DEFAULT_VALUE,
+ };
+
+ ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+ for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+ int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+ EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+ }
+}
+
+TEST_F(PropertiesTest, GetInt32) {
+ const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF);
+
+ const std::string intMaxString = ToString(INT32_MAX);
+ const std::string intStringOverflow = intMaxString + "0";
+
+ const std::string intMinString = ToString(INT32_MIN);
+ const std::string intStringUnderflow = intMinString + "0";
+
+ const char* setValues[] = {
+ // base 10
+ "1", "2", "12345", "-1", "-2", "-12345",
+ // base 16
+ "0xFF", "0x0FF", "0xC0FFEE", "0Xf00",
+ // base 8
+ "0", "01234", "07",
+ // corner cases
+ " 2", "2 ", "+0", "-0", " +0 ", intMaxString.c_str(), intMinString.c_str(),
+ // failing cases
+ NULL, "", " ", " ", "hello", " true ", "y",
+ intStringOverflow.c_str(), intStringUnderflow.c_str(),
+ };
+
+ int32_t getValues[] = {
+ // base 10
+ 1, 2, 12345, -1, -2, -12345,
+ // base 16
+ 0xFF, 0x0FF, 0xC0FFEE, 0Xf00,
+ // base 8
+ 0, 01234, 07,
+ // corner cases
+ 2, 2, 0, 0, 0, INT32_MAX, INT32_MIN,
+ // failing cases
+ DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE,
+ DEFAULT_VALUE, DEFAULT_VALUE,
+ };
+
+ ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+
+ for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
+
+ int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
+ EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'";
+ }
+}
+
+} // namespace android
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 42cc928..bf182f0 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -1,5 +1,4 @@
-/* libs/cutils/threads.c
-**
+/*
** Copyright (C) 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +13,12 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+
#include <cutils/threads.h>
#ifdef HAVE_PTHREADS
void* thread_store_get( thread_store_t* store )
{
- const pthread_key_t k = store->tls;
-
if (!store->has_tls)
return NULL;
diff --git a/libcutils/trace.c b/libcutils/trace.c
index 9754a44..f57aac2 100644
--- a/libcutils/trace.c
+++ b/libcutils/trace.c
@@ -28,7 +28,7 @@
#include <cutils/trace.h>
#define LOG_TAG "cutils-trace"
-#include <cutils/log.h>
+#include <log/log.h>
volatile int32_t atrace_is_ready = 0;
int atrace_marker_fd = -1;
@@ -86,7 +86,6 @@
static bool atrace_is_app_tracing_enabled()
{
bool sys_debuggable = false;
- bool proc_debuggable = false;
char value[PROPERTY_VALUE_MAX];
bool result = false;
diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
index b5d83fa..624e385 100644
--- a/libdiskconfig/Android.mk
+++ b/libdiskconfig/Android.mk
@@ -12,6 +12,7 @@
LOCAL_MODULE := libdiskconfig
LOCAL_MODULE_TAGS := optional
LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
ifeq ($(HOST_OS),linux)
diff --git a/libdiskconfig/diskutils.c b/libdiskconfig/diskutils.c
index 7659632..5d0ee62 100644
--- a/libdiskconfig/diskutils.c
+++ b/libdiskconfig/diskutils.c
@@ -41,7 +41,7 @@
int done = 0;
uint64_t total = 0;
- ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, offset);
+ ALOGI("Writing RAW image '%s' to '%s' (offset=%llu)", src, dst, (unsigned long long)offset);
if ((src_fd = open(src, O_RDONLY)) < 0) {
ALOGE("Could not open %s for reading (errno=%d).", src, errno);
goto fail;
@@ -54,7 +54,7 @@
}
if (lseek64(dst_fd, offset, SEEK_SET) != offset) {
- ALOGE("Could not seek to offset %lld in %s.", offset, dst);
+ ALOGE("Could not seek to offset %lld in %s.", (long long)offset, dst);
goto fail;
}
}
@@ -102,7 +102,7 @@
if (dst_fd >= 0)
fsync(dst_fd);
- ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, offset);
+ ALOGI("Wrote %" PRIu64 " bytes to %s @ %lld", total, dst, (long long)offset);
close(src_fd);
if (dst_fd >= 0)
diff --git a/libdiskconfig/write_lst.c b/libdiskconfig/write_lst.c
index 826ef7a..90b1c82 100644
--- a/libdiskconfig/write_lst.c
+++ b/libdiskconfig/write_lst.c
@@ -71,18 +71,18 @@
{
for(; lst; lst = lst->next) {
if (lseek64(fd, lst->offset, SEEK_SET) != (loff_t)lst->offset) {
- ALOGE("Cannot seek to the specified position (%lld).", lst->offset);
+ ALOGE("Cannot seek to the specified position (%lld).", (long long)lst->offset);
goto fail;
}
if (!test) {
if (write(fd, lst->data, lst->len) != (int)lst->len) {
ALOGE("Failed writing %u bytes at position %lld.", lst->len,
- lst->offset);
+ (long long)lst->offset);
goto fail;
}
} else
- ALOGI("Would write %d bytes @ offset %lld.", lst->len, lst->offset);
+ ALOGI("Would write %d bytes @ offset %lld.", lst->len, (long long)lst->offset);
}
return 0;
diff --git a/libion/Android.mk b/libion/Android.mk
index e5d495b..6562cd3 100644
--- a/libion/Android.mk
+++ b/libion/Android.mk
@@ -1,4 +1,4 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := ion.c
@@ -7,6 +7,7 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
@@ -15,6 +16,7 @@
LOCAL_MODULE_TAGS := optional tests
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 5e01903..a7eead9 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -57,11 +57,8 @@
# ========================================================
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_LDLIBS := -lpthread
-ifeq ($(strip $(HOST_OS)),linux)
-LOCAL_LDLIBS += -lrt
-endif
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -70,6 +67,7 @@
ifeq ($(strip $(HOST_OS)),linux)
LOCAL_LDLIBS := -lrt
endif
+LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -78,11 +76,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := lib64log
LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_LDLIBS := -lpthread
-ifeq ($(strip $(HOST_OS)),linux)
-LOCAL_LDLIBS += -lrt
-endif
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64
+LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64 -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
# Shared and static library for target
@@ -90,13 +84,13 @@
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := $(liblog_cflags)
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := $(liblog_cflags)
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index f3d1e2f..bea99aa 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <log/event_tag_map.h>
-#include <log/log.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
-#include <fcntl.h>
#include <sys/mman.h>
-#include <errno.h>
-#include <assert.h>
+
+#include <log/event_tag_map.h>
+#include <log/log.h>
#define OUT_TAG "EventTagMap"
@@ -52,7 +53,6 @@
static int parseMapLines(EventTagMap* map);
static int scanTagLine(char** pData, EventTag* tag, int lineNum);
static int sortTags(EventTagMap* map);
-static void dumpTags(const EventTagMap* map);
/*
@@ -185,8 +185,6 @@
*/
static int processFile(EventTagMap* map)
{
- EventTag* tagArray = NULL;
-
/* get a tag count */
map->numTags = countMapLines(map);
if (map->numTags < 0)
@@ -422,17 +420,3 @@
return 0;
}
-
-/*
- * Dump the tag array for debugging.
- */
-static void dumpTags(const EventTagMap* map)
-{
- int i;
-
- for (i = 0; i < map->numTags; i++) {
- const EventTag* tag = &map->tagArray[i];
- printf(" %3d: %6d '%s'\n", i, tag->tagIndex, tag->tagStr);
- }
-}
-
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index da83a85..136792d 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -21,18 +21,22 @@
*/
#include "fake_log_device.h"
-#include <log/logd.h>
-
-#include <stdlib.h>
-#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/logd.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
#define kTagSetSize 16 /* arbitrary */
@@ -613,7 +617,7 @@
/*
* Open a log output device and return a fake fd.
*/
-static int logOpen(const char* pathName, int flags)
+static int logOpen(const char* pathName, int flags __unused)
{
LogState *logState;
int fd = -1;
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 11fe848..ca5a1a7 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -23,6 +23,7 @@
#define NOMINMAX /* for windows to suppress definition of min in stdlib.h */
#include <stdlib.h>
#include <string.h>
+#include <sys/cdefs.h>
#include <unistd.h>
#include <cutils/list.h>
@@ -34,7 +35,9 @@
#define min(x,y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))
#define WEAK __attribute__((weak))
-#define UNUSED __attribute__((unused))
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
/* Private copy of ../libcutils/socket_local_client.c prevent library loops */
@@ -142,11 +145,10 @@
* Used by AndroidSocketImpl
*/
int WEAK socket_local_client_connect(int fd, const char *name, int namespaceId,
- int type UNUSED)
+ int type __unused)
{
struct sockaddr_un addr;
socklen_t alen;
- size_t namelen;
int err;
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
@@ -409,7 +411,7 @@
/*
* returns the logger version
*/
-int android_logger_get_log_version(struct logger *logger UNUSED)
+int android_logger_get_log_version(struct logger *logger __unused)
{
return 3;
}
@@ -420,7 +422,6 @@
ssize_t android_logger_get_statistics(struct logger_list *logger_list,
char *buf, size_t len)
{
- struct listnode *node;
struct logger *logger;
char *cp = buf;
size_t remaining = len;
@@ -440,13 +441,13 @@
return send_log_msg(NULL, NULL, buf, len);
}
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
char *buf, size_t len)
{
return send_log_msg(NULL, "getPruneList", buf, len);
}
-int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
+int android_logger_set_prune_list(struct logger_list *logger_list __unused,
char *buf, size_t len)
{
const char cmd[] = "setPruneList ";
@@ -512,9 +513,7 @@
struct logger *android_logger_open(struct logger_list *logger_list,
log_id_t id)
{
- struct listnode *node;
struct logger *logger;
- char *n;
if (!logger_list || (id >= LOG_ID_MAX)) {
goto err;
@@ -561,7 +560,7 @@
return logger_list;
}
-static void caught_signal(int signum UNUSED)
+static void caught_signal(int signum __unused)
{
}
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index 021fe47..41b8a51 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -21,12 +21,13 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
#include <cutils/list.h>
#include <log/log.h>
#include <log/logger.h>
-#include <sys/ioctl.h>
-
#define __LOGGERIO 0xAE
#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
@@ -51,7 +52,9 @@
logger != node_to_item(&(logger_list)->node, struct logger, node); \
logger = node_to_item((logger)->node.next, struct logger, node))
-#define UNUSED __attribute__((unused))
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
/* In the future, we would like to make this list extensible */
static const char *LOG_NAME[LOG_ID_MAX] = {
@@ -233,8 +236,8 @@
return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
}
-int android_logger_set_log_size(struct logger *logger UNUSED,
- unsigned long size UNUSED)
+int android_logger_set_log_size(struct logger *logger __unused,
+ unsigned long size __unused)
{
return -ENOTSUP;
}
@@ -262,21 +265,21 @@
*/
static const char unsupported[] = "18\nNot Supported\n\f";
-ssize_t android_logger_get_statistics(struct logger_list *logger_list UNUSED,
+ssize_t android_logger_get_statistics(struct logger_list *logger_list __unused,
char *buf, size_t len)
{
strncpy(buf, unsupported, len);
return -ENOTSUP;
}
-ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
+ssize_t android_logger_get_prune_list(struct logger_list *logger_list __unused,
char *buf, size_t len)
{
strncpy(buf, unsupported, len);
return -ENOTSUP;
}
-int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
+int android_logger_set_prune_list(struct logger_list *logger_list __unused,
char *buf, size_t len)
{
static const char unsupported_error[] = "Unsupported";
@@ -302,7 +305,7 @@
}
struct logger_list *android_logger_list_alloc_time(int mode,
- log_time start UNUSED,
+ log_time start __unused,
pid_t pid)
{
return android_logger_list_alloc(mode, 0, pid);
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 94722d3..3171c78 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -49,12 +49,15 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
-#define UNUSED __attribute__((__unused__))
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
-static int logd_fd = -1;
#if FAKE_LOG_DEVICE
#define WEAK __attribute__((weak))
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+#else
+static int logd_fd = -1;
#endif
/*
@@ -77,12 +80,14 @@
return (g_log_status == kLogAvailable);
}
+#if !FAKE_LOG_DEVICE
/* give up, resources too limited */
-static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED,
- size_t nr UNUSED)
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+ size_t nr __unused)
{
return -1;
}
+#endif
/* log_init_lock assumed */
static int __write_to_log_initialize()
@@ -102,7 +107,7 @@
close(i);
}
- i = socket(PF_UNIX, SOCK_DGRAM, 0);
+ i = socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (i < 0) {
ret = -errno;
write_to_log = __write_to_log_null;
@@ -146,12 +151,22 @@
ret = -errno;
}
} while (ret == -EINTR);
-
- return ret;
#else
- if (getuid() == AID_LOGD) {
+ static const unsigned header_length = 3;
+ struct iovec newVec[nr + header_length];
+ typeof_log_id_t log_id_buf;
+ uint16_t tid;
+ struct timespec ts;
+ log_time realtime_ts;
+ size_t i, payload_size;
+ static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
+
+ if (last_uid == AID_ROOT) { /* have we called to get the UID yet? */
+ last_uid = getuid();
+ }
+ if (last_uid == AID_LOGD) { /* logd, after initialization and priv drop */
/*
- * ignore log messages we send to ourself.
+ * ignore log messages we send to ourself (logd).
* Such log messages are often generated by libraries we depend on
* which use standard Android logging.
*/
@@ -181,29 +196,32 @@
* };
* };
*/
- static const unsigned header_length = 3;
- struct iovec newVec[nr + header_length];
- typeof_log_id_t log_id_buf = log_id;
- uint16_t tid = gettid();
+
+ clock_gettime(CLOCK_REALTIME, &ts);
+ realtime_ts.tv_sec = ts.tv_sec;
+ realtime_ts.tv_nsec = ts.tv_nsec;
+
+ log_id_buf = log_id;
+ tid = gettid();
newVec[0].iov_base = (unsigned char *) &log_id_buf;
newVec[0].iov_len = sizeof_log_id_t;
newVec[1].iov_base = (unsigned char *) &tid;
newVec[1].iov_len = sizeof(tid);
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- log_time realtime_ts;
- realtime_ts.tv_sec = ts.tv_sec;
- realtime_ts.tv_nsec = ts.tv_nsec;
-
newVec[2].iov_base = (unsigned char *) &realtime_ts;
newVec[2].iov_len = sizeof(log_time);
- size_t i;
- for (i = header_length; i < nr + header_length; i++) {
- newVec[i].iov_base = vec[i-header_length].iov_base;
- newVec[i].iov_len = vec[i-header_length].iov_len;
+ for (payload_size = 0, i = header_length; i < nr + header_length; i++) {
+ newVec[i].iov_base = vec[i - header_length].iov_base;
+ payload_size += newVec[i].iov_len = vec[i - header_length].iov_len;
+
+ if (payload_size > LOGGER_ENTRY_MAX_PAYLOAD) {
+ newVec[i].iov_len -= payload_size - LOGGER_ENTRY_MAX_PAYLOAD;
+ if (newVec[i].iov_len) {
+ ++i;
+ }
+ break;
+ }
}
/*
@@ -212,7 +230,7 @@
* ENOTCONN occurs if logd dies.
* EAGAIN occurs if logd is overloaded.
*/
- ret = writev(logd_fd, newVec, nr + header_length);
+ ret = writev(logd_fd, newVec, i);
if (ret < 0) {
ret = -errno;
if (ret == -ENOTCONN) {
@@ -234,8 +252,13 @@
}
}
}
- return ret;
+
+ if (ret > (ssize_t)(sizeof_log_id_t + sizeof(tid) + sizeof(log_time))) {
+ ret -= sizeof_log_id_t + sizeof(tid) + sizeof(log_time);
+ }
#endif
+
+ return ret;
}
#if FAKE_LOG_DEVICE
@@ -308,6 +331,13 @@
tag = tmp_tag;
}
+#if __BIONIC__
+ if (prio == ANDROID_LOG_FATAL) {
+ extern void __android_set_abort_message(const char*);
+ __android_set_abort_message(msg);
+ }
+#endif
+
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
@@ -408,8 +438,8 @@
}
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
-
__builtin_trap(); /* trap so we have a chance to debug the situation */
+ /* NOTREACHED */
}
int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
@@ -443,3 +473,25 @@
return write_to_log(LOG_ID_EVENTS, vec, 3);
}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index c29c28f..1ed5ecf 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -57,7 +57,9 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
-#define UNUSED __attribute__((__unused__))
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
@@ -81,8 +83,8 @@
return (g_log_status == kLogAvailable);
}
-static int __write_to_log_null(log_id_t log_fd UNUSED, struct iovec *vec UNUSED,
- size_t nr UNUSED)
+static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused,
+ size_t nr __unused)
{
return -1;
}
@@ -173,6 +175,13 @@
tag = tmp_tag;
}
+#if __BIONIC__
+ if (prio == ANDROID_LOG_FATAL) {
+ extern void __android_set_abort_message(const char*);
+ __android_set_abort_message(msg);
+ }
+#endif
+
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
@@ -273,8 +282,8 @@
}
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
-
__builtin_trap(); /* trap so we have a chance to debug the situation */
+ /* NOTREACHED */
}
int __android_log_bwrite(int32_t tag, const void *payload, size_t len)
@@ -308,3 +317,25 @@
return write_to_log(LOG_ID_EVENTS, vec, 3);
}
+
+/*
+ * Like __android_log_bwrite, but used for writing strings to the
+ * event log.
+ */
+int __android_log_bswrite(int32_t tag, const char *payload)
+{
+ struct iovec vec[4];
+ char type = EVENT_TYPE_STRING;
+ uint32_t len = strlen(payload);
+
+ vec[0].iov_base = &tag;
+ vec[0].iov_len = sizeof(tag);
+ vec[1].iov_base = &type;
+ vec[1].iov_len = sizeof(type);
+ vec[2].iov_base = &len;
+ vec[2].iov_len = sizeof(len);
+ vec[3].iov_base = (void*)payload;
+ vec[3].iov_len = len;
+
+ return write_to_log(LOG_ID_EVENTS, vec, 4);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index a7480d5..08e830a 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -17,14 +17,14 @@
#define _GNU_SOURCE /* for asprintf */
-#include <ctype.h>
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <assert.h>
#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <log/logd.h>
#include <log/logprint.h>
@@ -52,15 +52,7 @@
return p_ret;
}
-static void filterinfo_free(FilterInfo *p_info)
-{
- if (p_info == NULL) {
- return;
- }
-
- free(p_info->mTag);
- p_info->mTag = NULL;
-}
+/* balance to above, filterinfo_free left unimplemented */
/*
* Note: also accepts 0-9 priorities
@@ -139,23 +131,6 @@
return p_format->global_pri;
}
-/** for debugging */
-static void dumpFilters(AndroidLogFormat *p_format)
-{
- FilterInfo *p_fi;
-
- for (p_fi = p_format->filters ; p_fi != NULL ; p_fi = p_fi->p_next) {
- char cPri = filterPriToChar(p_fi->mPri);
- if (p_fi->mPri == ANDROID_LOG_DEFAULT) {
- cPri = filterPriToChar(p_format->global_pri);
- }
- fprintf(stderr,"%s:%c\n", p_fi->mTag, cPri);
- }
-
- fprintf(stderr,"*:%c\n", filterPriToChar(p_format->global_pri));
-
-}
-
/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
@@ -234,7 +209,6 @@
int android_log_addFilterRule(AndroidLogFormat *p_format,
const char *filterExpression)
{
- size_t i=0;
size_t tagNameLength;
android_LogPriority pri = ANDROID_LOG_DEFAULT;
@@ -718,7 +692,6 @@
#endif
struct tm* ptm;
char timeBuf[32];
- char headerBuf[128];
char prefixBuf[128], suffixBuf[128];
char priChar;
int prefixSuffixIsHeaderFooter = 0;
@@ -817,7 +790,6 @@
/* the following code is tragically unreadable */
size_t numLines;
- size_t i;
char *p;
size_t bufferSize;
const char *pm;
@@ -938,88 +910,3 @@
return ret;
}
-
-
-
-void logprint_run_tests()
-{
-#if 0
-
- fprintf(stderr, "tests disabled\n");
-
-#else
-
- int err;
- const char *tag;
- AndroidLogFormat *p_format;
-
- p_format = android_log_format_new();
-
- fprintf(stderr, "running tests\n");
-
- tag = "random";
-
- android_log_addFilterRule(p_format,"*:i");
-
- assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
- android_log_addFilterRule(p_format, "*");
- assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:v");
- assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:i");
- assert (ANDROID_LOG_INFO == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
- android_log_addFilterRule(p_format, "random");
- assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:v");
- assert (ANDROID_LOG_VERBOSE == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:d");
- assert (ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:w");
- assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
- android_log_addFilterRule(p_format, "crap:*");
- assert (ANDROID_LOG_VERBOSE== filterPriForTag(p_format, "crap"));
- assert(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
-
- // invalid expression
- err = android_log_addFilterRule(p_format, "random:z");
- assert (err < 0);
- assert (ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
- assert(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
-
- // Issue #550946
- err = android_log_addFilterString(p_format, " ");
- assert(err == 0);
- assert(ANDROID_LOG_WARN == filterPriForTag(p_format, "random"));
-
- // note trailing space
- err = android_log_addFilterString(p_format, "*:s random:d ");
- assert(err == 0);
- assert(ANDROID_LOG_DEBUG == filterPriForTag(p_format, "random"));
-
- err = android_log_addFilterString(p_format, "*:s random:z");
- assert(err < 0);
-
-
-#if 0
- char *ret;
- char defaultBuffer[512];
-
- ret = android_log_formatLogLine(p_format,
- defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
- 123, 123, "random", "nofile", strlen("Hello"), "Hello", NULL);
-#endif
-
-
- fprintf(stderr, "tests complete\n");
-#endif
-}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index db06cf7..255dc2e 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -32,7 +32,7 @@
benchmark_src_files := \
benchmark_main.cpp \
- liblog_benchmark.cpp \
+ liblog_benchmark.cpp
# Build benchmarks for the device. Run with:
# adb shell liblog-benchmarks
@@ -59,10 +59,22 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin \
+ -fno-builtin
test_src_files := \
- liblog_test.cpp \
+ liblog_test.cpp
+
+# to prevent breaking the build if bionic not relatively visible to us
+ifneq ($(wildcard $(LOCAL_PATH)/../../../../bionic/libc/bionic/libc_logging.cpp),)
+
+test_src_files += \
+ libc_test.cpp
+
+ifndef ($(TARGET_USES_LOGD),false)
+test_c_flags += -DTARGET_USES_LOGD
+endif
+
+endif
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
@@ -71,7 +83,6 @@
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_LDLIBS := -lpthread
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
new file mode 100644
index 0000000..9839729
--- /dev/null
+++ b/liblog/tests/libc_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <sys/cdefs.h>
+
+#include <gtest/gtest.h>
+
+// Should be in bionic test suite, *but* we are using liblog to confirm
+// end-to-end logging, so let the overly cute oedipus complex begin ...
+#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
+#define _ANDROID_LOG_H // Priorities redefined
+#define _LIBS_LOG_LOG_H // log ids redefined
+typedef unsigned char log_id_t; // log_id_t missing as a result
+#ifdef TARGET_USES_LOGD
+#define _LIBS_LOG_LOG_READ_H // log_time redefined
+#endif
+
+#include <log/log.h>
+#include <log/logger.h>
+#include <log/log_read.h>
+
+TEST(libc, __libc_android_log_event_int) {
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
+
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ int value = ts.tv_nsec;
+
+ __libc_android_log_event_int(0, value);
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.len != (4 + 1 + 4))
+ || ((int)log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
+
+ char *eventData = log_msg.msg();
+
+ int incoming = (eventData[0] & 0xFF) |
+ ((eventData[1] & 0xFF) << 8) |
+ ((eventData[2] & 0xFF) << 16) |
+ ((eventData[3] & 0xFF) << 24);
+
+ if (incoming != 0) {
+ continue;
+ }
+
+ if (eventData[4] != EVENT_TYPE_INT) {
+ continue;
+ }
+
+ incoming = (eventData[4 + 1 + 0] & 0xFF) |
+ ((eventData[4 + 1 + 1] & 0xFF) << 8) |
+ ((eventData[4 + 1 + 2] & 0xFF) << 16) |
+ ((eventData[4 + 1 + 3] & 0xFF) << 24);
+
+ if (incoming == value) {
+ ++count;
+ }
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(libc, __libc_fatal_no_abort) {
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ (log_id_t)LOG_ID_CRASH, O_RDONLY | O_NDELAY, 1000, pid)));
+
+ char b[80];
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+ snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((int)log_msg.id() != LOG_ID_CRASH) {
+ continue;
+ }
+
+ char *data = log_msg.msg();
+
+ if ((*data == ANDROID_LOG_FATAL)
+ && !strcmp(data + 1, "libc")
+ && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
+ ++count;
+ }
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 39fe2ad..549d79e 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -99,7 +99,7 @@
}
BENCHMARK(BM_log_overhead);
-static void caught_latency(int signum)
+static void caught_latency(int /*signum*/)
{
unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
@@ -193,7 +193,7 @@
}
BENCHMARK(BM_log_latency);
-static void caught_delay(int signum)
+static void caught_delay(int /*signum*/)
{
unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 24ae738..393e2cd 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -21,6 +21,7 @@
#include <log/log.h>
#include <log/logger.h>
#include <log/log_read.h>
+#include <log/logprint.h>
// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
// non-syscall libs. Since we are only using this in the emergency of
@@ -163,7 +164,7 @@
static unsigned signaled;
log_time signal_time;
-static void caught_blocking(int signum)
+static void caught_blocking(int /*signum*/)
{
unsigned long long v = 0xDEADBEEFA55A0000ULL;
@@ -482,11 +483,68 @@
}
}
+ android_logger_list_close(logger_list);
+
EXPECT_EQ(true, matches);
EXPECT_LE(sizeof(max_payload_buf), static_cast<size_t>(max_len));
+}
+
+TEST(liblog, too_big_payload) {
+ pid_t pid = getpid();
+ static const char big_payload_tag[] = "TEST_big_payload_XXXX";
+ char tag[sizeof(big_payload_tag)];
+ memcpy(tag, big_payload_tag, sizeof(tag));
+ snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
+
+ std::string longString(3266519, 'x');
+
+ ssize_t ret = LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM,
+ ANDROID_LOG_INFO, tag, longString.c_str()));
+
+ struct logger_list *logger_list;
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_SYSTEM, O_RDONLY | O_NDELAY, 100, 0)));
+
+ ssize_t max_len = 0;
+
+ for(;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ if ((log_msg.entry.pid != pid) || (log_msg.id() != LOG_ID_SYSTEM)) {
+ continue;
+ }
+
+ char *data = log_msg.msg() + 1;
+
+ if (strcmp(data, tag)) {
+ continue;
+ }
+
+ data += strlen(data) + 1;
+
+ const char *left = data;
+ const char *right = longString.c_str();
+ while (*left && *right && (*left == *right)) {
+ ++left;
+ ++right;
+ }
+
+ if (max_len <= (left - data)) {
+ max_len = left - data + 1;
+ }
+ }
android_logger_list_close(logger_list);
+
+ EXPECT_LE(LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag),
+ static_cast<size_t>(max_len));
+
+ EXPECT_EQ(ret, max_len + static_cast<ssize_t>(sizeof(big_payload_tag)));
}
TEST(liblog, dual_reader) {
@@ -555,3 +613,72 @@
android_logger_list_close(logger_list);
}
+
+static bool checkPriForTag(AndroidLogFormat *p_format, const char *tag, android_LogPriority pri) {
+ return android_log_shouldPrintLine(p_format, tag, pri)
+ && !android_log_shouldPrintLine(p_format, tag, (android_LogPriority)(pri - 1));
+}
+
+TEST(liblog, filterRule) {
+ static const char tag[] = "random";
+
+ AndroidLogFormat *p_format = android_log_format_new();
+
+ android_log_addFilterRule(p_format,"*:i");
+
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+ android_log_addFilterRule(p_format, "*");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "*:v");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "*:i");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+ android_log_addFilterRule(p_format, tag);
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:v");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:d");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
+ android_log_addFilterRule(p_format, "random:w");
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+ android_log_addFilterRule(p_format, "crap:*");
+ EXPECT_TRUE (checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
+
+ // invalid expression
+ EXPECT_TRUE (android_log_addFilterRule(p_format, "random:z") < 0);
+ EXPECT_TRUE (checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+ EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) == 0);
+
+ // Issue #550946
+ EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
+
+ // note trailing space
+ EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
+ EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
+
+ EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
+
+#if 0 // bitrot, seek update
+ char defaultBuffer[512];
+
+ android_log_formatLogLine(p_format,
+ defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
+ 123, 123, tag, "nofile", strlen("Hello"), "Hello", NULL);
+
+ fprintf(stderr, "%s\n", defaultBuffer);
+#endif
+
+ android_log_format_free(p_format);
+}
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
index 8df6cf7..101314b 100644
--- a/libmincrypt/dsa_sig.c
+++ b/libmincrypt/dsa_sig.c
@@ -26,6 +26,7 @@
#include <string.h>
+#include "mincrypt/dsa_sig.h"
#include "mincrypt/p256.h"
/**
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
index 1608d37..555a07a 100644
--- a/libmincrypt/p256.c
+++ b/libmincrypt/p256.c
@@ -49,8 +49,6 @@
{{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
-static const p256_int p256_one = P256_ONE;
-
void p256_init(p256_int* a) {
memset(a, 0, sizeof(*a));
}
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
index b5a7b3a..24ec013 100644
--- a/libmincrypt/test/ecdsa_test.c
+++ b/libmincrypt/test/ecdsa_test.c
@@ -24,15 +24,21 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdio.h>
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/cdefs.h>
+#include "mincrypt/dsa_sig.h"
#include "mincrypt/p256.h"
#include "mincrypt/p256_ecdsa.h"
#include "mincrypt/sha256.h"
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
+
/**
* Messages signed using:
*
@@ -209,7 +215,7 @@
return result;
}
-int main(int arg, char** argv) {
+int main(int arg __unused, char** argv __unused) {
unsigned char hash_buf[SHA256_DIGEST_SIZE];
diff --git a/libmincrypt/test/rsa_test.c b/libmincrypt/test/rsa_test.c
index 17862dc..055138f 100644
--- a/libmincrypt/test/rsa_test.c
+++ b/libmincrypt/test/rsa_test.c
@@ -1,5 +1,4 @@
-/* rsa_test.c
-**
+/*
** Copyright 2013, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
@@ -25,14 +24,19 @@
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdio.h>
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/cdefs.h>
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+
// RSA test data taken from:
//
// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
@@ -791,7 +795,7 @@
}
-int main(int arg, char** argv) {
+int main(int arg __unused, char** argv __unused) {
unsigned char hash[SHA_DIGEST_SIZE];
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index aba4621..1f61511 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -1,7 +1,7 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= \
+LOCAL_SRC_FILES := \
dhcpclient.c \
dhcpmsg.c \
dhcp_utils.c \
@@ -12,6 +12,8 @@
libcutils \
liblog
-LOCAL_MODULE:= libnetutils
+LOCAL_MODULE := libnetutils
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
diff --git a/libnetutils/dhcpclient.c b/libnetutils/dhcpclient.c
index 34500e7..b58120e 100644
--- a/libnetutils/dhcpclient.c
+++ b/libnetutils/dhcpclient.c
@@ -282,16 +282,18 @@
ALOGD("chaddr = {%s}", buf);
for (n = 0; n < 64; n++) {
- if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
- if (msg->sname[n] == 0) break;
+ unsigned char x = msg->sname[n];
+ if ((x < ' ') || (x > 127)) {
+ if (x == 0) break;
msg->sname[n] = '.';
}
}
msg->sname[63] = 0;
for (n = 0; n < 128; n++) {
- if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
- if (msg->file[n] == 0) break;
+ unsigned char x = msg->file[n];
+ if ((x < ' ') || (x > 127)) {
+ if (x == 0) break;
msg->file[n] = '.';
}
}
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 7446da2..cfd2b37 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -89,7 +89,7 @@
gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE, fd, 0);
- LOG_ALWAYS_FATAL_IF(gExecutableStore == NULL,
+ LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
"Creating code cache, mmap failed with error "
"'%s'", strerror(errno));
close(fd);
@@ -201,9 +201,9 @@
mCacheInUse += assemblySize;
mWhen++;
// synchronize caches...
- const long base = long(assembly->base());
- const long curr = base + long(assembly->size());
- __builtin___clear_cache((void*)base, (void*)curr);
+ void* base = assembly->base();
+ void* curr = (uint8_t*)base + assembly->size();
+ __builtin___clear_cache(base, curr);
}
pthread_mutex_unlock(&mLock);
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index f84a28a..26b9a3e 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -39,7 +39,7 @@
#include "codeflinger/ARMAssembler.h"
#elif defined(__aarch64__)
#include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
#include "codeflinger/MIPSAssembler.h"
#endif
//#include "codeflinger/ARMAssemblerOptimizer.h"
@@ -59,7 +59,7 @@
# define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED
#endif
-#if defined(__arm__) || defined(__mips__) || defined(__aarch64__)
+#if defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)
# define ANDROID_ARM_CODEGEN 1
#else
# define ANDROID_ARM_CODEGEN 0
@@ -73,7 +73,7 @@
*/
#define DEBUG_NEEDS 0
-#ifdef __mips__
+#if defined( __mips__) && !defined(__LP64__)
#define ASSEMBLY_SCRATCH_SIZE 4096
#elif defined(__aarch64__)
#define ASSEMBLY_SCRATCH_SIZE 8192
@@ -134,7 +134,7 @@
#elif defined(__aarch64__)
extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
#endif
@@ -2175,7 +2175,7 @@
void scanline_t32cb16blend(context_t* c)
{
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__mips__) || defined(__aarch64__)))
+#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || (defined(__mips__) && !defined(__LP64__)) || defined(__aarch64__)))
int32_t x = c->iterators.xl;
size_t ct = c->iterators.xr - x;
int32_t y = c->iterators.y;
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 36db49c..eca36ef 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -16,4 +16,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index ac890c7..3368eb0 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -13,4 +13,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
index baf4070..8f62f09 100644
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/disassembler/Android.mk
@@ -14,4 +14,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 1cce1bd..8e5ec5e 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -13,4 +13,6 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+LOCAL_MULTILIB := 64
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/Android.mk b/libpixelflinger/tests/codegen/Android.mk
index aa320fc..bc07015 100644
--- a/libpixelflinger/tests/codegen/Android.mk
+++ b/libpixelflinger/tests/codegen/Android.mk
@@ -15,4 +15,4 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
index e9f6c61..46c1ccc 100644
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ b/libpixelflinger/tests/codegen/codegen.cpp
@@ -52,7 +52,7 @@
GGLAssembler assembler( new ARMAssembler(a) );
#endif
-#if defined(__mips__)
+#if defined(__mips__) && !defined(__LP64__)
GGLAssembler assembler( new ArmToMipsAssembler(a) );
#endif
diff --git a/libpixelflinger/tests/gglmul/Android.mk b/libpixelflinger/tests/gglmul/Android.mk
index 64f88b7..f479fa1 100644
--- a/libpixelflinger/tests/gglmul/Android.mk
+++ b/libpixelflinger/tests/gglmul/Android.mk
@@ -13,4 +13,4 @@
LOCAL_MODULE_TAGS := tests
-include $(BUILD_EXECUTABLE)
+include $(BUILD_NATIVE_TEST)
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 9025cc0..02ab412 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -17,6 +17,7 @@
LOCAL_MODULE := libsparse_host
LOCAL_STATIC_LIBRARIES := libz
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -27,6 +28,7 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
LOCAL_SHARED_LIBRARIES := \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
@@ -36,6 +38,7 @@
LOCAL_MODULE := libsparse_static
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include external/zlib
LOCAL_STATIC_LIBRARIES := libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
@@ -48,6 +51,7 @@
LOCAL_STATIC_LIBRARIES := \
libsparse_host \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
@@ -58,6 +62,7 @@
LOCAL_STATIC_LIBRARIES := \
libsparse_static \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
@@ -69,6 +74,7 @@
LOCAL_STATIC_LIBRARIES := \
libsparse_host \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
@@ -78,6 +84,7 @@
LOCAL_STATIC_LIBRARIES := \
libsparse_static \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
@@ -87,6 +94,7 @@
LOCAL_STATIC_LIBRARIES := \
libsparse_host \
libz
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
@@ -95,5 +103,5 @@
LOCAL_SRC_FILES := simg_dump.py
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_IS_HOST_MODULE := true
+LOCAL_CFLAGS := -Werror
include $(BUILD_PREBUILT)
-
diff --git a/libsparse/img2simg.c b/libsparse/img2simg.c
index 6b1caa5..a0db36f 100644
--- a/libsparse/img2simg.c
+++ b/libsparse/img2simg.c
@@ -47,7 +47,6 @@
{
int in;
int out;
- unsigned int i;
int ret;
struct sparse_file *s;
unsigned int block_size = 4096;
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index 1cf8d8d..cd30800 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -31,8 +31,8 @@
#include "defs.h"
#include "output_file.h"
-#include "sparse_format.h"
#include "sparse_crc32.h"
+#include "sparse_format.h"
#ifndef USE_MINGW
#include <sys/mman.h>
@@ -295,7 +295,6 @@
static int callback_file_write(struct output_file *out, void *data, int len)
{
- int ret;
struct output_file_callback *outc = to_output_file_callback(out);
return outc->write(outc->priv, data, len);
@@ -341,7 +340,7 @@
static int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len)
{
chunk_header_t chunk_header;
- int ret, chunk;
+ int ret;
if (skip_len % out->block_size) {
error("don't care size %"PRIi64" is not a multiple of the block size %u",
@@ -368,9 +367,8 @@
uint32_t fill_val)
{
chunk_header_t chunk_header;
- int rnd_up_len, zero_len, count;
+ int rnd_up_len, count;
int ret;
- unsigned int i;
/* Round up the fill length to a multiple of the block size */
rnd_up_len = ALIGN(len, out->block_size);
@@ -536,8 +534,6 @@
void output_file_close(struct output_file *out)
{
- int ret;
-
out->sparse_ops->write_end_chunk(out);
out->ops->close(out);
}
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 0f107b0..baa30cd 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -279,7 +279,6 @@
struct sparse_file **out_s, int out_s_count)
{
struct backed_block *bb;
- unsigned int overhead;
struct sparse_file *s;
struct sparse_file *tmp;
int c = 0;
diff --git a/libsparse/sparse_read.c b/libsparse/sparse_read.c
index 873c87c..8e188e9 100644
--- a/libsparse/sparse_read.c
+++ b/libsparse/sparse_read.c
@@ -180,22 +180,16 @@
int fd __unused, unsigned int blocks,
unsigned int block __unused, uint32_t *crc32)
{
- int ret;
- int chunk;
- int64_t len = (int64_t)blocks * s->block_size;
- uint32_t fill_val;
- uint32_t *fillbuf;
- unsigned int i;
-
if (chunk_size != 0) {
return -EINVAL;
}
if (crc32) {
+ int64_t len = (int64_t)blocks * s->block_size;
memset(copybuf, 0, COPY_BUF_SIZE);
while (len) {
- chunk = min(len, COPY_BUF_SIZE);
+ int chunk = min(len, COPY_BUF_SIZE);
*crc32 = sparse_crc32(*crc32, copybuf, chunk);
len -= chunk;
}
@@ -367,7 +361,6 @@
int64_t remain = s->len;
int64_t offset = 0;
unsigned int to_read;
- char *ptr;
unsigned int i;
bool sparse_block;
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
index a2fa3e0..1ba2f59 100644
--- a/libsuspend/Android.mk
+++ b/libsuspend/Android.mk
@@ -18,6 +18,7 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
+LOCAL_CFLAGS := -Werror
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
include $(BUILD_SHARED_LIBRARY)
@@ -27,5 +28,6 @@
LOCAL_MODULE_TAGS := optional
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
include $(BUILD_STATIC_LIBRARY)
diff --git a/libsync/Android.mk b/libsync/Android.mk
index 626b762..fd1c88c 100644
--- a/libsync/Android.mk
+++ b/libsync/Android.mk
@@ -7,6 +7,7 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
@@ -15,4 +16,5 @@
LOCAL_MODULE_TAGS := optional tests
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index 1451b0d..246f954 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -18,7 +18,7 @@
LOCAL_C_INCLUDES :=
-LOCAL_CFLAGS :=
+LOCAL_CFLAGS := -Werror
LOCAL_SHARED_LIBRARIES := libcutils liblog
diff --git a/libsysutils/EventLogTags.logtags b/libsysutils/EventLogTags.logtags
index 7aa5cad..713f8cd 100644
--- a/libsysutils/EventLogTags.logtags
+++ b/libsysutils/EventLogTags.logtags
@@ -1,5 +1,5 @@
# See system/core/logcat/event.logtags for a description of the format of this file.
# FrameworkListener dispatchCommand overflow
-78001 dispatchCommand_overflow
-65537 netlink_failure (uid|1)
+78001 exp_det_dispatchCommand_overflow
+65537 exp_det_netlink_failure (uid|1)
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 01ed54e..e7b3dd6 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -92,7 +92,6 @@
char *qlimit = tmp + sizeof(tmp) - 1;
bool esc = false;
bool quote = false;
- int k;
bool haveCmdNum = !mWithSeq;
memset(argv, 0, sizeof(argv));
@@ -166,7 +165,7 @@
goto overflow;
argv[argc++] = strdup(tmp);
#if 0
- for (k = 0; k < argc; k++) {
+ for (int k = 0; k < argc; k++) {
SLOGD("arg[%d] = '%s'", k, argv[k]);
}
#endif
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 34f2016..1c9c70a 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -109,7 +109,7 @@
if (ifaddr->ifa_family == AF_INET) {
struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
- SLOGE("Short IPv4 address (%d bytes) in %s",
+ SLOGE("Short IPv4 address (%zu bytes) in %s",
RTA_PAYLOAD(rta), msgtype);
continue;
}
@@ -117,7 +117,7 @@
} else if (ifaddr->ifa_family == AF_INET6) {
struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
- SLOGE("Short IPv6 address (%d bytes) in %s",
+ SLOGE("Short IPv6 address (%zu bytes) in %s",
RTA_PAYLOAD(rta), msgtype);
continue;
}
@@ -152,7 +152,7 @@
}
if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
- SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s",
+ SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
continue;
}
@@ -174,7 +174,6 @@
}
/*
-<<<<<<< HEAD
* Parse a RTM_NEWNDUSEROPT message.
*/
bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
@@ -399,7 +398,6 @@
const char *s = buffer;
const char *end;
int param_idx = 0;
- int i;
int first = 1;
if (size == 0)
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
index acfc020..5c12f2c 100644
--- a/libusbhost/Android.mk
+++ b/libusbhost/Android.mk
@@ -25,6 +25,7 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -38,7 +39,7 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
-LOCAL_CFLAGS := -g -DUSE_LIBLOG
+LOCAL_CFLAGS := -g -DUSE_LIBLOG -Werror
# needed for logcat
LOCAL_SHARED_LIBRARIES := libcutils
@@ -52,5 +53,6 @@
LOCAL_MODULE := libusbhost
LOCAL_SRC_FILES := usbhost.c
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 8be393e..cd8000a 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -263,11 +263,12 @@
D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
"new" : "gone", path, i);
if (i > 0 && i < MAX_USBFS_WD_COUNT) {
+ int local_ret = 0;
if (event->mask & IN_CREATE) {
- ret = inotify_add_watch(context->fd, path,
+ local_ret = inotify_add_watch(context->fd, path,
IN_CREATE | IN_DELETE);
- if (ret >= 0)
- context->wds[i] = ret;
+ if (local_ret >= 0)
+ context->wds[i] = local_ret;
done = find_existing_devices_bus(path, context->cb_added,
context->data);
} else if (event->mask & IN_DELETE) {
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 1710d36..9a50147 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -43,7 +43,7 @@
VectorImpl.cpp \
misc.cpp
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
+host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
ifeq ($(HOST_OS),windows)
ifeq ($(strip $(USE_CYGWIN),),)
@@ -69,7 +69,7 @@
LOCAL_MODULE:= libutils
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(host_commonCflags)
-LOCAL_LDLIBS += $(host_commonLdlibs)
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -83,7 +83,6 @@
LOCAL_MODULE:= lib64utils
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += $(host_commonCflags) -m64
-LOCAL_LDLIBS += $(host_commonLdlibs)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -98,20 +97,15 @@
Looper.cpp \
Trace.cpp
-ifeq ($(TARGET_OS),linux)
-LOCAL_LDLIBS += -lrt -ldl
-endif
-
ifeq ($(TARGET_ARCH),mips)
LOCAL_CFLAGS += -DALIGN_DOUBLE
endif
+LOCAL_CFLAGS += -Werror
LOCAL_C_INCLUDES += \
bionic/libc/private \
external/zlib
-LOCAL_LDLIBS += -lpthread
-
LOCAL_STATIC_LIBRARIES := \
libcutils
@@ -134,7 +128,8 @@
libbacktrace \
libcutils \
libdl \
- liblog \
+ liblog
+LOCAL_CFLAGS := -Werror
include external/stlport/libstlport.mk
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index 660917b..f00bf14 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -28,7 +28,7 @@
namespace android {
// BlobCache::Header::mMagicNumber value
-static const uint32_t blobCacheMagic = '_Bb$';
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
// BlobCache::Header::mBlobCacheVersion value
static const uint32_t blobCacheVersion = 1;
@@ -49,7 +49,7 @@
mRandState[1] = (now >> 16) & 0xFFFF;
mRandState[2] = (now >> 32) & 0xFFFF;
#endif
- ALOGV("initializing random seed using %lld", now);
+ ALOGV("initializing random seed using %lld", (unsigned long long)now);
}
void BlobCache::set(const void* key, size_t keySize, const void* value,
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index 933e7aa..be4b14f 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -23,7 +23,13 @@
#include <utils/FileMap.h>
#include <utils/Log.h>
+#if defined(HAVE_WIN32_FILEMAP) && !defined(__USE_MINGW_ANSI_STDIO)
+# define PRId32 "I32d"
+# define PRIx32 "I32x"
+# define PRId64 "I64d"
+#else
#include <inttypes.h>
+#endif
#include <stdio.h>
#include <stdlib.h>
@@ -169,8 +175,8 @@
goto try_again;
}
- ALOGE("mmap(%" PRId64 ",%zu) failed: %s\n",
- adjOffset, adjLength, strerror(errno));
+ ALOGE("mmap(%lld,%zu) failed: %s\n",
+ (long long)adjOffset, adjLength, strerror(errno));
return false;
}
mBasePtr = ptr;
diff --git a/libutils/LinearAllocator.cpp b/libutils/LinearAllocator.cpp
index a07a291..8b90696 100644
--- a/libutils/LinearAllocator.cpp
+++ b/libutils/LinearAllocator.cpp
@@ -92,7 +92,7 @@
: mNextPage(0)
{}
- void* operator new(size_t size, void* buf) { return buf; }
+ void* operator new(size_t /*size*/, void* buf) { return buf; }
void* start() {
return (void*) (((size_t)this) + sizeof(Page));
@@ -103,7 +103,7 @@
}
private:
- Page(const Page& other) {}
+ Page(const Page& /*other*/) {}
Page* mNextPage;
};
diff --git a/libutils/Printer.cpp b/libutils/Printer.cpp
index 263e740..1dc8632 100644
--- a/libutils/Printer.cpp
+++ b/libutils/Printer.cpp
@@ -25,10 +25,6 @@
#include <stdio.h>
#include <stdlib.h>
-#ifndef __BIONIC__
-#define fdprintf dprintf
-#endif
-
namespace android {
/*
@@ -120,7 +116,7 @@
}
#ifndef USE_MINGW
- fdprintf(mFd, mFormatString, mPrefix, string);
+ dprintf(mFd, mFormatString, mPrefix, string);
#endif
}
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 385c226..02907ad 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -17,6 +17,14 @@
#define LOG_TAG "RefBase"
// #define LOG_NDEBUG 0
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <typeinfo>
+#include <unistd.h>
+
#include <utils/RefBase.h>
#include <utils/Atomic.h>
@@ -24,13 +32,9 @@
#include <utils/Log.h>
#include <utils/threads.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <typeinfo>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
// compile with refcounting debugging enabled
#define DEBUG_REFS 0
@@ -388,7 +392,7 @@
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
impl->addWeakRef(id);
- const int32_t c = android_atomic_inc(&impl->mWeak);
+ const int32_t c __unused = android_atomic_inc(&impl->mWeak);
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
@@ -615,7 +619,7 @@
{
}
-bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
+bool RefBase::onIncStrongAttempted(uint32_t flags, const void* /*id*/)
{
return (flags&FIRST_INC_STRONG) ? true : false;
}
@@ -626,13 +630,15 @@
// ---------------------------------------------------------------------------
-void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
#if DEBUG_REFS
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
for (size_t i=0 ; i<n ; i++) {
renamer(i);
}
-#endif
}
+#else
+void RefBase::renameRefs(size_t /*n*/, const ReferenceRenamer& /*renamer*/) { }
+#endif
void RefBase::renameRefId(weakref_type* ref,
const void* old_id, const void* new_id) {
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index b1708d6..8c7b596 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -21,7 +21,9 @@
#include <stdio.h>
/* for PRId64 */
+#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS 1
+#endif
#include <inttypes.h>
#include <utils/Log.h>
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index b09b728..91efdaa 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -16,7 +16,6 @@
#include <utils/String16.h>
-#include <utils/Debug.h>
#include <utils/Log.h>
#include <utils/Unicode.h>
#include <utils/String8.h>
@@ -67,8 +66,6 @@
return getEmptyString();
}
- const uint8_t* const u8end = u8cur + u8len;
-
SharedBuffer* buf = SharedBuffer::alloc(sizeof(char16_t)*(u16len+1));
if (buf) {
u8cur = (const uint8_t*) u8str;
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 8acb4d4..49340bb 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -551,7 +551,6 @@
{
const char* lastSlash;
const char* lastDot;
- int extLen;
const char* const str = mString;
// only look at the filename
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 413250f..dbad581 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -68,13 +68,7 @@
*/
#define DEBUG_TIMESTAMP 0
-static const char *gettime_method_names[] = {
- "clock_gettime",
- "ioctl",
- "systemTime",
-};
-
-#if DEBUG_TIMESTAMP
+#if DEBUG_TIMESTAMP && defined(ARCH_ARM)
static inline void checkTimeStamps(int64_t timestamp,
int64_t volatile *prevTimestampPtr,
int volatile *prevMethodPtr,
@@ -85,11 +79,16 @@
* gettid, and int64_t is different on the ARM platform
* (ie long vs long long).
*/
-#ifdef ARCH_ARM
int64_t prevTimestamp = *prevTimestampPtr;
int prevMethod = *prevMethodPtr;
if (timestamp < prevTimestamp) {
+ static const char *gettime_method_names[] = {
+ "clock_gettime",
+ "ioctl",
+ "systemTime",
+ };
+
ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
prevTimestamp, gettime_method_names[prevMethod],
timestamp, gettime_method_names[curMethod],
@@ -99,7 +98,6 @@
// write is interrupted or not observed as a whole.
*prevTimestampPtr = timestamp;
*prevMethodPtr = curMethod;
-#endif
}
#else
#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index ff74914..cc7fe89 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -17,16 +17,11 @@
// #define LOG_NDEBUG 0
#define LOG_TAG "libutils.threads"
-#include <utils/threads.h>
-#include <utils/Log.h>
-
-#include <cutils/sched_policy.h>
-
+#include <assert.h>
+#include <errno.h>
+#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
-#include <memory.h>
-#include <errno.h>
-#include <assert.h>
#include <unistd.h>
#if defined(HAVE_PTHREADS)
@@ -47,6 +42,17 @@
#include <sys/prctl.h>
#endif
+#include <utils/threads.h>
+#include <utils/Log.h>
+
+#include <cutils/sched_policy.h>
+
+#ifdef HAVE_ANDROID_OS
+# define __android_unused
+#else
+# define __android_unused __attribute__((__unused__))
+#endif
+
/*
* ===========================================================================
* Thread wrappers
@@ -119,7 +125,7 @@
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
void *userData,
- const char* threadName,
+ const char* threadName __android_unused,
int32_t threadPriority,
size_t threadStackSize,
android_thread_id_t *threadId)
@@ -251,9 +257,9 @@
int androidCreateRawThreadEtc(android_thread_func_t fn,
void *userData,
- const char* threadName,
- int32_t threadPriority,
- size_t threadStackSize,
+ const char* /*threadName*/,
+ int32_t /*threadPriority*/,
+ size_t /*threadStackSize*/,
android_thread_id_t *threadId)
{
return doCreateThread( fn, userData, threadId);
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index a431e92..4687d4d 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -32,9 +32,9 @@
#include <windows.h>
#endif
+#if defined(HAVE_ANDROID_OS)
nsecs_t systemTime(int clock)
{
-#if defined(HAVE_ANDROID_OS)
static const clockid_t clocks[] = {
CLOCK_REALTIME,
CLOCK_MONOTONIC,
@@ -46,7 +46,10 @@
t.tv_sec = t.tv_nsec = 0;
clock_gettime(clocks[clock], &t);
return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec;
+}
#else
+nsecs_t systemTime(int /*clock*/)
+{
// Clock support varies widely across hosts. Mac OS doesn't support
// posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
// is windows.
@@ -54,8 +57,8 @@
t.tv_sec = t.tv_usec = 0;
gettimeofday(&t, NULL);
return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL;
-#endif
}
+#endif
int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
{
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index a66e3bb..fe8887d 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -576,7 +576,7 @@
char16_t* utf8_to_utf16_n(const uint8_t* src, size_t srcLen, char16_t* dst, size_t dstLen) {
const uint8_t* const u8end = src + srcLen;
const uint8_t* u8cur = src;
- const uint16_t* const u16end = dst + dstLen;
+ const char16_t* const u16end = dst + dstLen;
char16_t* u16cur = dst;
while (u8cur < u8end && u16cur < u16end) {
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index 7202123..dac4e2c 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -44,7 +44,7 @@
};
TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
@@ -54,7 +54,7 @@
}
TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
- char buf[2] = { 0xee, 0xee };
+ unsigned char buf[2] = { 0xee, 0xee };
mBC->set("ab", 2, "cd", 2);
mBC->set("ef", 2, "gh", 2);
ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
@@ -66,7 +66,7 @@
}
TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
- char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
ASSERT_EQ(0xee, buf[0]);
@@ -78,7 +78,7 @@
}
TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
- char buf[3] = { 0xee, 0xee, 0xee };
+ unsigned char buf[3] = { 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
ASSERT_EQ(0xee, buf[0]);
@@ -92,7 +92,7 @@
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
mBC->set("abcd", 4, "ijkl", 4);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -103,7 +103,7 @@
}
TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
- char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
@@ -115,7 +115,7 @@
TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
char key[MAX_KEY_SIZE+1];
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
key[i] = 'a';
}
@@ -165,7 +165,7 @@
TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
char key[MAX_KEY_SIZE];
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
for (int i = 0; i < MAX_KEY_SIZE; i++) {
key[i] = 'a';
}
@@ -214,7 +214,7 @@
}
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
- char buf[1] = { 0xee };
+ unsigned char buf[1] = { 0xee };
mBC->set("x", 1, "y", 1);
ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
ASSERT_EQ('y', buf[0]);
@@ -282,7 +282,7 @@
};
TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
roundTrip();
ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
@@ -348,7 +348,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -365,7 +365,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -384,7 +384,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
@@ -403,7 +403,7 @@
}
TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
- char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
mBC->set("abcd", 4, "efgh", 4);
size_t size = mBC->getFlattenedSize();
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index e754c3b..705caa5 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -30,6 +30,7 @@
LOCAL_MODULE:= libziparchive
LOCAL_C_INCLUDES += ${includes}
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -40,6 +41,8 @@
LOCAL_STATIC_LIBRARIES := libz libutils
LOCAL_MODULE:= libziparchive-host
+LOCAL_CFLAGS := -Werror
+LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -47,7 +50,8 @@
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS += \
-DGTEST_OS_LINUX_ANDROID \
- -DGTEST_HAS_STD_STRING
+ -DGTEST_HAS_STD_STRING \
+ -Werror
LOCAL_SRC_FILES := zip_archive_test.cc
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_STATIC_LIBRARIES := libziparchive libz libgtest libgtest_main libutils
@@ -58,7 +62,8 @@
LOCAL_CPP_EXTENSION := .cc
LOCAL_CFLAGS += \
-DGTEST_OS_LINUX \
- -DGTEST_HAS_STD_STRING
+ -DGTEST_HAS_STD_STRING \
+ -Werror
LOCAL_SRC_FILES := zip_archive_test.cc
LOCAL_STATIC_LIBRARIES := libziparchive-host \
libz \
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index aebddc8..128bad4 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <utils/Compat.h>
#include <utils/FileMap.h>
#include <zlib.h>
@@ -34,57 +35,173 @@
#include "ziparchive/zip_archive.h"
-// This is for windows. If we don't open a file in binary mode, weirds
+// This is for windows. If we don't open a file in binary mode, weird
// things will happen.
#ifndef O_BINARY
#define O_BINARY 0
#endif
-/*
- * Zip file constants.
- */
-static const uint32_t kEOCDSignature = 0x06054b50;
-static const uint32_t kEOCDLen = 2;
-static const uint32_t kEOCDNumEntries = 8; // offset to #of entries in file
-static const uint32_t kEOCDSize = 12; // size of the central directory
-static const uint32_t kEOCDFileOffset = 16; // offset to central directory
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
-static const uint32_t kMaxCommentLen = 65535; // longest possible in ushort
-static const uint32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
+// The "end of central directory" (EOCD) record. Each archive
+// contains exactly once such record which appears at the end of
+// the archive. It contains archive wide information like the
+// number of entries in the archive and the offset to the central
+// directory of the offset.
+struct EocdRecord {
+ static const uint32_t kSignature = 0x06054b50;
-static const uint32_t kLFHSignature = 0x04034b50;
-static const uint32_t kLFHLen = 30; // excluding variable-len fields
-static const uint32_t kLFHGPBFlags = 6; // general purpose bit flags
-static const uint32_t kLFHCRC = 14; // offset to CRC
-static const uint32_t kLFHCompLen = 18; // offset to compressed length
-static const uint32_t kLFHUncompLen = 22; // offset to uncompressed length
-static const uint32_t kLFHNameLen = 26; // offset to filename length
-static const uint32_t kLFHExtraLen = 28; // offset to extra length
+ // End of central directory signature, should always be
+ // |kSignature|.
+ uint32_t eocd_signature;
+ // The number of the current "disk", i.e, the "disk" that this
+ // central directory is on.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that disk_num == 1.
+ uint16_t disk_num;
+ // The disk where the central directory starts.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that cd_start_disk == 1.
+ uint16_t cd_start_disk;
+ // The number of central directory records on this disk.
+ //
+ // This implementation assumes that each archive spans a single
+ // disk only. i.e, that num_records_on_disk == num_records.
+ uint16_t num_records_on_disk;
+ // The total number of central directory records.
+ uint16_t num_records;
+ // The size of the central directory (in bytes).
+ uint32_t cd_size;
+ // The offset of the start of the central directory, relative
+ // to the start of the file.
+ uint32_t cd_start_offset;
+ // Length of the central directory comment.
+ uint16_t comment_length;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+} __attribute__((packed));
-static const uint32_t kCDESignature = 0x02014b50;
-static const uint32_t kCDELen = 46; // excluding variable-len fields
-static const uint32_t kCDEMethod = 10; // offset to compression method
-static const uint32_t kCDEModWhen = 12; // offset to modification timestamp
-static const uint32_t kCDECRC = 16; // offset to entry CRC
-static const uint32_t kCDECompLen = 20; // offset to compressed length
-static const uint32_t kCDEUncompLen = 24; // offset to uncompressed length
-static const uint32_t kCDENameLen = 28; // offset to filename length
-static const uint32_t kCDEExtraLen = 30; // offset to extra length
-static const uint32_t kCDECommentLen = 32; // offset to comment length
-static const uint32_t kCDELocalOffset = 42; // offset to local hdr
+// A structure representing the fixed length fields for a single
+// record in the central directory of the archive. In addition to
+// the fixed length fields listed here, each central directory
+// record contains a variable length "file_name" and "extra_field"
+// whose lengths are given by |file_name_length| and |extra_field_length|
+// respectively.
+struct CentralDirectoryRecord {
+ static const uint32_t kSignature = 0x02014b50;
-static const uint32_t kDDOptSignature = 0x08074b50; // *OPTIONAL* data descriptor signature
-static const uint32_t kDDSignatureLen = 4;
-static const uint32_t kDDLen = 12;
-static const uint32_t kDDMaxLen = 16; // max of 16 bytes with a signature, 12 bytes without
-static const uint32_t kDDCrc32 = 0; // offset to crc32
-static const uint32_t kDDCompLen = 4; // offset to compressed length
-static const uint32_t kDDUncompLen = 8; // offset to uncompressed length
+ // The start of record signature. Must be |kSignature|.
+ uint32_t record_signature;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_made_by;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_needed;
+ // The "general purpose bit flags" for this entry. The only
+ // flag value that we currently check for is the "data descriptor"
+ // flag.
+ uint16_t gpb_flags;
+ // The compression method for this entry, one of |kCompressStored|
+ // and |kCompressDeflated|.
+ uint16_t compression_method;
+ // The file modification time and date for this entry.
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ // The CRC-32 checksum for this entry.
+ uint32_t crc32;
+ // The compressed size (in bytes) of this entry.
+ uint32_t compressed_size;
+ // The uncompressed size (in bytes) of this entry.
+ uint32_t uncompressed_size;
+ // The length of the entry file name in bytes. The file name
+ // will appear immediately after this record.
+ uint16_t file_name_length;
+ // The length of the extra field info (in bytes). This data
+ // will appear immediately after the entry file name.
+ uint16_t extra_field_length;
+ // The length of the entry comment (in bytes). This data will
+ // appear immediately after the extra field.
+ uint16_t comment_length;
+ // The start disk for this entry. Ignored by this implementation).
+ uint16_t file_start_disk;
+ // File attributes. Ignored by this implementation.
+ uint16_t internal_file_attributes;
+ // File attributes. Ignored by this implementation.
+ uint32_t external_file_attributes;
+ // The offset to the local file header for this entry, from the
+ // beginning of this archive.
+ uint32_t local_file_header_offset;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+} __attribute__((packed));
-static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
+// The local file header for a given entry. This duplicates information
+// present in the central directory of the archive. It is an error for
+// the information here to be different from the central directory
+// information for a given entry.
+struct LocalFileHeader {
+ static const uint32_t kSignature = 0x04034b50;
+ // The local file header signature, must be |kSignature|.
+ uint32_t lfh_signature;
+ // Tool version. Ignored by this implementation.
+ uint16_t version_needed;
+ // The "general purpose bit flags" for this entry. The only
+ // flag value that we currently check for is the "data descriptor"
+ // flag.
+ uint16_t gpb_flags;
+ // The compression method for this entry, one of |kCompressStored|
+ // and |kCompressDeflated|.
+ uint16_t compression_method;
+ // The file modification time and date for this entry.
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ // The CRC-32 checksum for this entry.
+ uint32_t crc32;
+ // The compressed size (in bytes) of this entry.
+ uint32_t compressed_size;
+ // The uncompressed size (in bytes) of this entry.
+ uint32_t uncompressed_size;
+ // The length of the entry file name in bytes. The file name
+ // will appear immediately after this record.
+ uint16_t file_name_length;
+ // The length of the extra field info (in bytes). This data
+ // will appear immediately after the entry file name.
+ uint16_t extra_field_length;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+} __attribute__((packed));
+
+struct DataDescriptor {
+ // The *optional* data descriptor start signature.
+ static const uint32_t kOptSignature = 0x08074b50;
+
+ // CRC-32 checksum of the entry.
+ uint32_t crc32;
+ // Compressed size of the entry.
+ uint32_t compressed_size;
+ // Uncompressed size of the entry.
+ uint32_t uncompressed_size;
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+} __attribute__((packed));
+
+#undef DISALLOW_IMPLICIT_CONSTRUCTORS
+
+static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
static const uint32_t kMaxErrorLen = 1024;
+// The maximum size of a central directory or a file
+// comment in bytes.
+static const uint32_t kMaxCommentLen = 65535;
+
+// The maximum number of bytes to scan backwards for the EOCD start.
+static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
+
static const char* kErrorMessages[] = {
"Unknown return code.",
"Iteration ended",
@@ -218,7 +335,7 @@
ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
if (actual != get_size) {
- ALOGW("CopyFileToFile: copy read failed (%zd vs %zd)", actual, get_size);
+ ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
return kIoError;
}
@@ -310,39 +427,21 @@
return 0;
}
-/*
- * Get 2 little-endian bytes.
- */
-static uint16_t get2LE(const uint8_t* src) {
- return src[0] | (src[1] << 8);
-}
-
-/*
- * Get 4 little-endian bytes.
- */
-static uint32_t get4LE(const uint8_t* src) {
- uint32_t result;
-
- result = src[0];
- result |= src[1] << 8;
- result |= src[2] << 16;
- result |= src[3] << 24;
-
- return result;
-}
-
static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
ZipArchive* archive, off64_t file_length,
- uint32_t read_amount, uint8_t* scan_buffer) {
+ off64_t read_amount, uint8_t* scan_buffer) {
const off64_t search_start = file_length - read_amount;
if (lseek64(fd, search_start, SEEK_SET) != search_start) {
- ALOGW("Zip: seek %" PRId64 " failed: %s", search_start, strerror(errno));
+ ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
+ strerror(errno));
return kIoError;
}
- ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount));
- if (actual != (ssize_t) read_amount) {
- ALOGW("Zip: read %u failed: %s", read_amount, strerror(errno));
+ ssize_t actual = TEMP_FAILURE_RETRY(
+ read(fd, scan_buffer, static_cast<size_t>(read_amount)));
+ if (actual != static_cast<ssize_t>(read_amount)) {
+ ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
+ strerror(errno));
return kIoError;
}
@@ -352,9 +451,10 @@
* doing an initial minimal read; if we don't find it, retry with a
* second read as above.)
*/
- int i;
- for (i = read_amount - kEOCDLen; i >= 0; i--) {
- if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) {
+ int i = read_amount - sizeof(EocdRecord);
+ for (; i >= 0; i--) {
+ if (scan_buffer[i] == 0x50 &&
+ ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) {
ALOGV("+++ Found EOCD at buf+%d", i);
break;
}
@@ -365,46 +465,52 @@
}
const off64_t eocd_offset = search_start + i;
- const uint8_t* eocd_ptr = scan_buffer + i;
-
- assert(eocd_offset < file_length);
+ const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
+ /*
+ * Verify that there's no trailing space at the end of the central directory
+ * and its comment.
+ */
+ const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
+ + eocd->comment_length;
+ if (calculated_length != file_length) {
+ ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
+ static_cast<int64_t>(file_length - calculated_length));
+ return kInvalidFile;
+ }
/*
* Grab the CD offset and size, and the number of entries in the
- * archive. Verify that they look reasonable. Widen dir_size and
- * dir_offset to the file offset type.
+ * archive and verify that they look reasonable.
*/
- const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries);
- const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize);
- const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset);
-
- if (dir_offset + dir_size > eocd_offset) {
- ALOGW("Zip: bad offsets (dir %" PRId64 ", size %" PRId64 ", eocd %" PRId64 ")",
- dir_offset, dir_size, eocd_offset);
+ if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) {
+ ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
+ eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
return kInvalidOffset;
}
- if (num_entries == 0) {
+ if (eocd->num_records == 0) {
ALOGW("Zip: empty archive?");
return kEmptyArchive;
}
- ALOGV("+++ num_entries=%d dir_size=%" PRId64 " dir_offset=%" PRId64,
- num_entries, dir_size, dir_offset);
+ ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32,
+ eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
/*
* It all looks good. Create a mapping for the CD, and set the fields
* in archive.
*/
- android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size,
- true /* read only */, debug_file_name);
+ android::FileMap* map = MapFileSegment(fd,
+ static_cast<off64_t>(eocd->cd_start_offset),
+ static_cast<size_t>(eocd->cd_size),
+ true /* read only */, debug_file_name);
if (map == NULL) {
archive->directory_map = NULL;
return kMmapFailed;
}
archive->directory_map = map;
- archive->num_entries = num_entries;
- archive->directory_offset = dir_offset;
+ archive->num_entries = eocd->num_records;
+ archive->directory_offset = eocd->cd_start_offset;
return 0;
}
@@ -430,12 +536,12 @@
}
if (file_length > (off64_t) 0xffffffff) {
- ALOGV("Zip: zip file too long %" PRId64, file_length);
+ ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
return kInvalidFile;
}
- if (file_length < (int64_t) kEOCDLen) {
- ALOGV("Zip: length %" PRId64 " is too small to be zip", file_length);
+ if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
+ ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
return kInvalidFile;
}
@@ -451,12 +557,12 @@
*
* We start by pulling in the last part of the file.
*/
- uint32_t read_amount = kMaxEOCDSearch;
- if (file_length < (off64_t) read_amount) {
+ off64_t read_amount = kMaxEOCDSearch;
+ if (file_length < read_amount) {
read_amount = file_length;
}
- uint8_t* scan_buffer = (uint8_t*) malloc(read_amount);
+ uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
file_length, read_amount, scan_buffer);
@@ -472,9 +578,9 @@
*/
static int32_t ParseZipArchive(ZipArchive* archive) {
int32_t result = -1;
- const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
- size_t cd_length = archive->directory_map->getDataLength();
- uint16_t num_entries = archive->num_entries;
+ const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr();
+ const size_t cd_length = archive->directory_map->getDataLength();
+ const uint16_t num_entries = archive->num_entries;
/*
* Create hash table. We have a minimum 75% load factor, possibly as
@@ -489,45 +595,49 @@
* Walk through the central directory, adding entries to the hash
* table and verifying values.
*/
+ const uint8_t* const cd_end = cd_ptr + cd_length;
const uint8_t* ptr = cd_ptr;
for (uint16_t i = 0; i < num_entries; i++) {
- if (get4LE(ptr) != kCDESignature) {
- ALOGW("Zip: missed a central dir sig (at %d)", i);
+ const CentralDirectoryRecord* cdr =
+ reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+ if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
+ ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
goto bail;
}
- if (ptr + kCDELen > cd_ptr + cd_length) {
- ALOGW("Zip: ran off the end (at %d)", i);
+ if (ptr + sizeof(CentralDirectoryRecord) > cd_end) {
+ ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
goto bail;
}
- const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
+ const off64_t local_header_offset = cdr->local_file_header_offset;
if (local_header_offset >= archive->directory_offset) {
- ALOGW("Zip: bad LFH offset %" PRId64 " at entry %d", local_header_offset, i);
+ ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i);
goto bail;
}
- const uint16_t file_name_length = get2LE(ptr + kCDENameLen);
- const uint16_t extra_length = get2LE(ptr + kCDEExtraLen);
- const uint16_t comment_length = get2LE(ptr + kCDECommentLen);
+ const uint16_t file_name_length = cdr->file_name_length;
+ const uint16_t extra_length = cdr->extra_field_length;
+ const uint16_t comment_length = cdr->comment_length;
/* add the CDE filename to the hash table */
+ const char* file_name = reinterpret_cast<const char *>(ptr + sizeof(CentralDirectoryRecord));
const int add_result = AddToHash(archive->hash_table,
- archive->hash_table_size, (const char*) ptr + kCDELen, file_name_length);
+ archive->hash_table_size, file_name, file_name_length);
if (add_result) {
ALOGW("Zip: Error adding entry to hash table %d", add_result);
result = add_result;
goto bail;
}
- ptr += kCDELen + file_name_length + extra_length + comment_length;
- if ((size_t)(ptr - cd_ptr) > cd_length) {
- ALOGW("Zip: bad CD advance (%zu vs %zu) at entry %d",
- (size_t) (ptr - cd_ptr), cd_length, i);
+ ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
+ if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
+ ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
+ ptr - cd_ptr, cd_length, i);
goto bail;
}
}
- ALOGV("+++ zip good scan %d entries", num_entries);
+ ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
result = 0;
@@ -596,21 +706,19 @@
static int32_t UpdateEntryFromDataDescriptor(int fd,
ZipEntry *entry) {
- uint8_t ddBuf[kDDMaxLen];
+ uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf)));
if (actual != sizeof(ddBuf)) {
return kIoError;
}
- const uint32_t ddSignature = get4LE(ddBuf);
- uint16_t ddOffset = 0;
- if (ddSignature == kDDOptSignature) {
- ddOffset = 4;
- }
+ const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
+ const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
+ const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
- entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32);
- entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen);
- entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen);
+ entry->crc32 = descriptor->crc32;
+ entry->compressed_length = descriptor->compressed_size;
+ entry->uncompressed_length = descriptor->uncompressed_size;
return 0;
}
@@ -646,19 +754,22 @@
// Recover the start of the central directory entry from the filename
// pointer. The filename is the first entry past the fixed-size data,
// so we can just subtract back from that.
- const unsigned char* ptr = (const unsigned char*) name;
- ptr -= kCDELen;
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
+ ptr -= sizeof(CentralDirectoryRecord);
// This is the base of our mmapped region, we have to sanity check that
// the name that's in the hash table is a pointer to a location within
// this mapped region.
- const unsigned char* base_ptr = (const unsigned char*)
- archive->directory_map->getDataPtr();
+ const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
+ archive->directory_map->getDataPtr());
if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) {
ALOGW("Zip: Invalid entry pointer");
return kInvalidOffset;
}
+ const CentralDirectoryRecord *cdr =
+ reinterpret_cast<const CentralDirectoryRecord*>(ptr);
+
// The offset of the start of the central directory in the zipfile.
// We keep this lying around so that we can sanity check all our lengths
// and our per-file structures.
@@ -667,52 +778,48 @@
// Fill out the compression method, modification time, crc32
// and other interesting attributes from the central directory. These
// will later be compared against values from the local file header.
- data->method = get2LE(ptr + kCDEMethod);
- data->mod_time = get4LE(ptr + kCDEModWhen);
- data->crc32 = get4LE(ptr + kCDECRC);
- data->compressed_length = get4LE(ptr + kCDECompLen);
- data->uncompressed_length = get4LE(ptr + kCDEUncompLen);
+ data->method = cdr->compression_method;
+ data->mod_time = cdr->last_mod_time;
+ data->crc32 = cdr->crc32;
+ data->compressed_length = cdr->compressed_size;
+ data->uncompressed_length = cdr->uncompressed_size;
// Figure out the local header offset from the central directory. The
// actual file data will begin after the local header and the name /
// extra comments.
- const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset);
- if (local_header_offset + (off64_t) kLFHLen >= cd_offset) {
+ const off64_t local_header_offset = cdr->local_file_header_offset;
+ if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
ALOGW("Zip: bad local hdr offset in zip");
return kInvalidOffset;
}
- uint8_t lfh_buf[kLFHLen];
+ uint8_t lfh_buf[sizeof(LocalFileHeader)];
ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf),
local_header_offset);
if (actual != sizeof(lfh_buf)) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, local_header_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)local_header_offset);
return kIoError;
}
- if (get4LE(lfh_buf) != kLFHSignature) {
+ const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
+
+ if (lfh->lfh_signature != LocalFileHeader::kSignature) {
ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
- local_header_offset);
+ static_cast<int64_t>(local_header_offset));
return kInvalidOffset;
}
// Paranoia: Match the values specified in the local file header
// to those specified in the central directory.
- const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags);
- const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen);
- const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen);
-
- if ((lfhGpbFlags & kGPBDDFlagMask) == 0) {
- const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC);
- const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen);
- const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen);
-
+ if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
data->has_data_descriptor = 0;
- if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen
- || data->crc32 != lfhCrc) {
- ALOGW("Zip: size/crc32 mismatch. expected {%d, %d, %x}, was {%d, %d, %x}",
+ if (data->compressed_length != lfh->compressed_size
+ || data->uncompressed_length != lfh->uncompressed_size
+ || data->crc32 != lfh->crc32) {
+ ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
+ ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
data->compressed_length, data->uncompressed_length, data->crc32,
- lfhCompLen, lfhUncompLen, lfhCrc);
+ lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
return kInconsistentInformation;
}
} else {
@@ -721,9 +828,9 @@
// Check that the local file header name matches the declared
// name in the central directory.
- if (lfhNameLen == nameLen) {
- const off64_t name_offset = local_header_offset + kLFHLen;
- if (name_offset + lfhNameLen >= cd_offset) {
+ if (lfh->file_name_length == nameLen) {
+ const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
+ if (name_offset + lfh->file_name_length >= cd_offset) {
ALOGW("Zip: Invalid declared length");
return kInvalidOffset;
}
@@ -733,7 +840,7 @@
name_offset);
if (actual != nameLen) {
- ALOGW("Zip: failed reading lfh name from offset %" PRId64, name_offset);
+ ALOGW("Zip: failed reading lfh name from offset %" PRId64, (int64_t)name_offset);
free(name_buf);
return kIoError;
}
@@ -749,22 +856,23 @@
return kInconsistentInformation;
}
- const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen;
+ const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
+ + lfh->file_name_length + lfh->extra_field_length;
if (data_offset > cd_offset) {
- ALOGW("Zip: bad data offset %" PRId64 " in zip", data_offset);
+ ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset);
return kInvalidOffset;
}
if ((off64_t)(data_offset + data->compressed_length) > cd_offset) {
- ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %zd > %" PRId64 ")",
- data_offset, data->compressed_length, cd_offset);
+ ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
+ (int64_t)data_offset, data->compressed_length, (int64_t)cd_offset);
return kInvalidOffset;
}
if (data->method == kCompressStored &&
(off64_t)(data_offset + data->uncompressed_length) > cd_offset) {
- ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %d > %" PRId64 ")",
- data_offset, data->uncompressed_length, cd_offset);
+ ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
+ (int64_t)data_offset, data->uncompressed_length, (int64_t)cd_offset);
return kInvalidOffset;
}
@@ -900,10 +1008,10 @@
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
- const ssize_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
- const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
+ const ZD_TYPE getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
+ const ZD_TYPE actual = TEMP_FAILURE_RETRY(read(fd, read_buf, getSize));
if (actual != getSize) {
- ALOGW("Zip: inflate read failed (%zd vs %zd)", actual, getSize);
+ ALOGW("Zip: inflate read failed (" ZD " vs " ZD ")", actual, getSize);
result = kIoError;
goto z_bail;
}
@@ -946,7 +1054,7 @@
*crc_out = zstream.adler;
if (zstream.total_out != uncompressed_length || compressed_length != 0) {
- ALOGW("Zip: size mismatch on inflated file (%ld vs %u)",
+ ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
zstream.total_out, uncompressed_length);
result = kInconsistentInformation;
goto z_bail;
@@ -967,7 +1075,7 @@
off64_t data_offset = entry->offset;
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
- ALOGW("Zip: lseek to data at %" PRId64 " failed", data_offset);
+ ALOGW("Zip: lseek to data at %" PRId64 " failed", (int64_t)data_offset);
return kIoError;
}
@@ -990,7 +1098,7 @@
// TODO: Fix this check by passing the right flags to inflate2 so that
// it calculates the CRC for us.
if (entry->crc32 != crc && false) {
- ALOGW("Zip: crc mismatch: expected %u, was %" PRIu64, entry->crc32, crc);
+ ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
return kInconsistentInformation;
}
@@ -1011,7 +1119,7 @@
int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
if (result == -1) {
ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- declared_length + current_offset, strerror(errno));
+ (int64_t)(declared_length + current_offset), strerror(errno));
return kIoError;
}
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 3082216..875b6de 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -140,11 +140,7 @@
CloseArchive(handle);
}
-TEST(ziparchive, EmptyEntries) {
- char temp_file_pattern[] = "empty_entries_test_XXXXXX";
- int fd = mkstemp(temp_file_pattern);
- ASSERT_NE(-1, fd);
- const uint32_t data[] = {
+static const uint32_t kEmptyEntriesZip[] = {
0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
@@ -152,8 +148,28 @@
0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
- const ssize_t file_size = 168;
- ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
+
+static int make_temporary_file(const char* file_name_pattern) {
+ char full_path[1024];
+ // Account for differences between the host and the target.
+ //
+ // TODO: Maybe reuse bionic/tests/TemporaryFile.h.
+ snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern);
+ int fd = mkstemp(full_path);
+ if (fd == -1) {
+ snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern);
+ fd = mkstemp(full_path);
+ }
+
+ return fd;
+}
+
+TEST(ziparchive, EmptyEntries) {
+ char temp_file_pattern[] = "empty_entries_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+ const ssize_t file_size = sizeof(kEmptyEntriesZip);
+ ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
@@ -165,7 +181,7 @@
ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
char output_file_pattern[] = "empty_entries_output_XXXXXX";
- int output_fd = mkstemp(output_file_pattern);
+ int output_fd = make_temporary_file(output_file_pattern);
ASSERT_NE(-1, output_fd);
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
@@ -177,9 +193,25 @@
close(output_fd);
}
+TEST(ziparchive, TrailerAfterEOCD) {
+ char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+
+ // Create a file with 8 bytes of random garbage.
+ static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
+ const ssize_t file_size = sizeof(kEmptyEntriesZip);
+ const ssize_t trailer_size = sizeof(trailer);
+ ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size)));
+ ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size)));
+
+ ZipArchiveHandle handle;
+ ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
+}
+
TEST(ziparchive, ExtractToFile) {
char kTempFilePattern[] = "zip_archive_input_XXXXXX";
- int fd = mkstemp(kTempFilePattern);
+ int fd = make_temporary_file(kTempFilePattern);
ASSERT_NE(-1, fd);
const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
const ssize_t data_size = sizeof(data);
@@ -209,7 +241,8 @@
sizeof(kATxtContents)));
// Assert that the total length of the file is sane
- ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END));
+ ASSERT_EQ(data_size + static_cast<ssize_t>(sizeof(kATxtContents)),
+ lseek64(fd, 0, SEEK_END));
close(fd);
}
@@ -247,4 +280,3 @@
return RUN_ALL_TESTS();
}
-
diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk
index d2d758c..12a2229 100644
--- a/libzipfile/Android.mk
+++ b/libzipfile/Android.mk
@@ -14,6 +14,10 @@
LOCAL_C_INCLUDES += external/zlib
+LOCAL_CFLAGS := -Werror
+
+LOCAL_MULTILIB := both
+
include $(BUILD_HOST_STATIC_LIBRARY)
# build device static library
@@ -30,6 +34,8 @@
LOCAL_C_INCLUDES += external/zlib
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_STATIC_LIBRARY)
@@ -45,4 +51,6 @@
LOCAL_C_INCLUDES += external/zlib
+LOCAL_CFLAGS := -Werror
+
include $(BUILD_HOST_EXECUTABLE)
diff --git a/libzipfile/centraldir.c b/libzipfile/centraldir.c
index 911e2b9..69cf47a 100644
--- a/libzipfile/centraldir.c
+++ b/libzipfile/centraldir.c
@@ -3,6 +3,8 @@
#include <string.h>
#include <stdlib.h>
+#include <utils/Compat.h>
+
enum {
// finding the directory
CD_SIGNATURE = 0x06054b50,
@@ -66,24 +68,10 @@
{
const unsigned char* p;
- unsigned short versionMadeBy;
- unsigned short versionToExtract;
- unsigned short gpBitFlag;
- unsigned short compressionMethod;
- unsigned short lastModFileTime;
- unsigned short lastModFileDate;
- unsigned long crc32;
unsigned short extraFieldLength;
unsigned short fileCommentLength;
- unsigned short diskNumberStart;
- unsigned short internalAttrs;
- unsigned long externalAttrs;
unsigned long localHeaderRelOffset;
- const unsigned char* extraField;
- const unsigned char* fileComment;
unsigned int dataOffset;
- unsigned short lfhExtraFieldSize;
-
p = *buf;
@@ -97,21 +85,12 @@
return -1;
}
- versionMadeBy = read_le_short(&p[0x04]);
- versionToExtract = read_le_short(&p[0x06]);
- gpBitFlag = read_le_short(&p[0x08]);
entry->compressionMethod = read_le_short(&p[0x0a]);
- lastModFileTime = read_le_short(&p[0x0c]);
- lastModFileDate = read_le_short(&p[0x0e]);
- crc32 = read_le_int(&p[0x10]);
entry->compressedSize = read_le_int(&p[0x14]);
entry->uncompressedSize = read_le_int(&p[0x18]);
entry->fileNameLength = read_le_short(&p[0x1c]);
extraFieldLength = read_le_short(&p[0x1e]);
fileCommentLength = read_le_short(&p[0x20]);
- diskNumberStart = read_le_short(&p[0x22]);
- internalAttrs = read_le_short(&p[0x24]);
- externalAttrs = read_le_int(&p[0x26]);
localHeaderRelOffset = read_le_int(&p[0x2a]);
p += ENTRY_LEN;
@@ -125,19 +104,9 @@
p += entry->fileNameLength;
// extra field
- if (extraFieldLength != 0) {
- extraField = p;
- } else {
- extraField = NULL;
- }
p += extraFieldLength;
// comment, if any
- if (fileCommentLength != 0) {
- fileComment = p;
- } else {
- fileComment = NULL;
- }
p += fileCommentLength;
*buf = p;
@@ -183,7 +152,7 @@
int err;
const unsigned char* buf = file->buf;
- ssize_t bufsize = file->bufsize;
+ ZD_TYPE bufsize = file->bufsize;
const unsigned char* eocd;
const unsigned char* p;
const unsigned char* start;
@@ -192,7 +161,7 @@
// too small to be a ZIP archive?
if (bufsize < EOCD_LEN) {
- fprintf(stderr, "Length is %zd -- too small\n", bufsize);
+ fprintf(stderr, "Length is " ZD " -- too small\n", bufsize);
goto bail;
}
diff --git a/libzipfile/zipfile.c b/libzipfile/zipfile.c
index a401a9b..b903fcf 100644
--- a/libzipfile/zipfile.c
+++ b/libzipfile/zipfile.c
@@ -79,7 +79,6 @@
uninflate(unsigned char* out, int unlen, const unsigned char* in, int clen)
{
z_stream zstream;
- unsigned long crc;
int err = 0;
int zerr;
diff --git a/logcat/Android.mk b/logcat/Android.mk
index b5e27eb..f46a4de 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -7,7 +7,9 @@
LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_MODULE:= logcat
+LOCAL_MODULE := logcat
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 995a42e..7c6af42 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -281,7 +281,29 @@
return 0;
}
-extern "C" void logprint_run_tests(void);
+static const char multipliers[][2] = {
+ { "" },
+ { "K" },
+ { "M" },
+ { "G" }
+};
+
+static unsigned long value_of_size(unsigned long value)
+{
+ for (unsigned i = 0;
+ (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+ value /= 1024, ++i) ;
+ return value;
+}
+
+static const char *multiplier_of_size(unsigned long value)
+{
+ unsigned i;
+ for (i = 0;
+ (i < sizeof(multipliers)/sizeof(multipliers[0])) && (value >= 1024);
+ value /= 1024, ++i) ;
+ return multipliers[i];
+}
int main(int argc, char **argv)
{
@@ -306,11 +328,6 @@
g_logformat = android_log_format_new();
- if (argc == 2 && 0 == strcmp(argv[1], "--test")) {
- logprint_run_tests();
- exit(0);
- }
-
if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
android::show_help(argv[0]);
exit(0);
@@ -319,7 +336,7 @@
for (;;) {
int ret;
- ret = getopt(argc, argv, "cdt:T:gG:sQf:r::n:v:b:BSpP:");
+ ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:");
if (ret < 0) {
break;
@@ -496,9 +513,6 @@
android::g_logRotateSizeKBytes
= DEFAULT_LOG_ROTATE_SIZE_KBYTES;
} else {
- long logRotateSize;
- char *lastDigit;
-
if (!isdigit(optarg[0])) {
fprintf(stderr,"Invalid parameter to -r\n");
android::show_help(argv[0]);
@@ -609,18 +623,14 @@
}
if (!devices) {
- devices = new log_device_t("main", false, 'm');
+ dev = devices = new log_device_t("main", false, 'm');
android::g_devCount = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
- devices->next = new log_device_t("system", false, 's');
+ dev = dev->next = new log_device_t("system", false, 's');
android::g_devCount++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
- if (devices->next) {
- devices->next->next = new log_device_t("crash", false, 'c');
- } else {
- devices->next = new log_device_t("crash", false, 'c');
- }
+ dev = dev->next = new log_device_t("crash", false, 'c');
android::g_devCount++;
}
}
@@ -725,9 +735,10 @@
exit(EXIT_FAILURE);
}
- printf("%s: ring buffer is %ldKb (%ldKb consumed), "
+ printf("%s: ring buffer is %ld%sb (%ld%sb consumed), "
"max entry is %db, max payload is %db\n", dev->device,
- size / 1024, readable / 1024,
+ value_of_size(size), multiplier_of_size(size),
+ value_of_size(readable), multiplier_of_size(readable),
(int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
}
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index d42b3d0..015a23d 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -16,11 +16,7 @@
LOCAL_PATH := $(call my-dir)
-# -----------------------------------------------------------------------------
-# Unit tests.
-# -----------------------------------------------------------------------------
-
-test_module := logcat-unit-tests
+test_module_prefix := logcat-
test_tags := tests
test_c_flags := \
@@ -28,7 +24,29 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin
+ -fno-builtin \
+ -std=gnu++11
+
+# -----------------------------------------------------------------------------
+# Benchmarks (actually a gTest where the result code does not matter)
+# ----------------------------------------------------------------------------
+
+benchmark_src_files := \
+ logcat_benchmark.cpp
+
+# Build benchmarks for the device. Run with:
+# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
+include $(CLEAR_VARS)
+LOCAL_MODULE := $(test_module_prefix)benchmarks
+LOCAL_MODULE_TAGS := $(test_tags)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += $(test_c_flags)
+LOCAL_SRC_FILES := $(benchmark_src_files)
+include $(BUILD_NATIVE_TEST)
+
+# -----------------------------------------------------------------------------
+# Unit tests.
+# -----------------------------------------------------------------------------
test_src_files := \
logcat_test.cpp \
@@ -36,11 +54,10 @@
# Build tests for the device (with .so). Run with:
# adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
include $(CLEAR_VARS)
-LOCAL_MODULE := $(test_module)
+LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_LDLIBS := -lpthread
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
new file mode 100644
index 0000000..be815be
--- /dev/null
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+static const char begin[] = "--------- beginning of ";
+
+TEST(logcat, sorted_order) {
+ FILE *fp;
+
+ ASSERT_TRUE(NULL != (fp = popen(
+ "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
+ "r")));
+
+ class timestamp {
+ private:
+ int month;
+ int day;
+ int hour;
+ int minute;
+ int second;
+ int millisecond;
+ bool ok;
+
+ public:
+ void init(const char *buffer)
+ {
+ ok = false;
+ if (buffer != NULL) {
+ ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
+ &month, &day, &hour, &minute, &second, &millisecond) == 6;
+ }
+ }
+
+ timestamp(const char *buffer)
+ {
+ init(buffer);
+ }
+
+ bool operator< (timestamp &T)
+ {
+ return !ok || !T.ok
+ || (month < T.month)
+ || ((month == T.month)
+ && ((day < T.day)
+ || ((day == T.day)
+ && ((hour < T.hour)
+ || ((hour == T.hour)
+ && ((minute < T.minute)
+ || ((minute == T.minute)
+ && ((second < T.second)
+ || ((second == T.second)
+ && (millisecond < T.millisecond))))))))));
+ }
+
+ bool valid(void)
+ {
+ return ok;
+ }
+ } last(NULL);
+
+ char *last_buffer = NULL;
+ char buffer[5120];
+
+ int count = 0;
+ int next_lt_last = 0;
+
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
+ continue;
+ }
+ if (!last.valid()) {
+ free(last_buffer);
+ last_buffer = strdup(buffer);
+ last.init(buffer);
+ }
+ timestamp next(buffer);
+ if (next < last) {
+ if (last_buffer) {
+ fprintf(stderr, "<%s", last_buffer);
+ }
+ fprintf(stderr, ">%s", buffer);
+ ++next_lt_last;
+ }
+ if (next.valid()) {
+ free(last_buffer);
+ last_buffer = strdup(buffer);
+ last.init(buffer);
+ }
+ ++count;
+ }
+ free(last_buffer);
+
+ pclose(fp);
+
+ static const int max_ok = 2;
+
+ // Allow few fails, happens with readers active
+ fprintf(stderr, "%s: %d/%d out of order entries\n",
+ (next_lt_last)
+ ? ((next_lt_last <= max_ok)
+ ? "WARNING"
+ : "ERROR")
+ : "INFO",
+ next_lt_last, count);
+
+ EXPECT_GE(max_ok, next_lt_last);
+
+ // sample statistically too small
+ EXPECT_LT(100, count);
+}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index b07cc8b..9b316d1 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <gtest/gtest.h>
@@ -41,99 +42,6 @@
static const char begin[] = "--------- beginning of ";
-TEST(logcat, sorted_order) {
- FILE *fp;
-
- ASSERT_TRUE(NULL != (fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
-
- class timestamp {
- private:
- int month;
- int day;
- int hour;
- int minute;
- int second;
- int millisecond;
- bool ok;
-
- public:
- void init(const char *buffer)
- {
- ok = false;
- if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ",
- &month, &day, &hour, &minute, &second, &millisecond) == 6;
- }
- }
-
- timestamp(const char *buffer)
- {
- init(buffer);
- }
-
- bool operator< (timestamp &T)
- {
- return !ok || !T.ok
- || (month < T.month)
- || ((month == T.month)
- && ((day < T.day)
- || ((day == T.day)
- && ((hour < T.hour)
- || ((hour == T.hour)
- && ((minute < T.minute)
- || ((minute == T.minute)
- && ((second < T.second)
- || ((second == T.second)
- && (millisecond < T.millisecond))))))))));
- }
-
- bool valid(void)
- {
- return ok;
- }
- } last(NULL);
-
- char *last_buffer = NULL;
- char buffer[5120];
-
- int count = 0;
- int next_lt_last = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
- if (!last.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- timestamp next(buffer);
- if (next < last) {
- if (last_buffer) {
- fprintf(stderr, "<%s", last_buffer);
- }
- fprintf(stderr, ">%s", buffer);
- ++next_lt_last;
- }
- if (next.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- ++count;
- }
- free(last_buffer);
-
- pclose(fp);
-
- EXPECT_EQ(0, next_lt_last);
-
- EXPECT_LT(100, count);
-}
-
TEST(logcat, buckets) {
FILE *fp;
@@ -362,9 +270,10 @@
ASSERT_EQ(1, count);
}
-TEST(logcat, get_) {
+TEST(logcat, get_size) {
FILE *fp;
+ // NB: crash log only available in user space
ASSERT_TRUE(NULL != (fp = popen(
"logcat -b radio -b events -b system -b main -g 2>/dev/null",
"r")));
@@ -375,13 +284,49 @@
while (fgets(buffer, sizeof(buffer), fp)) {
int size, consumed, max, payload;
+ char size_mult, consumed_mult;
+ long full_size, full_consumed;
size = consumed = max = payload = 0;
- if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed),"
- " max entry is %db, max payload is %db",
- &size, &consumed, &max, &payload))
- && ((size * 3) >= consumed)
- && ((size * 1024) > max)
+ // NB: crash log can be very small, not hit a Kb of consumed space
+ // doubly lucky we are not including it.
+ if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed),"
+ " max entry is %db, max payload is %db",
+ &size, &size_mult, &consumed, &consumed_mult,
+ &max, &payload)) {
+ fprintf(stderr, "WARNING: Parse error: %s", buffer);
+ continue;
+ }
+ full_size = size;
+ switch(size_mult) {
+ case 'G':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_size *= 1024;
+ break;
+ }
+ full_consumed = consumed;
+ switch(consumed_mult) {
+ case 'G':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_consumed *= 1024;
+ break;
+ }
+ EXPECT_GT((full_size * 9) / 4, full_consumed);
+ EXPECT_GT(full_size, max);
+ EXPECT_GT(max, payload);
+
+ if ((((full_size * 9) / 4) >= full_consumed)
+ && (full_size > max)
&& (max > payload)) {
++count;
}
@@ -392,7 +337,7 @@
ASSERT_EQ(4, count);
}
-static void caught_blocking(int signum)
+static void caught_blocking(int /*signum*/)
{
unsigned long long v = 0xDEADBEEFA55A0000ULL;
@@ -461,7 +406,7 @@
EXPECT_EQ(1, signals);
}
-static void caught_blocking_tail(int signum)
+static void caught_blocking_tail(int /*signum*/)
{
unsigned long long v = 0xA55ADEADBEEF0000ULL;
@@ -532,7 +477,7 @@
EXPECT_EQ(1, signals);
}
-static void caught_blocking_clear(int signum)
+static void caught_blocking_clear(int /*signum*/)
{
unsigned long long v = 0xDEADBEEFA55C0000ULL;
@@ -649,7 +594,7 @@
char buffer[5120];
- snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list);
+ snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : "");
fp = popen(buffer, "r");
if (fp == NULL) {
fprintf(stderr, "ERROR: %s\n", buffer);
@@ -662,10 +607,10 @@
++buf;
}
char *end = buf + strlen(buf);
- while (isspace(*--end) && (end >= buf)) {
+ while ((end > buf) && isspace(*--end)) {
*end = '\0';
}
- if (end < buf) {
+ if (end <= buf) {
continue;
}
fprintf(stderr, "%s\n", buf);
@@ -679,7 +624,7 @@
char *list = NULL;
char *adjust = NULL;
- ASSERT_EQ(true, get_white_black(&list));
+ get_white_black(&list);
static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
ASSERT_EQ(true, set_white_black(adjustment));
@@ -696,8 +641,8 @@
adjust = NULL;
ASSERT_EQ(true, set_white_black(list));
- ASSERT_EQ(true, get_white_black(&adjust));
- EXPECT_STREQ(list, adjust);
+ get_white_black(&adjust);
+ EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
free(adjust);
adjust = NULL;
diff --git a/logd/Android.mk b/logd/Android.mk
index 0235478..188511f 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -17,7 +17,8 @@
LogStatistics.cpp \
LogWhiteBlackList.cpp \
libaudit.c \
- LogAudit.cpp
+ LogAudit.cpp \
+ event.logtags
LOCAL_SHARED_LIBRARIES := \
libsysutils \
@@ -25,7 +26,7 @@
libcutils \
libutils
-LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags)
include $(BUILD_EXECUTABLE)
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index a7bf92b..d7088b4 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -21,6 +21,7 @@
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
+#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -66,11 +67,16 @@
, mBuf(*buf)
{ }
+static void setname() {
+ prctl(PR_SET_NAME, "logd.control");
+}
+
int CommandListener::ClearCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
+ setname();
+ uid_t uid = cli->getUid();
+ if (clientHasLogCredentials(cli)) {
+ uid = AID_ROOT;
}
if (argc < 2) {
@@ -84,7 +90,7 @@
return 0;
}
- mBuf.clear((log_id_t) id);
+ mBuf.clear((log_id_t) id, uid);
cli->sendMsg("success");
return 0;
}
@@ -96,6 +102,7 @@
int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
+ setname();
if (argc < 2) {
cli->sendMsg("Missing Argument");
return 0;
@@ -121,6 +128,7 @@
int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
+ setname();
if (!clientHasLogCredentials(cli)) {
cli->sendMsg("Permission Denied");
return 0;
@@ -154,6 +162,7 @@
int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
+ setname();
if (argc < 2) {
cli->sendMsg("Missing Argument");
return 0;
@@ -197,8 +206,8 @@
int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
+ setname();
uid_t uid = cli->getUid();
- gid_t gid = cli->getGid();
if (clientHasLogCredentials(cli)) {
uid = AID_ROOT;
}
@@ -236,6 +245,7 @@
int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
int /*argc*/, char ** /*argv*/) {
+ setname();
char *buf = NULL;
mBuf.formatPrune(&buf);
if (!buf) {
@@ -255,6 +265,7 @@
int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
+ setname();
if (!clientHasLogCredentials(cli)) {
cli->sendMsg("Permission Denied");
return 0;
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index ea6eece..f8d6162 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -16,9 +16,11 @@
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/klog.h>
+#include <sys/prctl.h>
#include <sys/uio.h>
#include "libaudit.h"
@@ -34,8 +36,14 @@
}
bool LogAudit::onDataAvailable(SocketClient *cli) {
+ prctl(PR_SET_NAME, "logd.auditd");
+
struct audit_message rep;
+ rep.nlh.nlmsg_type = 0;
+ rep.nlh.nlmsg_len = 0;
+ rep.data[0] = '\0';
+
if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
return false;
@@ -46,9 +54,6 @@
return true;
}
-#define AUDIT_LOG_ID LOG_ID_MAIN
-#define AUDIT_LOG_PRIO ANDROID_LOG_WARN
-
int LogAudit::logPrint(const char *fmt, ...) {
if (fmt == NULL) {
return -EINVAL;
@@ -65,6 +70,11 @@
return rc;
}
+ char *cp;
+ while ((cp = strstr(str, " "))) {
+ memmove(cp, cp + 1, strlen(cp + 1) + 1);
+ }
+
if (fdDmesg >= 0) {
struct iovec iov[2];
@@ -83,12 +93,11 @@
static const char audit_str[] = " audit(";
char *timeptr = strstr(str, audit_str);
- char *cp;
if (timeptr
&& ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
&& (*cp == ':')) {
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
- strcpy(timeptr + sizeof(audit_str) - 1 + 3, cp);
+ memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
} else {
now.strptime("", ""); // side effect of setting CLOCK_REALTIME
}
@@ -104,53 +113,88 @@
}
tid = pid;
uid = logbuf->pidToUid(pid);
- strcpy(pidptr, cp);
+ memmove(pidptr, cp, strlen(cp) + 1);
}
- static const char comm_str[] = " comm=\"";
- char *comm = strstr(str, comm_str);
- if (comm) {
- cp = comm;
- comm += sizeof(comm_str) - 1;
- char *ecomm = strchr(comm, '"');
- if (ecomm) {
- *ecomm = '\0';
- }
- comm = strdup(comm);
- if (ecomm) {
- strcpy(cp, ecomm + 1);
- }
- } else if (pid == getpid()) {
- pid = tid;
- comm = strdup("auditd");
- } else if (!(comm = logbuf->pidToName(pid))) {
- comm = strdup("unknown");
- }
+ // log to events
- size_t l = strlen(comm) + 1;
- size_t n = l + strlen(str) + 2;
+ size_t l = strlen(str);
+ size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
+
+ bool notify = false;
char *newstr = reinterpret_cast<char *>(malloc(n));
if (!newstr) {
- free(comm);
- free(str);
- return -ENOMEM;
+ rc = -ENOMEM;
+ } else {
+ cp = newstr;
+ *cp++ = AUDITD_LOG_TAG & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
+ *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
+ *cp++ = EVENT_TYPE_STRING;
+ *cp++ = l & 0xFF;
+ *cp++ = (l >> 8) & 0xFF;
+ *cp++ = (l >> 16) & 0xFF;
+ *cp++ = (l >> 24) & 0xFF;
+ memcpy(cp, str, l);
+
+ logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ free(newstr);
+
+ notify = true;
}
- *newstr = AUDIT_LOG_PRIO;
- strcpy(newstr + 1, comm);
- free(comm);
- strcpy(newstr + 1 + l, str);
+ // log to main
+
+ static const char comm_str[] = " comm=\"";
+ const char *comm = strstr(str, comm_str);
+ const char *estr = str + strlen(str);
+ if (comm) {
+ estr = comm;
+ comm += sizeof(comm_str) - 1;
+ } else if (pid == getpid()) {
+ pid = tid;
+ comm = "auditd";
+ } else if (!(comm = logbuf->pidToName(pid))) {
+ comm = "unknown";
+ }
+
+ const char *ecomm = strchr(comm, '"');
+ if (ecomm) {
+ ++ecomm;
+ l = ecomm - comm;
+ } else {
+ l = strlen(comm) + 1;
+ ecomm = "";
+ }
+ n = (estr - str) + strlen(ecomm) + l + 2;
+
+ newstr = reinterpret_cast<char *>(malloc(n));
+ if (!newstr) {
+ rc = -ENOMEM;
+ } else {
+ *newstr = (strstr(str, " permissive=1")
+ || strstr(str, " policy loaded "))
+ ? ANDROID_LOG_INFO
+ : ANDROID_LOG_WARN;
+ strlcpy(newstr + 1, comm, l);
+ strncpy(newstr + 1 + l, str, estr - str);
+ strcpy(newstr + 1 + l + (estr - str), ecomm);
+
+ logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ free(newstr);
+
+ notify = true;
+ }
+
free(str);
- unsigned short len = n; // cap to internal maximum
- if (len != n) {
- len = -1;
+ if (notify) {
+ reader->notifyNewLog();
}
- logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr, len);
- reader->notifyNewLog();
-
- free(newstr);
return rc;
}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 8dcab87..cd9ea20 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -14,29 +14,121 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/user.h>
#include <time.h>
#include <unistd.h>
+#include <cutils/properties.h>
#include <log/logger.h>
#include "LogBuffer.h"
+#include "LogReader.h"
#include "LogStatistics.h"
#include "LogWhiteBlackList.h"
-#include "LogReader.h"
// Default
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
#define log_buffer_size(id) mMaxSize[id]
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+
+static bool valid_size(unsigned long value) {
+ if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+ return false;
+ }
+
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pages < 1) {
+ return true;
+ }
+
+ long pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize <= 1) {
+ pagesize = PAGE_SIZE;
+ }
+
+ // maximum memory impact a somewhat arbitrary ~3%
+ pages = (pages + 31) / 32;
+ unsigned long maximum = pages * pagesize;
+
+ if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+ return true;
+ }
+
+ return value <= maximum;
+}
+
+static unsigned long property_get_size(const char *key) {
+ char property[PROPERTY_VALUE_MAX];
+ property_get(key, property, "");
+
+ char *cp;
+ unsigned long value = strtoul(property, &cp, 10);
+
+ switch(*cp) {
+ case 'm':
+ case 'M':
+ value *= 1024;
+ /* FALLTHRU */
+ case 'k':
+ case 'K':
+ value *= 1024;
+ /* FALLTHRU */
+ case '\0':
+ break;
+
+ default:
+ value = 0;
+ }
+
+ if (!valid_size(value)) {
+ value = 0;
+ }
+
+ return value;
+}
LogBuffer::LogBuffer(LastLogTimes *times)
: mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
dgram_qlen_statistics = false;
+ static const char global_tuneable[] = "persist.logd.size"; // Settings App
+ static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
+
+ unsigned long default_size = property_get_size(global_tuneable);
+ if (!default_size) {
+ default_size = property_get_size(global_default);
+ }
+
log_id_for_each(i) {
- mMaxSize[i] = LOG_BUFFER_SIZE;
+ char key[PROP_NAME_MAX];
+
+ snprintf(key, sizeof(key), "%s.%s",
+ global_tuneable, android_log_id_to_name(i));
+ unsigned long property_size = property_get_size(key);
+
+ if (!property_size) {
+ snprintf(key, sizeof(key), "%s.%s",
+ global_default, android_log_id_to_name(i));
+ property_size = property_get_size(key);
+ }
+
+ if (!property_size) {
+ property_size = default_size;
+ }
+
+ if (!property_size) {
+ property_size = LOG_BUFFER_SIZE;
+ }
+
+ if (setSize(i, property_size)) {
+ setSize(i, LOG_BUFFER_MIN_SIZE);
+ }
}
}
@@ -82,7 +174,7 @@
if (last == mLogElements.end()) {
mLogElements.push_back(elem);
} else {
- log_time end;
+ log_time end = log_time::EPOCH;
bool end_set = false;
bool end_always = false;
@@ -140,7 +232,7 @@
// prune "pruneRows" of type "id" from the buffer.
//
// mLogElementsLock must be held when this function is called.
-void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
+void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogTimeEntry *oldest = NULL;
LogTimeEntry::lock();
@@ -158,6 +250,38 @@
LogBufferElementCollection::iterator it;
+ if (caller_uid != AID_ROOT) {
+ for(it = mLogElements.begin(); it != mLogElements.end();) {
+ LogBufferElement *e = *it;
+
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ break;
+ }
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
+ }
+
+ uid_t uid = e->getUid();
+
+ if (uid == caller_uid) {
+ it = mLogElements.erase(it);
+ unsigned short len = e->getMsgLen();
+ stats.subtract(len, id, uid, e->getPid());
+ delete e;
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+ } else {
+ ++it;
+ }
+ }
+ LogTimeEntry::unlock();
+ return;
+ }
+
// prune by worst offender by uid
while (pruneRows > 0) {
// recalculate the worst offender on every batched pass
@@ -167,17 +291,14 @@
if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
LidStatistics &l = stats.id(id);
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- UidStatistics *u = (*iu);
- size_t sizes = u->sizes();
- if (worst_sizes < sizes) {
- second_worst_sizes = worst_sizes;
- worst_sizes = sizes;
- worst = u->getUid();
- }
- if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
- second_worst_sizes = sizes;
+ l.sort();
+ UidStatisticsCollection::iterator iu = l.begin();
+ if (iu != l.end()) {
+ UidStatistics *u = *iu;
+ worst = u->getUid();
+ worst_sizes = u->sizes();
+ if (++iu != l.end()) {
+ second_worst_sizes = (*iu)->sizes();
}
}
}
@@ -286,9 +407,9 @@
}
// clear all rows of type "id" from the buffer.
-void LogBuffer::clear(log_id_t id) {
+void LogBuffer::clear(log_id_t id, uid_t uid) {
pthread_mutex_lock(&mLogElementsLock);
- prune(id, ULONG_MAX);
+ prune(id, ULONG_MAX, uid);
pthread_mutex_unlock(&mLogElementsLock);
}
@@ -303,7 +424,7 @@
// set the total space allocated to "id"
int LogBuffer::setSize(log_id_t id, unsigned long size) {
// Reasonable limits ...
- if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
+ if (!valid_size(size)) {
return -1;
}
pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index b8a54b9..4b982a8 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -23,6 +23,8 @@
#include <sysutils/SocketClient.h>
#include <utils/List.h>
+#include <private/android_filesystem_config.h>
+
#include "LogBufferElement.h"
#include "LogTimes.h"
#include "LogStatistics.h"
@@ -55,7 +57,7 @@
bool (*filter)(const LogBufferElement *element, void *arg) = NULL,
void *arg = NULL);
- void clear(log_id_t id);
+ void clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
int setSize(log_id_t id, unsigned long size);
unsigned long getSizeUsed(log_id_t id);
@@ -77,7 +79,7 @@
private:
void maybePrune(log_id_t id);
- void prune(log_id_t id, unsigned long pruneRows);
+ void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
};
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 0873e63..e4c138e 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -64,7 +64,7 @@
}
gid_t gid = cli->getGid();
- if ((gid == AID_ROOT) || (gid == AID_LOG)) {
+ if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
return true;
}
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index ed5b391..8186cea 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <limits.h>
+#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
@@ -31,7 +33,9 @@
{ }
bool LogListener::onDataAvailable(SocketClient *cli) {
- char buffer[sizeof_log_id_t + sizeof(log_time) + sizeof(char)
+ prctl(PR_SET_NAME, "logd.writer");
+
+ char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
+ LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
memset(buffer, 0, sizeof(buffer));
@@ -97,11 +101,10 @@
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
- unsigned short len = n; // cap to internal maximum
- if (len == n) {
- logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg, len);
- reader->notifyNewLog();
- }
+
+ logbuf->log(log_id, realtime, cred->uid, cred->pid, tid, msg,
+ ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ reader->notifyNewLog();
return true;
}
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 51aa2ad..8458c19 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -16,6 +16,7 @@
#include <ctype.h>
#include <poll.h>
+#include <sys/prctl.h>
#include <sys/socket.h>
#include <cutils/sockets.h>
@@ -36,6 +37,8 @@
}
bool LogReader::onDataAvailable(SocketClient *cli) {
+ prctl(PR_SET_NAME, "logd.reader");
+
char buffer[255];
int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 5146030..81c9bab 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -31,6 +31,7 @@
, mSizes(0)
, mElements(0)
, name(name)
+ , mGone(false)
{ }
#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
@@ -41,6 +42,7 @@
, mElementsTotal(copy->mElementsTotal)
, mSizes(copy->mSizes)
, mElements(copy->mElements)
+ , mGone(copy->mGone)
{ }
#endif
@@ -48,6 +50,20 @@
free(name);
}
+bool PidStatistics::pidGone() {
+ if (mGone) {
+ return true;
+ }
+ if (pid == gone) {
+ return true;
+ }
+ if (kill(pid, 0) && (errno != EPERM)) {
+ mGone = true;
+ return true;
+ }
+ return false;
+}
+
void PidStatistics::setName(char *new_name) {
free(name);
name = new_name;
@@ -63,7 +79,7 @@
bool PidStatistics::subtract(unsigned short size) {
mSizes -= size;
--mElements;
- return (mElements == 0) && kill(pid, 0) && (errno != EPERM);
+ return (mElements == 0) && pidGone();
}
void PidStatistics::addTotal(size_t size, size_t element) {
@@ -76,7 +92,7 @@
// must call free to release return value
char *PidStatistics::pidToName(pid_t pid) {
char *retval = NULL;
- if (pid != PidStatistics::gone) {
+ if (pid != gone) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
@@ -96,7 +112,9 @@
}
UidStatistics::UidStatistics(uid_t uid)
- : uid(uid) {
+ : uid(uid)
+ , mSizes(0)
+ , mElements(0) {
Pids.clear();
}
@@ -109,6 +127,9 @@
}
void UidStatistics::add(unsigned short size, pid_t pid) {
+ mSizes += size;
+ ++mElements;
+
PidStatistics *p;
PidStatisticsCollection::iterator last;
PidStatisticsCollection::iterator it;
@@ -116,18 +137,11 @@
p = *it;
if (pid == p->getPid()) {
p->add(size);
- // poor-man sort, bubble upwards if bigger than last
- if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) {
- Pids.erase(it);
- Pids.insert(last, p);
- }
return;
}
}
- // poor-man sort, insert if bigger than last or last is the gone entry.
- bool insert = (last != it)
- && ((p->getPid() == p->gone)
- || ((*last)->sizesTotal() < (size_t) size));
+ // insert if the gone entry.
+ bool insert = (last != it) && (p->getPid() == p->gone);
p = new PidStatistics(pid, pidToName(pid));
if (insert) {
Pids.insert(last, p);
@@ -138,6 +152,9 @@
}
void UidStatistics::subtract(unsigned short size, pid_t pid) {
+ mSizes -= size;
+ --mElements;
+
PidStatisticsCollection::iterator it;
for (it = begin(); it != end(); ++it) {
PidStatistics *p = *it;
@@ -166,28 +183,57 @@
}
}
+void UidStatistics::sort() {
+ for (bool pass = true; pass;) {
+ pass = false;
+ PidStatisticsCollection::iterator it = begin();
+ if (it != end()) {
+ PidStatisticsCollection::iterator lt = it;
+ PidStatistics *l = (*lt);
+ while (++it != end()) {
+ PidStatistics *n = (*it);
+ if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
+ pass = true;
+ Pids.erase(it);
+ Pids.insert(lt, n);
+ it = lt;
+ n = l;
+ }
+ lt = it;
+ l = n;
+ }
+ }
+ }
+}
+
size_t UidStatistics::sizes(pid_t pid) {
- size_t sizes = 0;
+ if (pid == pid_all) {
+ return sizes();
+ }
+
PidStatisticsCollection::iterator it;
for (it = begin(); it != end(); ++it) {
PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- sizes += p->sizes();
+ if (pid == p->getPid()) {
+ return p->sizes();
}
}
- return sizes;
+ return 0;
}
size_t UidStatistics::elements(pid_t pid) {
- size_t elements = 0;
+ if (pid == pid_all) {
+ return elements();
+ }
+
PidStatisticsCollection::iterator it;
for (it = begin(); it != end(); ++it) {
PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- elements += p->elements();
+ if (pid == p->getPid()) {
+ return p->elements();
}
}
- return elements;
+ return 0;
}
size_t UidStatistics::sizesTotal(pid_t pid) {
@@ -266,6 +312,29 @@
}
}
+void LidStatistics::sort() {
+ for (bool pass = true; pass;) {
+ pass = false;
+ UidStatisticsCollection::iterator it = begin();
+ if (it != end()) {
+ UidStatisticsCollection::iterator lt = it;
+ UidStatistics *l = (*lt);
+ while (++it != end()) {
+ UidStatistics *n = (*it);
+ if (n->sizes() > l->sizes()) {
+ pass = true;
+ Uids.erase(it);
+ Uids.insert(lt, n);
+ it = lt;
+ n = l;
+ }
+ lt = it;
+ l = n;
+ }
+ }
+ }
+}
+
size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
size_t sizes = 0;
UidStatisticsCollection::iterator it;
@@ -323,8 +392,8 @@
dgram_qlen_statistics = false;
for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) {
- mMinimum[bucket].tv_sec = (uint32_t)-1;
- mMinimum[bucket].tv_nsec = 999999999UL;
+ mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
+ mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
}
}
@@ -370,7 +439,7 @@
}
unsigned long long LogStatistics::minimum(unsigned short bucket) {
- if (mMinimum[bucket].tv_sec == LONG_MAX) {
+ if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
return 0;
}
return mMinimum[bucket].nsec();
@@ -455,13 +524,22 @@
short spaces = 2;
log_id_for_each(i) {
- if (logMask & (1 << i)) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
- spaces += spaces_total + oldLength - string.length();
+ if (!logMask & (1 << i)) {
+ continue;
+ }
+ oldLength = string.length();
+ if (spaces < 0) {
+ spaces = 0;
+ }
+ string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
+ spaces += spaces_total + oldLength - string.length();
+
+ LidStatistics &l = id(i);
+ l.sort();
+
+ UidStatisticsCollection::iterator iu;
+ for (iu = l.begin(); iu != l.end(); ++iu) {
+ (*iu)->sort();
}
}
@@ -597,8 +675,7 @@
sizes, sizesTotal);
android::String8 pd("");
- pd.appendFormat("%u%c", pid,
- (kill(pid, 0) && (errno != EPERM)) ? '?' : ' ');
+ pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
string.appendFormat("\n%-7s%-*s %-7s%s",
line ? "" : android_log_id_to_name(i),
@@ -703,14 +780,15 @@
spaces = 0;
uid_t u = up->getUid();
- pid_t p = (*pt)->getPid();
+ PidStatistics *pp = *pt;
+ pid_t p = pp->getPid();
intermediate = string.format(oneline
? ((p == PidStatistics::gone)
? "%d/?"
- : "%d/%d")
+ : "%d/%d%c")
: "%d",
- u, p);
+ u, p, pp->pidGone() ? '?' : '\0');
string.appendFormat(first ? "\n%-12s" : "%-12s",
intermediate.string());
intermediate.clear();
@@ -747,8 +825,8 @@
size_t gone_els = 0;
for(; pt != up->end(); ++pt) {
- PidStatistics *pp = *pt;
- pid_t p = pp->getPid();
+ pp = *pt;
+ p = pp->getPid();
// If a PID no longer has any current logs, and is not
// active anymore, skip & report totals for gone.
@@ -760,7 +838,7 @@
continue;
}
els = pp->elements();
- bool gone = kill(p, 0) && (errno != EPERM);
+ bool gone = pp->pidGone();
if (gone && (els == 0)) {
// ToDo: garbage collection: move this statistical bucket
// from its current UID/PID to UID/? (races and
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 12c68d5..3733137 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -37,6 +37,7 @@
size_t mElements;
char *name;
+ bool mGone;
public:
static const pid_t gone = (pid_t) -1;
@@ -46,6 +47,7 @@
~PidStatistics();
pid_t getPid() const { return pid; }
+ bool pidGone();
char *getName() const { return name; }
void setName(char *name);
@@ -70,6 +72,9 @@
PidStatisticsCollection Pids;
+ size_t mSizes;
+ size_t mElements;
+
public:
UidStatistics(uid_t uid);
~UidStatistics();
@@ -81,11 +86,17 @@
void add(unsigned short size, pid_t pid);
void subtract(unsigned short size, pid_t pid);
+ void sort();
static const pid_t pid_all = (pid_t) -1;
- size_t sizes(pid_t pid = pid_all);
- size_t elements(pid_t pid = pid_all);
+ // fast track current value
+ size_t sizes() const { return mSizes; };
+ size_t elements() const { return mElements; };
+
+ // statistical track
+ size_t sizes(pid_t pid);
+ size_t elements(pid_t pid);
size_t sizesTotal(pid_t pid = pid_all);
size_t elementsTotal(pid_t pid = pid_all);
@@ -108,6 +119,7 @@
void add(unsigned short size, uid_t uid, pid_t pid);
void subtract(unsigned short size, uid_t uid, pid_t pid);
+ void sort();
static const pid_t pid_all = (pid_t) -1;
static const uid_t uid_all = (uid_t) -1;
@@ -145,6 +157,7 @@
void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid);
+ void sort();
// fast track current value by id only
size_t sizes(log_id_t id) const { return mSizes[id]; }
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index c32ac2d..e7e3ec2 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <sys/prctl.h>
+
#include "FlushCommand.h"
#include "LogBuffer.h"
#include "LogTimes.h"
@@ -107,6 +109,8 @@
}
void *LogTimeEntry::threadStart(void *obj) {
+ prctl(PR_SET_NAME, "logd.reader.per");
+
LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj);
pthread_cleanup_push(threadStop, obj);
@@ -189,6 +193,7 @@
if (me->skipAhead) {
me->skipAhead--;
+ goto skip;
}
me->mStart = element->getMonotonicTime();
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index f739865..e87b604 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -65,7 +65,7 @@
}
int PruneList::init(char *str) {
- mWorstUidEnabled = true;
+ mWorstUidEnabled = false;
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end();) {
delete (*it);
diff --git a/logd/README.property b/logd/README.property
new file mode 100644
index 0000000..f4b3c3c
--- /dev/null
+++ b/logd/README.property
@@ -0,0 +1,25 @@
+The properties that logd responds to are:
+
+name type default description
+logd.auditd bool true Enable selinux audit daemon
+logd.auditd.dmesg bool true selinux audit messages duplicated and
+ sent on to dmesg log
+logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This
+ represents a performance impact and
+ is used to determine the platform's
+ minimum domain socket network FIFO
+ size (see source for details) based
+ on typical load (logcat -S to view)
+persist.logd.size number 256K default size of the buffer for all
+ log ids at initial startup, at runtime
+ use: logcat -b all -G <value>
+persist.logd.size.main number 256K Size of the buffer for the main log
+persist.logd.size.system number 256K Size of the buffer for the system log
+persist.logd.size.radio number 256K Size of the buffer for the radio log
+persist.logd.size.event number 256K Size of the buffer for the event log
+persist.logd.size.crash number 256K Size of the buffer for the crash log
+
+NB:
+- number support multipliers (K or M) for convenience. Range is limited
+ to between 64K and 256M for log buffer sizes. Individual logs override the
+ global default.
diff --git a/logd/event.logtags b/logd/event.logtags
new file mode 100644
index 0000000..a63f034
--- /dev/null
+++ b/logd/event.logtags
@@ -0,0 +1,36 @@
+# The entries in this file map a sparse set of log tag numbers to tag names.
+# This is installed on the device, in /system/etc, and parsed by logcat.
+#
+# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
+# negative values alone for now.)
+#
+# Tag names are one or more ASCII letters and numbers or underscores, i.e.
+# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
+# impacts log readability, the latter makes regex searches more annoying).
+#
+# Tag numbers and names are separated by whitespace. Blank lines and lines
+# starting with '#' are ignored.
+#
+# Optionally, after the tag names can be put a description for the value(s)
+# of the tag. Description are in the format
+# (<name>|data type[|data unit])
+# Multiple values are separated by commas.
+#
+# The data type is a number from the following values:
+# 1: int
+# 2: long
+# 3: string
+# 4: list
+#
+# The data unit is a number taken from the following list:
+# 1: Number of objects
+# 2: Number of bytes
+# 3: Number of milliseconds
+# 4: Number of allocations
+# 5: Id
+# 6: Percent
+# Default value for data of type int/long is 2 (bytes).
+#
+# TODO: generate ".java" and ".h" files with integer constants from this file.
+
+1003 auditd (avc|3)
diff --git a/logd/main.cpp b/logd/main.cpp
index 04eef4a..ece5a3a 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -107,16 +107,31 @@
return 0;
}
+// Property helper
+static bool property_get_bool(const char *key, bool def) {
+ char property[PROPERTY_VALUE_MAX];
+ property_get(key, property, "");
+
+ if (!strcasecmp(property, "true")) {
+ return true;
+ }
+ if (!strcasecmp(property, "false")) {
+ return false;
+ }
+
+ return def;
+}
+
// Foreground waits for exit of the three main persistent threads that
// are started here. The three threads are created to manage UNIX
// domain client sockets for writing, reading and controlling the user
// space logger. Additional transitory per-client threads are created
// for each reader once they register.
int main() {
+ bool auditd = property_get_bool("logd.auditd", true);
+
int fdDmesg = -1;
- char dmesg[PROPERTY_VALUE_MAX];
- property_get("logd.auditd.dmesg", dmesg, "1");
- if (atol(dmesg)) {
+ if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
fdDmesg = open("/dev/kmsg", O_WRONLY);
}
@@ -135,9 +150,7 @@
LogBuffer *logBuf = new LogBuffer(times);
- char dgram_qlen_statistics[PROPERTY_VALUE_MAX];
- property_get("logd.dgram_qlen.statistics", dgram_qlen_statistics, "");
- if (atol(dgram_qlen_statistics)) {
+ if (property_get_bool("logd.statistics.dgram_qlen", false)) {
logBuf->enableDgramQlenStatistics();
}
@@ -171,11 +184,13 @@
// initiated log messages. New log entries are added to LogBuffer
// and LogReader is notified to send updates to connected clients.
- // failure is an option ... messages are in dmesg (required by standard)
- LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
- if (al->startListener()) {
- delete al;
- close(fdDmesg);
+ if (auditd) {
+ // failure is an option ... messages are in dmesg (required by standard)
+ LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+ if (al->startListener()) {
+ delete al;
+ close(fdDmesg);
+ }
}
pause();
diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk
index 123e317..f851288 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -34,7 +34,7 @@
-Werror \
-fno-builtin \
-ifeq ($(TARGET_USES_LOGD),true)
+ifneq ($(TARGET_USES_LOGD),false)
test_c_flags += -DTARGET_USES_LOGD=1
endif
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 23e6146..957fdb5 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
#include "cutils/sockets.h"
+#include "log/log.h"
#include "log/logger.h"
#define __unused __attribute__((__unused__))
@@ -96,8 +97,9 @@
//
// main: UID/PID Total size/num Now UID/PID[?] Total
// 0 7500306/304207 71608/3183 0/4225? 7454388/303656
+ // <wrap> 93432/1012
// -or-
- // 0/gone 7454388/303656
+ // 0/gone 7454388/303656 93432/1012
//
// basically if we see a *large* number of 0/????? entries
unsigned long value;
@@ -126,6 +128,15 @@
value = value * 10ULL + *cp - '0';
++cp;
}
+ if (*cp != '/') {
+ value = 0;
+ continue;
+ }
+ while (isdigit(*++cp));
+ while (*cp == ' ') ++cp;
+ if (!isdigit(*cp)) {
+ value = 0;
+ }
}
} while ((value < 900000ULL) && *cp);
return cp;
@@ -185,8 +196,6 @@
cp = strstr(cp, "Minimum time between log events per dgram_qlen:");
- char *log_events_per_span = cp;
-
if (cp) {
while (*cp && (*cp != '\n')) {
++cp;
@@ -451,7 +460,7 @@
dump_log_msg("user", &msg, 3, -1);
}
- alarm(0);
+ alarm(old_alarm);
sigaction(SIGALRM, &old_sigaction, NULL);
close(fd);
@@ -559,10 +568,11 @@
while (fgets(buffer, sizeof(buffer), fp)) {
for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) {
- if (strncmp(benchmarks[i], buffer, strlen(benchmarks[i]))) {
+ char *cp = strstr(buffer, benchmarks[i]);
+ if (!cp) {
continue;
}
- sscanf(buffer, "%*s %lu %lu", &ns[i], &ns[i]);
+ sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
}
}
@@ -583,15 +593,15 @@
#endif
#ifdef TARGET_USES_LOGD
- EXPECT_GE(25000UL, ns[log_maximum]); // 14055 user
+ EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user
#else
EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel
#endif
- EXPECT_GE(4000UL, ns[clock_overhead]); // 2008
+ EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
#ifdef TARGET_USES_LOGD
- EXPECT_GE(250000UL, ns[log_overhead]); // 113219 user
+ EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user
#else
EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel
#endif
@@ -603,7 +613,7 @@
#endif
#ifdef TARGET_USES_LOGD
- EXPECT_GE(20000000UL, ns[log_delay]); // 9542541 user
+ EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
#else
EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel
#endif
@@ -624,7 +634,70 @@
#endif
ASSERT_TRUE(NULL != buf);
- EXPECT_TRUE(find_benchmark_spam(buf) != NULL);
+
+ char *benchmark_statistics_found = find_benchmark_spam(buf);
+ ASSERT_TRUE(benchmark_statistics_found != NULL);
+
+ // Check how effective the SPAM filter is, parse out Now size.
+ // Total Now
+ // 0/4225? 7454388/303656 31488/755
+ // ^-- benchmark_statistics_found
+
+ unsigned long nowSpamSize = atol(benchmark_statistics_found);
delete [] buf;
+
+ ASSERT_NE(0UL, nowSpamSize);
+
+ // Determine if we have the spam filter enabled
+ int sock = socket_local_client("logd",
+ ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+
+ ASSERT_TRUE(sock >= 0);
+
+ static const char getPruneList[] = "getPruneList";
+ if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
+ char buffer[80];
+ memset(buffer, 0, sizeof(buffer));
+ read(sock, buffer, sizeof(buffer));
+ char *cp = strchr(buffer, '\n');
+ if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
+ close(sock);
+ fprintf(stderr,
+ "WARNING: "
+ "Logger has SPAM filtration turned off \"%s\"\n", buffer);
+ return;
+ }
+ } else {
+ int save_errno = errno;
+ close(sock);
+ FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno);
+ }
+
+ static const unsigned long expected_absolute_minimum_log_size = 65536UL;
+ unsigned long totalSize = expected_absolute_minimum_log_size;
+ static const char getSize[] = {
+ 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ',
+ LOG_ID_MAIN + '0', '\0'
+ };
+ if (write(sock, getSize, sizeof(getSize)) > 0) {
+ char buffer[80];
+ memset(buffer, 0, sizeof(buffer));
+ read(sock, buffer, sizeof(buffer));
+ totalSize = atol(buffer);
+ if (totalSize < expected_absolute_minimum_log_size) {
+ fprintf(stderr,
+ "WARNING: "
+ "Logger had unexpected referenced size \"%s\"\n", buffer);
+ totalSize = expected_absolute_minimum_log_size;
+ }
+ }
+ close(sock);
+
+ // logd allows excursions to 110% of total size
+ totalSize = (totalSize * 11 ) / 10;
+
+ // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
+ ASSERT_GT(totalSize, nowSpamSize * 2);
}
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 917bf37..61b4659 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -11,6 +11,7 @@
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
# ========================================================
@@ -22,6 +23,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
# ========================================================
@@ -31,4 +33,5 @@
LOCAL_SRC_FILES:= logwrapper.c
LOCAL_MODULE := logwrapper
LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 4ca1db4..d47c9b5 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -104,8 +104,6 @@
static int add_line_to_linear_buf(struct beginning_buf *b_buf,
char *line, ssize_t line_len)
{
- size_t new_len;
- char *new_buf;
int full = 0;
if ((line_len + b_buf->used_len) > b_buf->buf_size) {
@@ -124,7 +122,6 @@
{
ssize_t free_len;
ssize_t needed_space;
- char *new_buf;
int cnt;
if (e_buf->buf == NULL) {
@@ -192,7 +189,6 @@
{
char *line_start;
char c;
- int line_len;
int i;
line_start = buf;
diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk
index 2a97c26..0c9b0c6 100644
--- a/mkbootimg/Android.mk
+++ b/mkbootimg/Android.mk
@@ -4,6 +4,7 @@
LOCAL_SRC_FILES := mkbootimg.c
LOCAL_STATIC_LIBRARIES := libmincrypt
+LOCAL_CFLAGS := -Werror
LOCAL_MODULE := mkbootimg
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index d598f03..fc92b4d 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -77,7 +77,7 @@
int write_padding(int fd, unsigned pagesize, unsigned itemsize)
{
unsigned pagemask = pagesize - 1;
- unsigned count;
+ ssize_t count;
if((itemsize & pagemask) == 0) {
return 0;
@@ -108,7 +108,7 @@
unsigned pagesize = 2048;
int fd;
SHA_CTX ctx;
- uint8_t* sha;
+ const uint8_t* sha;
unsigned base = 0x10000000;
unsigned kernel_offset = 0x00008000;
unsigned ramdisk_offset = 0x01000000;
@@ -189,7 +189,7 @@
return usage();
}
- strcpy(hdr.name, board);
+ strcpy((char *) hdr.name, board);
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
@@ -255,15 +255,15 @@
if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
- if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
+ if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
- if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
+ if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
if(second_data) {
- if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
- if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
+ if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
+ if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
}
return 0;
diff --git a/netcfg/Android.mk b/netcfg/Android.mk
index 949f417..fc01a54 100644
--- a/netcfg/Android.mk
+++ b/netcfg/Android.mk
@@ -11,6 +11,7 @@
#LOCAL_STATIC_LIBRARIES := libcutils libc
LOCAL_SHARED_LIBRARIES := libc libnetutils
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
endif
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 3738f24..2308f37 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -1,5 +1,4 @@
-/* system/bin/netcfg/netcfg.c
-**
+/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,18 +14,14 @@
** limitations under the License.
*/
-#include <stdio.h>
-#include <stdlib.h>
#include <errno.h>
#include <dirent.h>
#include <netinet/ether.h>
#include <netinet/if_ether.h>
-
-#include <netutils/ifc.h>
#include <netutils/dhcp.h>
-
-static int verbose = 0;
-
+#include <netutils/ifc.h>
+#include <stdio.h>
+#include <stdlib.h>
void die(const char *reason)
{
diff --git a/reboot/Android.mk b/reboot/Android.mk
index 4db0c1e..7a24f99 100644
--- a/reboot/Android.mk
+++ b/reboot/Android.mk
@@ -1,12 +1,14 @@
# Copyright 2013 The Android Open Source Project
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= reboot.c
+LOCAL_SRC_FILES := reboot.c
-LOCAL_SHARED_LIBRARIES:= libcutils
+LOCAL_SHARED_LIBRARIES := libcutils
-LOCAL_MODULE:= reboot
+LOCAL_MODULE := reboot
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2c16084..aca08bf 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,9 +30,17 @@
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
+# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
+bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM)))
+bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
+$(bcp_dep) :
+ $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
+bcp_md5 :=
+bcp_dep :=
#######################################
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 927c33d..1f964e3 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -9,3 +9,4 @@
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH %BOOTCLASSPATH%
+ export LD_PRELOAD libsigchain.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0ef097c..e2bc5b3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -26,29 +26,28 @@
start ueventd
-# create mountpoints
+ # create mountpoints
mkdir /mnt 0775 root system
on init
+ sysclktz 0
-sysclktz 0
+ loglevel 3
-loglevel 3
-
-# Backward compatibility
+ # Backward compatibility
symlink /system/etc /etc
symlink /sys/kernel/debug /d
-# Right now vendor lives on the same filesystem as system,
-# but someday that may change.
+ # Right now vendor lives on the same filesystem as system,
+ # but someday that may change.
symlink /system/vendor /vendor
-# Create cgroup mount point for cpu accounting
+ # Create cgroup mount point for cpu accounting
mkdir /acct
mount cgroup none /acct cpuacct
mkdir /acct/uid
-# Create cgroup mount point for memory
+ # Create cgroup mount point for memory
mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
mkdir /sys/fs/cgroup/memory 0750 root system
mount cgroup none /sys/fs/cgroup/memory memory
@@ -98,14 +97,20 @@
write /proc/sys/kernel/sched_child_runs_first 0
write /proc/sys/kernel/randomize_va_space 2
write /proc/sys/kernel/kptr_restrict 2
- write /proc/sys/kernel/dmesg_restrict 1
write /proc/sys/vm/mmap_min_addr 32768
write /proc/sys/net/ipv4/ping_group_range "0 2147483647"
write /proc/sys/net/unix/max_dgram_qlen 300
write /proc/sys/kernel/sched_rt_runtime_us 950000
write /proc/sys/kernel/sched_rt_period_us 1000000
-# Create cgroup mount points for process groups
+ # reflect fwmark from incoming packets onto generated replies
+ write /proc/sys/net/ipv4/fwmark_reflect 1
+ write /proc/sys/net/ipv6/fwmark_reflect 1
+
+ # set fwmark on accepted sockets
+ write /proc/sys/net/ipv4/tcp_fwmark_accept 1
+
+ # Create cgroup mount points for process groups
mkdir /dev/cpuctl
mount cgroup none /dev/cpuctl cpu
chown system system /dev/cpuctl
@@ -130,20 +135,50 @@
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
-# qtaguid will limit access to specific data based on group memberships.
-# net_bw_acct grants impersonation of socket owners.
-# net_bw_stats grants access to other apps' detailed tagged-socket stats.
+ # qtaguid will limit access to specific data based on group memberships.
+ # net_bw_acct grants impersonation of socket owners.
+ # net_bw_stats grants access to other apps' detailed tagged-socket stats.
chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
chown root net_bw_stats /proc/net/xt_qtaguid/stats
-# Allow everybody to read the xt_qtaguid resource tracking misc dev.
-# This is needed by any process that uses socket tagging.
+ # Allow everybody to read the xt_qtaguid resource tracking misc dev.
+ # This is needed by any process that uses socket tagging.
chmod 0644 /dev/xt_qtaguid
-# Create location for fs_mgr to store abbreviated output from filesystem
-# checker programs.
+ # Create location for fs_mgr to store abbreviated output from filesystem
+ # checker programs.
mkdir /dev/fscklogs 0770 root system
+ # pstore/ramoops previous console log
+ mount pstore pstore /sys/fs/pstore
+ chown system log /sys/fs/pstore/console-ramoops
+ chmod 0440 /sys/fs/pstore/console-ramoops
+
+# Healthd can trigger a full boot from charger mode by signaling this
+# property when the power button is held.
+on property:sys.boot_from_charger_mode=1
+ class_stop charger
+ trigger late-init
+
+# Load properties from /system/ + /factory after fs mount.
+on load_all_props_action
+ load_all_props
+
+# Mount filesystems and start core system services.
+on late-init
+ trigger early-fs
+ trigger fs
+ trigger post-fs
+ trigger post-fs-data
+
+ # Load properties from /system/ + /factory after fs mount. Place
+ # this in another action so that the load will be scheduled after the prior
+ # issued fs triggers have completed.
+ trigger load_all_props_action
+
+ trigger early-boot
+ trigger boot
+
on post-fs
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
@@ -154,13 +189,11 @@
chown system cache /cache
chmod 0770 /cache
# We restorecon /cache in case the cache partition has been reset.
- restorecon /cache
+ restorecon_recursive /cache
# This may have been created by the recovery system with odd permissions
chown system cache /cache/recovery
chmod 0770 /cache/recovery
- # This may have been created by the recovery system with the wrong context.
- restorecon /cache/recovery
#change permissions on vmallocinfo so we can grab it from bugreports
chown root log /proc/vmallocinfo
@@ -216,15 +249,18 @@
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/keychain 0771 system system
+ mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
mkdir /data/misc/sms 0770 system radio
mkdir /data/misc/zoneinfo 0775 system system
mkdir /data/misc/vpn 0770 system vpn
+ mkdir /data/misc/shared_relro 0771 shared_relro shared_relro
mkdir /data/misc/systemkeys 0700 system system
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
mkdir /data/misc/dhcp 0770 dhcp dhcp
+ mkdir /data/misc/user 0771 root root
# give system access to wpa_supplicant.conf for backup and restore
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
@@ -239,11 +275,10 @@
mkdir /data/app-lib 0771 system system
mkdir /data/app 0771 system system
mkdir /data/property 0700 root root
- mkdir /data/ssh 0750 root shell
- mkdir /data/ssh/empty 0700 root root
# create dalvik-cache, so as to enforce our permissions
mkdir /data/dalvik-cache 0771 system system
+ mkdir /data/dalvik-cache/profiles 0711 system system
# create resource-cache and double-check the perms
mkdir /data/resource-cache 0771 system system
@@ -280,17 +315,17 @@
#setprop vold.post_fs_data_done 1
on boot
-# basic network init
+ # basic network init
ifup lo
hostname localhost
domainname localdomain
-# set RLIMIT_NICE to allow priorities from 19 to -20
+ # set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
-# Memory management. Basic kernel parameters, and allow the high
-# level system server to be able to adjust the kernel OOM driver
-# parameters to match how it is managing things.
+ # Memory management. Basic kernel parameters, and allow the high
+ # level system server to be able to adjust the kernel OOM driver
+ # parameters to match how it is managing things.
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
chown root system /sys/module/lowmemorykiller/parameters/adj
@@ -366,8 +401,8 @@
chown system system /sys/kernel/ipv4/tcp_rmem_max
chown root radio /proc/cmdline
-# Define TCP buffer sizes for various networks
-# ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
+ # Define TCP buffer sizes for various networks
+ # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576
setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
@@ -381,12 +416,18 @@
setprop net.tcp.buffersize.gprs 4092,8760,48000,4096,8760,48000
setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144
+ # Define default initial receive window size in segments.
+ setprop net.tcp.default_init_rwnd 60
+
class_start core
class_start main
on nonencrypted
class_start late_start
+on property:sys.init_log_level=*
+ loglevel ${sys.init_log_level}
+
on charger
class_start charger
@@ -413,10 +454,17 @@
on property:sys.powerctl=*
powerctl ${sys.powerctl}
-# system server cannot write to /proc/sys files, so proxy it through init
+# system server cannot write to /proc/sys files,
+# and chown/chmod does not work for /proc/sys/ entries.
+# So proxy writes through init.
on property:sys.sysctl.extra_free_kbytes=*
write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes}
+# "tcp_default_init_rwnd" Is too long!
+on property:sys.sysctl.tcp_def_init_rwnd=*
+ write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd}
+
+
## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd
@@ -446,7 +494,7 @@
console
disabled
user shell
- group log
+ group shell log
seclabel u:r:shell:s0
on property:ro.debuggable=1
@@ -484,6 +532,7 @@
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
socket mdns stream 0660 root system
+ socket fwmarkd stream 0660 root inet
service debuggerd /system/bin/debuggerd
class main
@@ -557,10 +606,6 @@
disabled
oneshot
-service sshd /system/bin/start-ssh
- class main
- disabled
-
service mdnsd /system/bin/mdnsd
class main
user mdnsr
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 3d60a31..68c0668 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,4 +1,4 @@
-service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
new file mode 100644
index 0000000..979ab3b
--- /dev/null
+++ b/rootdir/init.zygote64_32.rc
@@ -0,0 +1,12 @@
+service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
+ class main
+ socket zygote stream 660 root system
+ onrestart write /sys/android_power/request_state wake
+ onrestart write /sys/power/state on
+ onrestart restart media
+ onrestart restart netd
+
+service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
+ class main
+ socket zygote_secondary stream 660 root system
+ onrestart restart zygote
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index b8fe716..eff24c3 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -91,3 +91,5 @@
/sys/devices/virtual/input/input* enable 0660 root input
/sys/devices/virtual/input/input* poll_delay 0660 root input
/sys/devices/virtual/usb_composite/* enable 0664 root system
+/sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system
+/sys/devices/system/cpu/cpu* cpufreq/scaling_min_freq 0664 system system
diff --git a/run-as/Android.mk b/run-as/Android.mk
index a8f2885..3774acc 100644
--- a/run-as/Android.mk
+++ b/run-as/Android.mk
@@ -1,10 +1,12 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= run-as.c package.c
+LOCAL_SRC_FILES := run-as.c package.c
LOCAL_SHARED_LIBRARIES := libselinux
-LOCAL_MODULE:= run-as
+LOCAL_MODULE := run-as
+
+LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
diff --git a/run-as/package.c b/run-as/package.c
index 901e9e3..4f8f3a7 100644
--- a/run-as/package.c
+++ b/run-as/package.c
@@ -128,7 +128,9 @@
}
/* Memory-map the file now */
- address = TEMP_FAILURE_RETRY(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0));
+ do {
+ address = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
+ } while (address == MAP_FAILED && errno == EINTR);
if (address == MAP_FAILED) {
address = NULL;
goto EXIT;
@@ -408,10 +410,6 @@
value = -1;
}
return value;
-
-BAD:
- *pp = p;
- return -1;
}
/* Read the system's package database and extract information about
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index 4630db9..63b0f41 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -1,10 +1,10 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= sdcard.c
-LOCAL_MODULE:= sdcard
-LOCAL_CFLAGS := -Wall -Wno-unused-parameter
+LOCAL_SRC_FILES := sdcard.c
+LOCAL_MODULE := sdcard
+LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
LOCAL_SHARED_LIBRARIES := libc libcutils
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
deleted file mode 100644
index 3138da9..0000000
--- a/sdcard/fuse.h
+++ /dev/null
@@ -1,578 +0,0 @@
-/*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
-*/
-
-/*
- * from the libfuse FAQ (and consistent with the Linux Kernel license):
- *
- * Under what conditions may I distribute a filesystem that uses the
- * raw kernel interface of FUSE?
- *
- * There are no restrictions whatsoever for using the raw kernel interface.
- *
- */
-
-/*
- * This file defines the kernel interface of FUSE
- *
- * Protocol changelog:
- *
- * 7.9:
- * - new fuse_getattr_in input argument of GETATTR
- * - add lk_flags in fuse_lk_in
- * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
- * - add blksize field to fuse_attr
- * - add file flags field to fuse_read_in and fuse_write_in
- *
- * 7.10
- * - add nonseekable open flag
- *
- * 7.11
- * - add IOCTL message
- * - add unsolicited notification support
- * - add POLL message and NOTIFY_POLL notification
- *
- * 7.12
- * - add umask flag to input argument of open, mknod and mkdir
- * - add notification messages for invalidation of inodes and
- * directory entries
- *
- * 7.13
- * - make max number of background requests and congestion threshold
- * tunables
- */
-
-#ifndef _LINUX_FUSE_H
-#define _LINUX_FUSE_H
-
-#include <linux/types.h>
-
-/*
- * Version negotiation:
- *
- * Both the kernel and userspace send the version they support in the
- * INIT request and reply respectively.
- *
- * If the major versions match then both shall use the smallest
- * of the two minor versions for communication.
- *
- * If the kernel supports a larger major version, then userspace shall
- * reply with the major version it supports, ignore the rest of the
- * INIT message and expect a new INIT message from the kernel with a
- * matching major version.
- *
- * If the library supports a larger major version, then it shall fall
- * back to the major protocol version sent by the kernel for
- * communication and reply with that major version (and an arbitrary
- * supported minor version).
- */
-
-/** Version number of this interface */
-#define FUSE_KERNEL_VERSION 7
-
-/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 13
-
-/** The node ID of the root inode */
-#define FUSE_ROOT_ID 1
-
-/* Make sure all structures are padded to 64bit boundary, so 32bit
- userspace works under 64bit kernels */
-
-struct fuse_attr {
- __u64 ino;
- __u64 size;
- __u64 blocks;
- __u64 atime;
- __u64 mtime;
- __u64 ctime;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 ctimensec;
- __u32 mode;
- __u32 nlink;
- __u32 uid;
- __u32 gid;
- __u32 rdev;
- __u32 blksize;
- __u32 padding;
-};
-
-struct fuse_kstatfs {
- __u64 blocks;
- __u64 bfree;
- __u64 bavail;
- __u64 files;
- __u64 ffree;
- __u32 bsize;
- __u32 namelen;
- __u32 frsize;
- __u32 padding;
- __u32 spare[6];
-};
-
-struct fuse_file_lock {
- __u64 start;
- __u64 end;
- __u32 type;
- __u32 pid; /* tgid */
-};
-
-/**
- * Bitmasks for fuse_setattr_in.valid
- */
-#define FATTR_MODE (1 << 0)
-#define FATTR_UID (1 << 1)
-#define FATTR_GID (1 << 2)
-#define FATTR_SIZE (1 << 3)
-#define FATTR_ATIME (1 << 4)
-#define FATTR_MTIME (1 << 5)
-#define FATTR_FH (1 << 6)
-#define FATTR_ATIME_NOW (1 << 7)
-#define FATTR_MTIME_NOW (1 << 8)
-#define FATTR_LOCKOWNER (1 << 9)
-
-/**
- * Flags returned by the OPEN request
- *
- * FOPEN_DIRECT_IO: bypass page cache for this open file
- * FOPEN_KEEP_CACHE: don't invalidate the data cache on open
- * FOPEN_NONSEEKABLE: the file is not seekable
- */
-#define FOPEN_DIRECT_IO (1 << 0)
-#define FOPEN_KEEP_CACHE (1 << 1)
-#define FOPEN_NONSEEKABLE (1 << 2)
-
-/**
- * INIT request/reply flags
- *
- * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
- * FUSE_DONT_MASK: don't apply umask to file mode on create operations
- */
-#define FUSE_ASYNC_READ (1 << 0)
-#define FUSE_POSIX_LOCKS (1 << 1)
-#define FUSE_FILE_OPS (1 << 2)
-#define FUSE_ATOMIC_O_TRUNC (1 << 3)
-#define FUSE_EXPORT_SUPPORT (1 << 4)
-#define FUSE_BIG_WRITES (1 << 5)
-#define FUSE_DONT_MASK (1 << 6)
-
-/**
- * CUSE INIT request/reply flags
- *
- * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl
- */
-#define CUSE_UNRESTRICTED_IOCTL (1 << 0)
-
-/**
- * Release flags
- */
-#define FUSE_RELEASE_FLUSH (1 << 0)
-
-/**
- * Getattr flags
- */
-#define FUSE_GETATTR_FH (1 << 0)
-
-/**
- * Lock flags
- */
-#define FUSE_LK_FLOCK (1 << 0)
-
-/**
- * WRITE flags
- *
- * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
- * FUSE_WRITE_LOCKOWNER: lock_owner field is valid
- */
-#define FUSE_WRITE_CACHE (1 << 0)
-#define FUSE_WRITE_LOCKOWNER (1 << 1)
-
-/**
- * Read flags
- */
-#define FUSE_READ_LOCKOWNER (1 << 1)
-
-/**
- * Ioctl flags
- *
- * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
- * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
- * FUSE_IOCTL_RETRY: retry with new iovecs
- *
- * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
- */
-#define FUSE_IOCTL_COMPAT (1 << 0)
-#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
-#define FUSE_IOCTL_RETRY (1 << 2)
-
-#define FUSE_IOCTL_MAX_IOV 256
-
-/**
- * Poll flags
- *
- * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify
- */
-#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
-
-enum fuse_opcode {
- FUSE_LOOKUP = 1,
- FUSE_FORGET = 2, /* no reply */
- FUSE_GETATTR = 3,
- FUSE_SETATTR = 4,
- FUSE_READLINK = 5,
- FUSE_SYMLINK = 6,
- FUSE_MKNOD = 8,
- FUSE_MKDIR = 9,
- FUSE_UNLINK = 10,
- FUSE_RMDIR = 11,
- FUSE_RENAME = 12,
- FUSE_LINK = 13,
- FUSE_OPEN = 14,
- FUSE_READ = 15,
- FUSE_WRITE = 16,
- FUSE_STATFS = 17,
- FUSE_RELEASE = 18,
- FUSE_FSYNC = 20,
- FUSE_SETXATTR = 21,
- FUSE_GETXATTR = 22,
- FUSE_LISTXATTR = 23,
- FUSE_REMOVEXATTR = 24,
- FUSE_FLUSH = 25,
- FUSE_INIT = 26,
- FUSE_OPENDIR = 27,
- FUSE_READDIR = 28,
- FUSE_RELEASEDIR = 29,
- FUSE_FSYNCDIR = 30,
- FUSE_GETLK = 31,
- FUSE_SETLK = 32,
- FUSE_SETLKW = 33,
- FUSE_ACCESS = 34,
- FUSE_CREATE = 35,
- FUSE_INTERRUPT = 36,
- FUSE_BMAP = 37,
- FUSE_DESTROY = 38,
- FUSE_IOCTL = 39,
- FUSE_POLL = 40,
-
- /* CUSE specific operations */
- CUSE_INIT = 4096,
-};
-
-enum fuse_notify_code {
- FUSE_NOTIFY_POLL = 1,
- FUSE_NOTIFY_INVAL_INODE = 2,
- FUSE_NOTIFY_INVAL_ENTRY = 3,
- FUSE_NOTIFY_CODE_MAX,
-};
-
-/* The read buffer is required to be at least 8k, but may be much larger */
-#define FUSE_MIN_READ_BUFFER 8192
-
-#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
-
-struct fuse_entry_out {
- __u64 nodeid; /* Inode ID */
- __u64 generation; /* Inode generation: nodeid:gen must
- be unique for the fs's lifetime */
- __u64 entry_valid; /* Cache timeout for the name */
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 entry_valid_nsec;
- __u32 attr_valid_nsec;
- struct fuse_attr attr;
-};
-
-struct fuse_forget_in {
- __u64 nlookup;
-};
-
-struct fuse_getattr_in {
- __u32 getattr_flags;
- __u32 dummy;
- __u64 fh;
-};
-
-#define FUSE_COMPAT_ATTR_OUT_SIZE 96
-
-struct fuse_attr_out {
- __u64 attr_valid; /* Cache timeout for the attributes */
- __u32 attr_valid_nsec;
- __u32 dummy;
- struct fuse_attr attr;
-};
-
-#define FUSE_COMPAT_MKNOD_IN_SIZE 8
-
-struct fuse_mknod_in {
- __u32 mode;
- __u32 rdev;
- __u32 umask;
- __u32 padding;
-};
-
-struct fuse_mkdir_in {
- __u32 mode;
- __u32 umask;
-};
-
-struct fuse_rename_in {
- __u64 newdir;
-};
-
-struct fuse_link_in {
- __u64 oldnodeid;
-};
-
-struct fuse_setattr_in {
- __u32 valid;
- __u32 padding;
- __u64 fh;
- __u64 size;
- __u64 lock_owner;
- __u64 atime;
- __u64 mtime;
- __u64 unused2;
- __u32 atimensec;
- __u32 mtimensec;
- __u32 unused3;
- __u32 mode;
- __u32 unused4;
- __u32 uid;
- __u32 gid;
- __u32 unused5;
-};
-
-struct fuse_open_in {
- __u32 flags;
- __u32 unused;
-};
-
-struct fuse_create_in {
- __u32 flags;
- __u32 mode;
- __u32 umask;
- __u32 padding;
-};
-
-struct fuse_open_out {
- __u64 fh;
- __u32 open_flags;
- __u32 padding;
-};
-
-struct fuse_release_in {
- __u64 fh;
- __u32 flags;
- __u32 release_flags;
- __u64 lock_owner;
-};
-
-struct fuse_flush_in {
- __u64 fh;
- __u32 unused;
- __u32 padding;
- __u64 lock_owner;
-};
-
-struct fuse_read_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 read_flags;
- __u64 lock_owner;
- __u32 flags;
- __u32 padding;
-};
-
-#define FUSE_COMPAT_WRITE_IN_SIZE 24
-
-struct fuse_write_in {
- __u64 fh;
- __u64 offset;
- __u32 size;
- __u32 write_flags;
- __u64 lock_owner;
- __u32 flags;
- __u32 padding;
-};
-
-struct fuse_write_out {
- __u32 size;
- __u32 padding;
-};
-
-#define FUSE_COMPAT_STATFS_SIZE 48
-
-struct fuse_statfs_out {
- struct fuse_kstatfs st;
-};
-
-struct fuse_fsync_in {
- __u64 fh;
- __u32 fsync_flags;
- __u32 padding;
-};
-
-struct fuse_setxattr_in {
- __u32 size;
- __u32 flags;
-};
-
-struct fuse_getxattr_in {
- __u32 size;
- __u32 padding;
-};
-
-struct fuse_getxattr_out {
- __u32 size;
- __u32 padding;
-};
-
-struct fuse_lk_in {
- __u64 fh;
- __u64 owner;
- struct fuse_file_lock lk;
- __u32 lk_flags;
- __u32 padding;
-};
-
-struct fuse_lk_out {
- struct fuse_file_lock lk;
-};
-
-struct fuse_access_in {
- __u32 mask;
- __u32 padding;
-};
-
-struct fuse_init_in {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
-};
-
-struct fuse_init_out {
- __u32 major;
- __u32 minor;
- __u32 max_readahead;
- __u32 flags;
- __u16 max_background;
- __u16 congestion_threshold;
- __u32 max_write;
-};
-
-#define CUSE_INIT_INFO_MAX 4096
-
-struct cuse_init_in {
- __u32 major;
- __u32 minor;
- __u32 unused;
- __u32 flags;
-};
-
-struct cuse_init_out {
- __u32 major;
- __u32 minor;
- __u32 unused;
- __u32 flags;
- __u32 max_read;
- __u32 max_write;
- __u32 dev_major; /* chardev major */
- __u32 dev_minor; /* chardev minor */
- __u32 spare[10];
-};
-
-struct fuse_interrupt_in {
- __u64 unique;
-};
-
-struct fuse_bmap_in {
- __u64 block;
- __u32 blocksize;
- __u32 padding;
-};
-
-struct fuse_bmap_out {
- __u64 block;
-};
-
-struct fuse_ioctl_in {
- __u64 fh;
- __u32 flags;
- __u32 cmd;
- __u64 arg;
- __u32 in_size;
- __u32 out_size;
-};
-
-struct fuse_ioctl_out {
- __s32 result;
- __u32 flags;
- __u32 in_iovs;
- __u32 out_iovs;
-};
-
-struct fuse_poll_in {
- __u64 fh;
- __u64 kh;
- __u32 flags;
- __u32 padding;
-};
-
-struct fuse_poll_out {
- __u32 revents;
- __u32 padding;
-};
-
-struct fuse_notify_poll_wakeup_out {
- __u64 kh;
-};
-
-struct fuse_in_header {
- __u32 len;
- __u32 opcode;
- __u64 unique;
- __u64 nodeid;
- __u32 uid;
- __u32 gid;
- __u32 pid;
- __u32 padding;
-};
-
-struct fuse_out_header {
- __u32 len;
- __s32 error;
- __u64 unique;
-};
-
-struct fuse_dirent {
- __u64 ino;
- __u64 off;
- __u32 namelen;
- __u32 type;
- char name[0];
-};
-
-#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
-#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
-#define FUSE_DIRENT_SIZE(d) \
- FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
-
-struct fuse_notify_inval_inode_out {
- __u64 ino;
- __s64 off;
- __s64 len;
-};
-
-struct fuse_notify_inval_entry_out {
- __u64 parent;
- __u32 namelen;
- __u32 padding;
-};
-
-#endif /* _LINUX_FUSE_H */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 6a9c2eb..844ca65 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -14,39 +14,41 @@
* limitations under the License.
*/
+#define LOG_TAG "sdcard"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <linux/fuse.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
+#include <sys/inotify.h>
#include <sys/mount.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statfs.h>
-#include <sys/uio.h>
-#include <dirent.h>
-#include <limits.h>
-#include <ctype.h>
-#include <pthread.h>
#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/inotify.h>
+#include <sys/uio.h>
+#include <unistd.h>
#include <cutils/fs.h>
#include <cutils/hashmap.h>
+#include <cutils/log.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
-#include "fuse.h"
-
/* README
*
* What is this?
- *
+ *
* sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
- * directory permissions (all files are given fixed owner, group, and
- * permissions at creation, owner, group, and permissions are not
+ * directory permissions (all files are given fixed owner, group, and
+ * permissions at creation, owner, group, and permissions are not
* changeable, symlinks and hardlinks are not createable, etc.
*
* See usage() for command line options.
@@ -91,12 +93,12 @@
#define FUSE_TRACE 0
#if FUSE_TRACE
-#define TRACE(x...) fprintf(stderr,x)
+#define TRACE(x...) ALOGD(x)
#else
#define TRACE(x...) do {} while (0)
#endif
-#define ERROR(x...) fprintf(stderr,x)
+#define ERROR(x...) ALOGE(x)
#define FUSE_UNKNOWN_INO 0xffffffff
@@ -1245,7 +1247,7 @@
struct handle *h = id_to_ptr(req->fh);
int res;
__u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGESIZE)));
-
+
if (req->flags & O_DIRECT) {
memcpy(aligned_buffer, buffer, req->size);
buffer = (const __u8*) aligned_buffer;
@@ -1307,14 +1309,23 @@
static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
{
- int is_data_sync = req->fsync_flags & 1;
- struct handle *h = id_to_ptr(req->fh);
- int res;
+ bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+ bool is_data_sync = req->fsync_flags & 1;
- TRACE("[%d] FSYNC %p(%d) is_data_sync=%d\n", handler->token,
- h, h->fd, is_data_sync);
- res = is_data_sync ? fdatasync(h->fd) : fsync(h->fd);
- if (res < 0) {
+ int fd = -1;
+ if (is_dir) {
+ struct dirhandle *dh = id_to_ptr(req->fh);
+ fd = dirfd(dh->d);
+ } else {
+ struct handle *h = id_to_ptr(req->fh);
+ fd = h->fd;
+ }
+
+ TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
+ is_dir ? "FSYNCDIR" : "FSYNC",
+ id_to_ptr(req->fh), fd, is_data_sync);
+ int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+ if (res == -1) {
return -errno;
}
return 0;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 5383b83..c53f17d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -2,73 +2,75 @@
include $(CLEAR_VARS)
TOOLS := \
- ls \
- mount \
cat \
- ps \
- kill \
- ln \
- insmod \
- rmmod \
- lsmod \
- ifconfig \
- rm \
- mkdir \
- rmdir \
- getevent \
- sendevent \
- date \
- wipe \
- sync \
- umount \
- start \
- stop \
- notify \
- cmp \
- dmesg \
- route \
- hd \
- dd \
- df \
- getprop \
- setprop \
- watchprops \
- log \
- sleep \
- renice \
- printenv \
- smd \
+ chcon \
chmod \
chown \
- newfs_msdos \
- netstat \
- ioctl \
- mv \
- schedtop \
- top \
- iftop \
+ clear \
+ cmp \
+ date \
+ dd \
+ df \
+ dmesg \
+ du \
+ getenforce \
+ getevent \
+ getprop \
+ getsebool \
+ hd \
id \
+ ifconfig \
+ iftop \
+ insmod \
+ ioctl \
+ ionice \
+ kill \
+ ln \
+ load_policy \
+ log \
+ ls \
+ lsmod \
+ lsof \
+ md5 \
+ mkdir \
+ mknod \
+ mkswap \
+ mount \
+ mv \
+ nandread \
+ netstat \
+ newfs_msdos \
+ nohup \
+ notify \
+ printenv \
+ ps \
+ readlink \
+ renice \
+ restorecon \
+ rm \
+ rmdir \
+ rmmod \
+ route \
+ runcon \
+ schedtop \
+ sendevent \
+ setenforce \
+ setprop \
+ setsebool \
+ sleep \
+ smd \
+ start \
+ stop \
+ swapoff \
+ swapon \
+ sync \
+ top \
+ touch \
+ umount \
uptime \
vmstat \
- nandread \
- ionice \
- touch \
- lsof \
- du \
- md5 \
- clear \
- getenforce \
- setenforce \
- chcon \
- restorecon \
- runcon \
- getsebool \
- setsebool \
- load_policy \
- swapon \
- swapoff \
- mkswap \
- readlink
+ watchprops \
+ wipe \
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
TOOLS += r
@@ -92,21 +94,25 @@
toolbox.c \
uid_from_user.c \
-LOCAL_C_INCLUDES := bionic/libc/bionic
-
LOCAL_CFLAGS += \
-std=gnu99 \
- -Wno-unused-parameter \
+ -Werror -Wno-unused-parameter \
-include bsd-compatibility.h \
+LOCAL_C_INCLUDES += external/openssl/include
+
LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libc \
- libusbhost \
- libselinux
+ libcrypto \
+ libcutils \
+ libselinux \
+
+# libusbhost is only used by lsusb, and that isn't usually included in toolbox.
+# The linker strips out all the unused library code in the normal case.
+LOCAL_STATIC_LIBRARIES := \
+ libusbhost \
LOCAL_MODULE := toolbox
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
# Including this will define $(intermediates).
#
diff --git a/toolbox/cp/cp.c b/toolbox/cp/cp.c
index bd3c70e..e666453 100644
--- a/toolbox/cp/cp.c
+++ b/toolbox/cp/cp.c
@@ -95,12 +95,14 @@
static int copy(char *[], enum op, int);
+#ifndef ANDROID
static void
progress(int sig __unused)
{
pinfo++;
}
+#endif
int
cp_main(int argc, char *argv[])
diff --git a/toolbox/cp/utils.c b/toolbox/cp/utils.c
index b682bbe..9d0390f 100644
--- a/toolbox/cp/utils.c
+++ b/toolbox/cp/utils.c
@@ -380,10 +380,11 @@
int
setfile(struct stat *fs, int fd)
{
- int rval, islink;
+ int rval = 0;
+#ifndef ANDROID
+ int islink = S_ISLNK(fs->st_mode);
+#endif
- rval = 0;
- islink = S_ISLNK(fs->st_mode);
fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
/*
@@ -401,13 +402,13 @@
fs->st_mode &= ~(S_ISUID | S_ISGID);
}
#ifdef ANDROID
- if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+ if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
#else
- if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+ if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
#endif
- warn("chmod: %s", to.p_path);
- rval = 1;
- }
+ warn("chmod: %s", to.p_path);
+ rval = 1;
+ }
#ifndef ANDROID
if (!islink && !Nflag) {
diff --git a/toolbox/date.c b/toolbox/date.c
index aa3b72e..70ce1d5 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -140,14 +140,12 @@
int date_main(int argc, char *argv[])
{
- int c;
+ int c;
int res;
- struct tm tm;
- time_t t;
- struct timeval tv;
- struct timespec ts;
- char strbuf[260];
- int fd;
+ struct tm tm;
+ time_t t;
+ struct timeval tv;
+ char strbuf[260];
int useutc = 0;
@@ -177,7 +175,6 @@
int hasfmt = argc == optind + 1 && argv[optind][0] == '+';
if(optind == argc || hasfmt) {
- char buf[2000];
time(&t);
if (useutc) {
gmtime_r(&t, &tm);
diff --git a/toolbox/dd.c b/toolbox/dd.c
index 6b61ffb..408a496 100644
--- a/toolbox/dd.c
+++ b/toolbox/dd.c
@@ -356,7 +356,7 @@
++st.in_full;
/* Handle full input blocks. */
- } else if (n == in.dbsz) {
+ } else if (n == (int64_t)in.dbsz) {
in.dbcnt += in.dbrcnt = n;
++st.in_full;
@@ -521,7 +521,7 @@
outp += nw;
st.bytes += nw;
if (nw == n) {
- if (n != out.dbsz)
+ if (n != (int64_t)out.dbsz)
++st.out_part;
else
++st.out_full;
@@ -649,8 +649,8 @@
void
pos_out(void)
{
-// struct mtop t_op;
- int cnt, n;
+/* struct mtop t_op; */
+ int64_t cnt, n;
/*
* If not a tape, try seeking on the file. Seeking on a pipe is
@@ -681,7 +681,7 @@
}
/* Read it. */
- for (cnt = 0; cnt < out.offset; ++cnt) {
+ for (cnt = 0; cnt < (int64_t)out.offset; ++cnt) {
if ((n = read(out.fd, out.db, out.dbsz)) > 0)
continue;
@@ -705,8 +705,8 @@
/* NOTREACHED */
}
- while (cnt++ < out.offset)
- if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
+ while (cnt++ < (int64_t)out.offset)
+ if ((n = bwrite(out.fd, out.db, out.dbsz)) != (int64_t)out.dbsz) {
fprintf(stderr, "%s: cannot position "
"by writing: %s\n",
out.name, strerror(errno));
@@ -1153,7 +1153,7 @@
((const struct arg *)b)->name));
}
-static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
+static long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max)
{
long long result;
@@ -1180,7 +1180,7 @@
f_count(char *arg)
{
- cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+ cpy_cnt = (uint64_t)strsuftoll("block count", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
if (!cpy_cnt)
terminate(0);
}
@@ -1228,14 +1228,14 @@
f_seek(char *arg)
{
- out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+ out.offset = (uint64_t)strsuftoll("seek blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
}
static void
f_skip(char *arg)
{
- in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+ in.offset = (uint64_t)strsuftoll("skip blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
}
static void
diff --git a/toolbox/du.c b/toolbox/du.c
index fc7c943..c8beba5 100644
--- a/toolbox/du.c
+++ b/toolbox/du.c
@@ -76,7 +76,7 @@
int64_t totalblocks;
int ftsoptions, listfiles;
int depth;
- int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, nflag, rval, sflag;
+ int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag;
const char *noargv[2];
Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
diff --git a/toolbox/getevent.c b/toolbox/getevent.c
index ed381f5..da83ec3 100644
--- a/toolbox/getevent.c
+++ b/toolbox/getevent.c
@@ -295,6 +295,7 @@
{
int version;
int fd;
+ int clkid = CLOCK_MONOTONIC;
struct pollfd *new_ufds;
char **new_device_names;
char name[80];
@@ -335,6 +336,11 @@
idstr[0] = '\0';
}
+ if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
+ fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno));
+ // a non-fatal error
+ }
+
new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1));
if(new_ufds == NULL) {
fprintf(stderr, "out of memory\n");
@@ -470,9 +476,9 @@
return 0;
}
-static void usage(int argc, char *argv[])
+static void usage(char *name)
{
- fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]);
+ fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name);
fprintf(stderr, " -t: show time stamps\n");
fprintf(stderr, " -n: don't print newlines\n");
fprintf(stderr, " -s: print switch states for given bits\n");
@@ -492,13 +498,11 @@
int c;
int i;
int res;
- int pollres;
int get_time = 0;
int print_device = 0;
char *newline = "\n";
uint16_t get_switch = 0;
struct input_event event;
- int version;
int print_flags = 0;
int print_flags_set = 0;
int dont_block = -1;
@@ -570,7 +574,7 @@
fprintf(stderr, "%s: invalid option -%c\n",
argv[0], optopt);
case 'h':
- usage(argc, argv);
+ usage(argv[0]);
exit(1);
}
} while (1);
@@ -582,7 +586,7 @@
optind++;
}
if (optind != argc) {
- usage(argc, argv);
+ usage(argv[0]);
exit(1);
}
nfds = 1;
@@ -629,7 +633,8 @@
return 0;
while(1) {
- pollres = poll(ufds, nfds, -1);
+ //int pollres =
+ poll(ufds, nfds, -1);
//printf("poll %d, returned %d\n", nfds, pollres);
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
diff --git a/toolbox/getevent.h b/toolbox/getevent.h
index 2b76209..0482d04 100644
--- a/toolbox/getevent.h
+++ b/toolbox/getevent.h
@@ -652,6 +652,7 @@
LABEL_END,
};
+#if 0
static struct label id_labels[] = {
LABEL(ID_BUS),
LABEL(ID_VENDOR),
@@ -682,6 +683,7 @@
LABEL(BUS_SPI),
LABEL_END,
};
+#endif
static struct label mt_tool_labels[] = {
LABEL(MT_TOOL_FINGER),
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
index c001fda..dcc0ea0 100644
--- a/toolbox/getprop.c
+++ b/toolbox/getprop.c
@@ -3,7 +3,6 @@
#include <cutils/properties.h>
-#include <sys/system_properties.h>
#include "dynarray.h"
static void record_prop(const char* key, const char* name, void* opaque)
@@ -31,12 +30,8 @@
strlist_done(list);
}
-int __system_property_wait(prop_info *pi);
-
int getprop_main(int argc, char *argv[])
{
- int n = 0;
-
if (argc == 1) {
list_properties();
} else {
diff --git a/toolbox/grep/file.c b/toolbox/grep/file.c
index 86b7658..d28dff5 100644
--- a/toolbox/grep/file.c
+++ b/toolbox/grep/file.c
@@ -78,7 +78,9 @@
grep_refill(struct file *f)
{
ssize_t nr;
+#ifndef ANDROID
int bzerr;
+#endif
bufpos = buffer;
bufrem = 0;
diff --git a/toolbox/grep/grep.c b/toolbox/grep/grep.c
index 5a4fa0c..7b2c487 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/grep/grep.c
@@ -403,7 +403,7 @@
Aflag = 0;
else if (Aflag > LLONG_MAX / 10) {
errno = ERANGE;
- err(2, NULL);
+ err(2, "%llu", Aflag);
}
Aflag = Bflag = (Aflag * 10) + (c - '0');
break;
@@ -420,10 +420,10 @@
l = strtoull(optarg, &ep, 10);
if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
((errno == EINVAL) && (l == 0)))
- err(2, NULL);
+ err(2, "strtoull");
else if (ep[0] != '\0') {
errno = EINVAL;
- err(2, NULL);
+ err(2, "empty");
}
if (c == 'A')
Aflag = l;
@@ -509,10 +509,10 @@
mcount = strtoull(optarg, &ep, 10);
if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
((errno == EINVAL) && (mcount == 0)))
- err(2, NULL);
+ err(2, "strtoull");
else if (ep[0] != '\0') {
errno = EINVAL;
- err(2, NULL);
+ err(2, "empty");
}
break;
case 'n':
diff --git a/toolbox/grep/util.c b/toolbox/grep/util.c
index 497db06..5712fee 100644
--- a/toolbox/grep/util.c
+++ b/toolbox/grep/util.c
@@ -273,7 +273,7 @@
return (c);
}
-#define iswword(x) (iswalnum((x)) || (x) == L'_')
+#define iswword(x) (iswalnum((wint_t)(x)) || (x) == L'_')
/*
* Processes a line comparing it with the specified patterns. Each pattern
@@ -323,7 +323,7 @@
continue;
/* Check for whole word match */
if (fg_pattern[i].word && pmatch.rm_so != 0) {
- wint_t wbegin, wend;
+ wchar_t wbegin, wend;
wbegin = wend = L' ';
if (pmatch.rm_so != 0 &&
diff --git a/toolbox/hd.c b/toolbox/hd.c
index 0d2f96a..7c9998e 100644
--- a/toolbox/hd.c
+++ b/toolbox/hd.c
@@ -14,7 +14,6 @@
unsigned char buf[4096];
int res;
int read_len;
- int rv = 0;
int i;
int filepos = 0;
int sum;
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index 80c0e5c..b953176 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -61,11 +61,11 @@
{
struct ifreq ifr;
int s;
- unsigned int addr, mask, flags;
+ unsigned int flags;
char astring[20];
char mstring[20];
char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
-
+
argc--;
argv++;
@@ -85,13 +85,17 @@
perror(ifr.ifr_name);
return -1;
} else
- addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ strlcpy(astring,
+ inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+ sizeof(astring));
if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) {
perror(ifr.ifr_name);
return -1;
} else
- mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
+ strlcpy(mstring,
+ inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
+ sizeof(mstring));
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
perror(ifr.ifr_name);
@@ -99,16 +103,6 @@
} else
flags = ifr.ifr_flags;
- sprintf(astring, "%d.%d.%d.%d",
- addr & 0xff,
- ((addr >> 8) & 0xff),
- ((addr >> 16) & 0xff),
- ((addr >> 24) & 0xff));
- sprintf(mstring, "%d.%d.%d.%d",
- mask & 0xff,
- ((mask >> 8) & 0xff),
- ((mask >> 16) & 0xff),
- ((mask >> 24) & 0xff));
printf("%s: ip %s mask %s flags [", ifr.ifr_name,
astring,
mstring
diff --git a/toolbox/insmod.c b/toolbox/insmod.c
index fb1448b..d252433 100644
--- a/toolbox/insmod.c
+++ b/toolbox/insmod.c
@@ -73,7 +73,7 @@
char *ptr = opts;
for (i = 2; (i < argc) && (ptr < end); i++) {
- len = MIN(strlen(argv[i]), end - ptr);
+ len = MIN(strlen(argv[i]), (size_t)(end - ptr));
memcpy(ptr, argv[i], len);
ptr += len;
*ptr++ = ' ';
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index fb555d2..17fabff 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -21,9 +21,9 @@
int arg_size = 4;
int direct_arg = 0;
uint32_t ioctl_nr;
- void *ioctl_args;
+ void *ioctl_args = NULL;
uint8_t *ioctl_argp;
- uint8_t *ioctl_argp_save;
+ uint8_t *ioctl_argp_save = NULL;
int rem;
do {
@@ -112,6 +112,7 @@
else
res = ioctl(fd, ioctl_nr, 0);
if (res < 0) {
+ free(ioctl_args);
fprintf(stderr, "ioctl 0x%x failed, %d\n", ioctl_nr, res);
return 1;
}
@@ -124,5 +125,6 @@
}
printf("\n");
}
+ free(ioctl_args);
return 0;
}
diff --git a/toolbox/load_policy.c b/toolbox/load_policy.c
index eb5aba6..90d48c4 100644
--- a/toolbox/load_policy.c
+++ b/toolbox/load_policy.c
@@ -10,7 +10,7 @@
int load_policy_main(int argc, char **argv)
{
- int fd, rc, vers;
+ int fd, rc;
struct stat sb;
void *map;
const char *path;
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 06910ee..011f7b5 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -443,7 +443,6 @@
int ls_main(int argc, char **argv)
{
int flags = 0;
- int listed = 0;
if(argc > 1) {
int i;
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index af321af..bee981d 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -99,10 +99,7 @@
static void print_maps(struct pid_info_t* info)
{
FILE *maps;
- char buffer[PATH_MAX + 100];
-
size_t offset;
- int major, minor;
char device[10];
long int inode;
char file[PATH_MAX];
diff --git a/toolbox/md5.c b/toolbox/md5.c
index 2fb8b05..5de4d9e 100644
--- a/toolbox/md5.c
+++ b/toolbox/md5.c
@@ -4,12 +4,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <md5.h>
-
-/* When this was written, bionic's md5.h did not define this. */
-#ifndef MD5_DIGEST_LENGTH
-#define MD5_DIGEST_LENGTH 16
-#endif
+#include <openssl/md5.h>
static int usage()
{
@@ -30,7 +25,6 @@
return -1;
}
- /* Note that bionic's MD5_* functions return void. */
MD5_Init(&md5_ctx);
while (1) {
diff --git a/toolbox/mkdir.c b/toolbox/mkdir.c
index 656970a..398d350 100644
--- a/toolbox/mkdir.c
+++ b/toolbox/mkdir.c
@@ -15,7 +15,6 @@
int mkdir_main(int argc, char *argv[])
{
- int symbolic = 0;
int ret;
if(argc < 2 || strcmp(argv[1], "--help") == 0) {
return usage();
diff --git a/toolbox/mknod.c b/toolbox/mknod.c
new file mode 100644
index 0000000..0fedece
--- /dev/null
+++ b/toolbox/mknod.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google, Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+static int print_usage() {
+ fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n");
+ return EXIT_FAILURE;
+}
+
+int mknod_main(int argc, char **argv) {
+ char *path = NULL;
+ int major = 0;
+ int minor = 0;
+ int args = 0;
+ mode_t mode = 0660;
+
+ /* Check correct argument count is 3 or 5 */
+ if (argc != 3 && argc != 5) {
+ fprintf(stderr, "Incorrect argument count\n");
+ return print_usage();
+ }
+
+ path = argv[1];
+
+ const char node_type = *argv[2];
+ switch (node_type) {
+ case 'b':
+ mode |= S_IFBLK;
+ args = 5;
+ break;
+ case 'c':
+ case 'u':
+ mode |= S_IFCHR;
+ args = 5;
+ break;
+ case 'p':
+ mode |= S_IFIFO;
+ args = 3;
+ break;
+ default:
+ fprintf(stderr, "Invalid node type '%c'\n", node_type);
+ return print_usage();
+ }
+
+ if (argc != args) {
+ if (args == 5) {
+ fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type);
+ } else {
+ fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type);
+ }
+ return print_usage();
+ }
+
+ if (args == 5) {
+ major = atoi(argv[3]);
+ minor = atoi(argv[4]);
+ }
+
+ if (mknod(path, mode, makedev(major, minor))) {
+ perror("Unable to create node");
+ return EXIT_FAILURE;
+ }
+ return 0;
+}
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
index 971c232..bd19942 100644
--- a/toolbox/nandread.c
+++ b/toolbox/nandread.c
@@ -1,9 +1,10 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <mtd/mtd-user.h>
@@ -189,18 +190,18 @@
for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
bad_block = 0;
if (verbose > 3)
- printf("reading at %llx\n", pos);
+ printf("reading at %" PRIx64 "\n", pos);
lseek64(fd, pos, SEEK_SET);
ret = read(fd, buffer, mtdinfo.writesize + rawmode);
if (ret < (int)mtdinfo.writesize) {
- fprintf(stderr, "short read at %llx, %d\n", pos, ret);
+ fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
bad_block = 2;
}
if (!rawmode) {
oobbuf.start = pos;
ret = ioctl(fd, MEMREADOOB, &oobbuf);
if (ret) {
- fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret);
+ fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
bad_block = 2;
}
}
@@ -213,17 +214,17 @@
bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
if (ret && errno != EOPNOTSUPP) {
- printf("badblock at %llx\n", pos);
+ printf("badblock at %" PRIx64 "\n", pos);
bad_block = 1;
}
if (ecc.corrected != last_ecc.corrected)
- printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos);
+ printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
if (ecc.failed != last_ecc.failed)
- printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos);
+ printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
if (ecc.badblocks != last_ecc.badblocks)
- printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos);
+ printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
if (ecc.bbtblocks != last_ecc.bbtblocks)
- printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
+ printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
if (!rawmode) {
oob_fixed = (uint8_t *)oob_data;
@@ -241,18 +242,18 @@
if (outfd >= 0) {
ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
if (ret < (int)(mtdinfo.writesize + spare_size)) {
- fprintf(stderr, "short write at %llx, %d\n", pos, ret);
+ fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
close(outfd);
outfd = -1;
}
if (ecc.corrected != last_ecc.corrected)
- fprintf(statusfile, "%08llx: ecc corrected\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
if (ecc.failed != last_ecc.failed)
- fprintf(statusfile, "%08llx: ecc failed\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
if (bad_block == 1)
- fprintf(statusfile, "%08llx: badblock\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
if (bad_block == 2)
- fprintf(statusfile, "%08llx: read error\n", opos);
+ fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
opos += mtdinfo.writesize + spare_size;
}
@@ -261,7 +262,7 @@
if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
empty_pages++;
else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
- printf("page at %llx (%d oobbytes): %08x %08x %08x %08x "
+ printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
"%08x %08x %08x %08x\n", pos, oobbuf.start,
oob_data[0], oob_data[1], oob_data[2], oob_data[3],
oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 27dca42..30b9f77 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -360,7 +360,7 @@
if (!opt_create && !strchr(fname, '/')) {
snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
if (!(fname = strdup(buf)))
- err(1, NULL);
+ err(1, "%s", buf);
}
dtype = *argv;
if (opt_create) {
@@ -493,7 +493,7 @@
if (!strchr(bname, '/')) {
snprintf(buf, sizeof(buf), "/boot/%s", bname);
if (!(bname = strdup(buf)))
- err(1, NULL);
+ err(1, "%s", buf);
}
if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
err(1, "%s", bname);
@@ -611,7 +611,7 @@
now = tv.tv_sec;
tm = localtime(&now);
if (!(img = malloc(bpb.bps)))
- err(1, NULL);
+ err(1, "%u", bpb.bps);
dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
x = lsn;
@@ -728,14 +728,14 @@
static void
check_mounted(const char *fname, mode_t mode)
{
+#ifdef ANDROID
+ warnx("Skipping mount checks");
+#else
struct statfs *mp;
const char *s1, *s2;
size_t len;
int n, r;
-#ifdef ANDROID
- warnx("Skipping mount checks");
-#else
if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
err(1, "getmntinfo");
len = strlen(_PATH_DEV);
diff --git a/toolbox/nohup.c b/toolbox/nohup.c
new file mode 100644
index 0000000..363999d
--- /dev/null
+++ b/toolbox/nohup.c
@@ -0,0 +1,26 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int nohup_main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+ signal(SIGHUP, SIG_IGN);
+ argv++;
+ if (strcmp(argv[0], "-n") == 0) {
+ argv++;
+ signal(SIGINT, SIG_IGN);
+ signal(SIGSTOP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ }
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ return EXIT_FAILURE;
+}
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 7c35ccb..57b4280 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -28,9 +28,12 @@
#define SHOW_POLICY 4
#define SHOW_CPU 8
#define SHOW_MACLABEL 16
+#define SHOW_ABI 32
static int display_flags = 0;
+static void print_exe_abi(int pid);
+
static int ps_line(int pid, int tid, char *namefilter)
{
char statline[1024];
@@ -40,7 +43,7 @@
struct stat stats;
int fd, r;
char *ptr, *name, *state;
- int ppid, tty;
+ int ppid;
unsigned wchan, rss, vss, eip;
unsigned utime, stime;
int prio, nice, rtprio, sched, psr;
@@ -88,7 +91,7 @@
ppid = atoi(nexttok(&ptr));
nexttok(&ptr); // pgrp
nexttok(&ptr); // sid
- tty = atoi(nexttok(&ptr));
+ nexttok(&ptr); // tty
nexttok(&ptr); // tpgid
nexttok(&ptr); // flags
@@ -130,7 +133,7 @@
rtprio = atoi(nexttok(&ptr)); // rt_priority
sched = atoi(nexttok(&ptr)); // scheduling policy
- tty = atoi(nexttok(&ptr));
+ nexttok(&ptr); // tty
if(tid != 0) {
ppid = pid;
@@ -170,7 +173,11 @@
else
printf(" %.2s ", get_sched_policy_name(p));
}
- printf(" %08x %08x %s %s", wchan, eip, state, cmdline[0] ? cmdline : name);
+ printf(" %08x %08x %s ", wchan, eip, state);
+ if (display_flags & SHOW_ABI) {
+ print_exe_abi(pid);
+ }
+ printf("%s", cmdline[0] ? cmdline : name);
if(display_flags&SHOW_TIME)
printf(" (u:%d, s:%d)", utime, stime);
@@ -179,6 +186,39 @@
return 0;
}
+static void print_exe_abi(int pid)
+{
+ int fd, r;
+ char exeline[1024];
+
+ sprintf(exeline, "/proc/%d/exe", pid);
+ fd = open(exeline, O_RDONLY);
+ if(fd == 0) {
+ printf(" ");
+ return;
+ }
+ r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
+ close(fd);
+ if(r < 0) {
+ printf(" ");
+ return;
+ }
+ if (memcmp("\177ELF", exeline, 4) != 0) {
+ printf("?? ");
+ return;
+ }
+ switch (exeline[4]) {
+ case 1:
+ printf("32 ");
+ return;
+ case 2:
+ printf("64 ");
+ return;
+ default:
+ printf("?? ");
+ return;
+ }
+}
void ps_threads(int pid, char *namefilter)
{
@@ -224,7 +264,9 @@
display_flags |= SHOW_PRIO;
} else if(!strcmp(argv[1],"-c")) {
display_flags |= SHOW_CPU;
- } else if(isdigit(argv[1][0])){
+ } else if(!strcmp(argv[1],"--abi")) {
+ display_flags |= SHOW_ABI;
+ } else if(isdigit(argv[1][0])){
pidfilter = atoi(argv[1]);
} else {
namefilter = argv[1];
@@ -236,10 +278,11 @@
if (display_flags & SHOW_MACLABEL) {
printf("LABEL USER PID PPID NAME\n");
} else {
- printf("USER PID PPID VSIZE RSS %s%s %s WCHAN PC NAME\n",
+ printf("USER PID PPID VSIZE RSS %s%s %s WCHAN PC %sNAME\n",
(display_flags&SHOW_CPU)?"CPU ":"",
(display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"",
- (display_flags&SHOW_POLICY)?"PCY " : "");
+ (display_flags&SHOW_POLICY)?"PCY " : "",
+ (display_flags&SHOW_ABI)?"ABI " : "");
}
while((de = readdir(d)) != 0){
if(isdigit(de->d_name[0])){
diff --git a/toolbox/rmdir.c b/toolbox/rmdir.c
index 06f3df2..749fec8 100644
--- a/toolbox/rmdir.c
+++ b/toolbox/rmdir.c
@@ -11,7 +11,6 @@
int rmdir_main(int argc, char *argv[])
{
- int symbolic = 0;
int ret;
if(argc < 2) return usage();
diff --git a/toolbox/schedtop.c b/toolbox/schedtop.c
index 0c85e76..2fccd2e 100644
--- a/toolbox/schedtop.c
+++ b/toolbox/schedtop.c
@@ -227,7 +227,6 @@
}
for (i = 0; i < last_processes.active; i++) {
int pid = last_processes.data[i].pid;
- int tid = last_processes.data[i].tid;
for (j = 0; j < processes.active; j++)
if (pid == processes.data[j].pid)
break;
@@ -270,9 +269,6 @@
{
int c;
DIR *d;
- struct dirent *de;
- char *namefilter = 0;
- int pidfilter = 0;
uint32_t flags = 0;
int delay = 3000000;
float delay_f;
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
index 1608e6c..9b813f6 100644
--- a/toolbox/sendevent.c
+++ b/toolbox/sendevent.c
@@ -47,9 +47,8 @@
int sendevent_main(int argc, char *argv[])
{
- int i;
int fd;
- int ret;
+ ssize_t ret;
int version;
struct input_event event;
@@ -72,7 +71,7 @@
event.code = atoi(argv[3]);
event.value = atoi(argv[4]);
ret = write(fd, &event, sizeof(event));
- if(ret < sizeof(event)) {
+ if(ret < (ssize_t) sizeof(event)) {
fprintf(stderr, "write event failed, %s\n", strerror(errno));
return -1;
}
diff --git a/toolbox/start.c b/toolbox/start.c
index 665a941..0941e64 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -7,14 +7,13 @@
int start_main(int argc, char *argv[])
{
- char buf[1024];
-
if(argc > 1) {
property_set("ctl.start", argv[1]);
} else {
/* defaults to starting the common services stopped by stop.c */
property_set("ctl.start", "surfaceflinger");
property_set("ctl.start", "zygote");
+ property_set("ctl.start", "zygote_secondary");
}
return 0;
diff --git a/toolbox/stop.c b/toolbox/stop.c
index 460f377..ed9a293 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -5,12 +5,11 @@
int stop_main(int argc, char *argv[])
{
- char buf[1024];
-
if(argc > 1) {
property_set("ctl.stop", argv[1]);
} else{
/* defaults to stopping the common services */
+ property_set("ctl.stop", "zygote_secondary");
property_set("ctl.stop", "zygote");
property_set("ctl.stop", "surfaceflinger");
}
diff --git a/toolbox/top.c b/toolbox/top.c
index 7382f1f..280a032 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -328,7 +328,6 @@
static int read_stat(char *filename, struct proc_info *proc) {
FILE *file;
char buf[MAX_LINE], *open_paren, *close_paren;
- int res, idx;
file = fopen(filename, "r");
if (!file) return 1;
@@ -414,9 +413,7 @@
struct proc_info *old_proc, *proc;
long unsigned total_delta_time;
struct passwd *user;
- struct group *group;
char *user_str, user_buf[20];
- char *group_str, group_buf[20];
for (i = 0; i < num_new_procs; i++) {
if (new_procs[i]) {
@@ -467,19 +464,12 @@
if (!proc || (max_procs && (i >= max_procs)))
break;
user = getpwuid(proc->uid);
- group = getgrgid(proc->gid);
if (user && user->pw_name) {
user_str = user->pw_name;
} else {
snprintf(user_buf, 20, "%d", proc->uid);
user_str = user_buf;
}
- if (group && group->gr_name) {
- group_str = group->gr_name;
- } else {
- snprintf(group_buf, 20, "%d", proc->gid);
- group_str = group_buf;
- }
if (!threads)
printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
diff --git a/toolbox/umount.c b/toolbox/umount.c
index 890e870..3e17396 100644
--- a/toolbox/umount.c
+++ b/toolbox/umount.c
@@ -33,7 +33,6 @@
char mount_path[256];
char rest[256];
int result = 0;
- int path_length = strlen(path);
f = fopen("/proc/mounts", "r");
if (!f) {
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index bf82882..0d05aba 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -6,8 +6,6 @@
#include <cutils/properties.h>
#include <cutils/hashmap.h>
-#include <sys/atomics.h>
-
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
@@ -23,9 +21,9 @@
static void announce(char *name, char *value)
{
- char *x;
+ unsigned char *x;
- for(x = value; *x; x++) {
+ for(x = (unsigned char *)value; *x; x++) {
if((*x < 32) || (*x > 127)) *x = '.';
}
@@ -77,9 +75,7 @@
int watchprops_main(int argc, char *argv[])
{
- unsigned serial = 0;
- unsigned count = 0;
- unsigned n;
+ unsigned serial;
Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
if (!watchlist)
@@ -87,7 +83,7 @@
__system_property_foreach(populate_watchlist, watchlist);
- for(;;) {
+ for(serial = 0;;) {
serial = __system_property_wait_any(serial);
__system_property_foreach(update_watchlist, watchlist);
}