Merge "logd: whitelist should not preserve expire messages"
diff --git a/adb/Android.mk b/adb/Android.mk
index f3a4822..f030041 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -14,8 +14,9 @@
adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
ADB_COMMON_CFLAGS := \
- -Wall -Werror \
+ -Wall -Wextra -Werror \
-Wno-unused-parameter \
+ -Wno-missing-field-initializers \
-DADB_REVISION='"$(adb_version)"' \
# libadb
@@ -45,7 +46,6 @@
LIBADB_CFLAGS := \
$(ADB_COMMON_CFLAGS) \
- -Wno-missing-field-initializers \
-fvisibility=hidden \
LIBADB_darwin_SRC_FILES := \
@@ -77,6 +77,10 @@
LOCAL_SHARED_LIBRARIES := libbase
+# Even though we're building a static library (and thus there's no link step for
+# this to take effect), this adds the includes to our path.
+LOCAL_STATIC_LIBRARIES := libbase
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -91,8 +95,8 @@
LOCAL_SHARED_LIBRARIES := libbase
# Even though we're building a static library (and thus there's no link step for
-# this to take effect), this adds the SSL includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_static
+# this to take effect), this adds the includes to our path.
+LOCAL_STATIC_LIBRARIES := libcrypto_static libbase
ifeq ($(HOST_OS),windows)
LOCAL_C_INCLUDES += development/host/windows/usb/api/
@@ -254,10 +258,10 @@
libbase \
libfs_mgr \
liblog \
- libcutils \
- libc \
libmincrypt \
libselinux \
libext4_utils_static \
+ libcutils \
+ libbase \
include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3d1b7b4..9c1ead5 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -31,7 +31,10 @@
#include <time.h>
#include <string>
+#include <vector>
+#include <unordered_map>
+#include <base/logging.h>
#include <base/stringprintf.h>
#include <base/strings.h>
@@ -48,16 +51,25 @@
#include <sys/mount.h>
#endif
-ADB_MUTEX_DEFINE( D_lock );
+ADB_MUTEX_DEFINE(D_lock);
int HOST = 0;
#if !ADB_HOST
-const char *adb_device_banner = "device";
+const char* adb_device_banner = "device";
+static android::base::LogdLogger gLogdLogger;
#endif
-void fatal(const char *fmt, ...)
-{
+void AdbLogger(android::base::LogId id, android::base::LogSeverity severity,
+ const char* tag, const char* file, unsigned int line,
+ const char* message) {
+ android::base::StderrLogger(id, severity, tag, file, line, message);
+#if !ADB_HOST
+ gLogdLogger(id, severity, tag, file, line, message);
+#endif
+}
+
+void fatal(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "error: ");
@@ -67,8 +79,7 @@
exit(-1);
}
-void fatal_errno(const char *fmt, ...)
-{
+void fatal_errno(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "error: %s: ", strerror(errno));
@@ -79,7 +90,7 @@
}
#if !ADB_HOST
-void start_device_log(void) {
+static std::string get_log_file_name() {
struct tm now;
time_t t;
tzset();
@@ -89,13 +100,18 @@
char timestamp[PATH_MAX];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
- std::string path = android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp, getpid());
- int fd = unix_open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
+ return android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp,
+ getpid());
+}
+
+void start_device_log(void) {
+ int fd = unix_open(get_log_file_name().c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
if (fd == -1) {
return;
}
- // redirect stdout and stderr to the log file
+ // Redirect stdout and stderr to the log file.
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
@@ -130,71 +146,58 @@
#endif
}
-// Split the comma/space/colum/semi-column separated list of tags from the trace
-// setting and build the trace mask from it. note that '1' and 'all' are special
-// cases to enable all tracing.
+// Split the space separated list of tags from the trace setting and build the
+// trace mask from it. note that '1' and 'all' are special cases to enable all
+// tracing.
//
// adb's trace setting comes from the ADB_TRACE environment variable, whereas
// adbd's comes from the system property persist.adb.trace_mask.
-void adb_trace_init() {
+static void setup_trace_mask() {
const std::string trace_setting = get_trace_setting();
- static const struct {
- const char* tag;
- int flag;
- } tags[] = {
- { "1", 0 },
- { "all", 0 },
- { "adb", TRACE_ADB },
- { "sockets", TRACE_SOCKETS },
- { "packets", TRACE_PACKETS },
- { "rwx", TRACE_RWX },
- { "usb", TRACE_USB },
- { "sync", TRACE_SYNC },
- { "sysdeps", TRACE_SYSDEPS },
- { "transport", TRACE_TRANSPORT },
- { "jdwp", TRACE_JDWP },
- { "services", TRACE_SERVICES },
- { "auth", TRACE_AUTH },
- { NULL, 0 }
- };
+ std::unordered_map<std::string, int> trace_flags = {
+ {"1", 0},
+ {"all", 0},
+ {"adb", TRACE_ADB},
+ {"sockets", TRACE_SOCKETS},
+ {"packets", TRACE_PACKETS},
+ {"rwx", TRACE_RWX},
+ {"usb", TRACE_USB},
+ {"sync", TRACE_SYNC},
+ {"sysdeps", TRACE_SYSDEPS},
+ {"transport", TRACE_TRANSPORT},
+ {"jdwp", TRACE_JDWP},
+ {"services", TRACE_SERVICES},
+ {"auth", TRACE_AUTH}};
- if (trace_setting.empty()) {
- return;
- }
-
- // Use a comma/colon/semi-colon/space separated list
- const char* p = trace_setting.c_str();
- while (*p) {
- int len, tagn;
-
- const char* q = strpbrk(p, " ,:;");
- if (q == NULL) {
- q = p + strlen(p);
+ std::vector<std::string> elements = android::base::Split(trace_setting, " ");
+ for (const auto& elem : elements) {
+ const auto& flag = trace_flags.find(elem);
+ if (flag == trace_flags.end()) {
+ D("Unknown trace flag: %s", flag->first.c_str());
+ continue;
}
- len = q - p;
- for (tagn = 0; tags[tagn].tag != NULL; tagn++) {
- int taglen = strlen(tags[tagn].tag);
-
- if (len == taglen && !memcmp(tags[tagn].tag, p, len)) {
- int flag = tags[tagn].flag;
- if (flag == 0) {
- adb_trace_mask = ~0;
- return;
- }
- adb_trace_mask |= (1 << flag);
- break;
- }
+ if (flag->second == 0) {
+ // 0 is used for the special values "1" and "all" that enable all
+ // tracing.
+ adb_trace_mask = ~0;
+ return;
+ } else {
+ adb_trace_mask |= 1 << flag->second;
}
- p = q;
- if (*p)
- p++;
}
+}
+void adb_trace_init(char** argv) {
#if !ADB_HOST
- start_device_log();
+ if (isatty(STDOUT_FILENO) == 0) {
+ start_device_log();
+ }
#endif
+
+ setup_trace_mask();
+ android::base::InitLogging(argv, AdbLogger);
}
apacket* get_apacket(void)
@@ -718,56 +721,50 @@
return 1;
}
- if (!strncmp(service, "forward:",8) ||
- !strncmp(service, "killforward:",12)) {
- char *local, *remote;
- 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;
+ if (!strncmp(service, "forward:", 8) || !strncmp(service, "killforward:", 12)) {
+ // killforward:local
+ // forward:(norebind:)?local;remote
+ bool kill_forward = false;
+ bool no_rebind = false;
+ if (android::base::StartsWith(service, "killforward:")) {
+ kill_forward = true;
+ service += 12;
+ if (android::base::StartsWith(service, "norebind:")) {
+ no_rebind = true;
+ service += 9;
+ }
+ } else {
+ service += 8;
}
- remote = strchr(local,';');
+ std::vector<std::string> pieces = android::base::Split(service, ";");
- if (createForward) {
- // Check forward: parameter format: '<local>;<remote>'
- if(remote == 0) {
- SendFail(reply_fd, "malformed forward spec");
- return 1;
- }
-
- *remote++ = 0;
- if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
- SendFail(reply_fd, "malformed forward spec");
+ if (kill_forward) {
+ // Check killforward: parameter format: '<local>'
+ if (pieces.size() != 1 || pieces[0].empty()) {
+ SendFail(reply_fd, android::base::StringPrintf("bad killforward: %s", service));
return 1;
}
} else {
- // Check killforward: parameter format: '<local>'
- if (local[0] == 0) {
- SendFail(reply_fd, "malformed forward spec");
+ // Check forward: parameter format: '<local>;<remote>'
+ if (pieces.size() != 2 || pieces[0].empty() || pieces[1].empty() || pieces[1][0] == '*') {
+ SendFail(reply_fd, android::base::StringPrintf("bad forward: %s", service));
return 1;
}
}
std::string error_msg;
- transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
+ atransport* transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
if (!transport) {
SendFail(reply_fd, error_msg);
return 1;
}
InstallStatus r;
- if (createForward) {
- r = install_listener(local, remote, transport, no_rebind);
+ if (kill_forward) {
+ r = remove_listener(pieces[0].c_str(), transport);
} else {
- r = remove_listener(local, transport);
+ r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind);
}
if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
@@ -780,7 +777,7 @@
std::string message;
switch (r) {
- case INSTALL_STATUS_OK: message = " "; break;
+ case INSTALL_STATUS_OK: message = "success (!)"; break;
case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
case INSTALL_STATUS_CANNOT_BIND:
message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
@@ -788,7 +785,9 @@
case INSTALL_STATUS_CANNOT_REBIND:
message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
break;
- case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
+ case INSTALL_STATUS_LISTENER_NOT_FOUND:
+ message = android::base::StringPrintf("listener '%s' not found", service);
+ break;
}
SendFail(reply_fd, message);
return 1;
diff --git a/adb/adb.h b/adb/adb.h
index e8960e3..1be83d7 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -20,6 +20,8 @@
#include <limits.h>
#include <sys/types.h>
+#include <base/macros.h>
+
#include "adb_trace.h"
#include "fdevent.h"
@@ -43,7 +45,7 @@
// Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 32
-struct atransport;
+class atransport;
struct usb_handle;
struct amessage {
@@ -152,20 +154,19 @@
};
-/* a transport object models the connection to a remote device or emulator
-** there is one transport per connected device/emulator. a "local transport"
-** connects through TCP (for the emulator), while a "usb transport" through
-** USB (for real devices)
-**
-** note that kTransportHost doesn't really correspond to a real transport
-** object, it's a special value used to indicate that a client wants to
-** connect to a service implemented within the ADB server itself.
-*/
+// A transport object models the connection to a remote device or emulator there
+// is one transport per connected device/emulator. A "local transport" connects
+// through TCP (for the emulator), while a "usb transport" through USB (for real
+// devices).
+//
+// Note that kTransportHost doesn't really correspond to a real transport
+// object, it's a special value used to indicate that a client wants to connect
+// to a service implemented within the ADB server itself.
enum TransportType {
- kTransportUsb,
- kTransportLocal,
- kTransportAny,
- kTransportHost,
+ kTransportUsb,
+ kTransportLocal,
+ kTransportAny,
+ kTransportHost,
};
#define TOKEN_SIZE 20
@@ -182,47 +183,59 @@
kCsUnauthorized,
};
-struct atransport
-{
- atransport *next;
- atransport *prev;
+class atransport {
+public:
+ // TODO(danalbert): We expose waaaaaaay too much stuff because this was
+ // historically just a struct, but making the whole thing a more idiomatic
+ // class in one go is a very large change. Given how bad our testing is,
+ // it's better to do this piece by piece.
- int (*read_from_remote)(apacket *p, atransport *t);
- int (*write_to_remote)(apacket *p, atransport *t);
- void (*close)(atransport *t);
- void (*kick)(atransport *t);
+ atransport() {
+ auth_fde = {};
+ transport_fde = {};
+ }
- int fd;
- int transport_socket;
+ virtual ~atransport() {}
+
+ int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
+ int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
+ void (*close)(atransport* t) = nullptr;
+ void (*kick)(atransport* t) = nullptr;
+
+ int fd = -1;
+ int transport_socket = -1;
fdevent transport_fde;
- int ref_count;
- unsigned sync_token;
- int connection_state;
- int online;
- TransportType type;
+ int ref_count = 0;
+ uint32_t sync_token = 0;
+ ConnectionState connection_state = kCsOffline;
+ bool online = false;
+ TransportType type = kTransportAny;
- /* usb handle or socket fd as needed */
- usb_handle *usb;
- int sfd;
+ // USB handle or socket fd as needed.
+ usb_handle* usb = nullptr;
+ int sfd = -1;
- /* used to identify transports for clients */
- char *serial;
- char *product;
- char *model;
- char *device;
- char *devpath;
- int adb_port; // Use for emulators (local transport)
+ // Used to identify transports for clients.
+ char* serial = nullptr;
+ char* product = nullptr;
+ char* model = nullptr;
+ char* device = nullptr;
+ char* devpath = nullptr;
+ int adb_port = -1; // Use for emulators (local transport)
+ bool kicked = false;
- /* a list of adisconnect callbacks called when the transport is kicked */
- int kicked;
- adisconnect disconnects;
+ // A list of adisconnect callbacks called when the transport is kicked.
+ adisconnect disconnects = {};
- void *key;
- unsigned char token[TOKEN_SIZE];
+ void* key = nullptr;
+ unsigned char token[TOKEN_SIZE] = {};
fdevent auth_fde;
- unsigned failed_auth_attempts;
+ size_t failed_auth_attempts = 0;
const char* connection_state_name() const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(atransport);
};
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index c73d737..ef9a586 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -256,19 +256,21 @@
}
-int adb_command(const std::string& service, std::string* error) {
- int fd = adb_connect(service, error);
+bool adb_command(const std::string& service) {
+ std::string error;
+ int fd = adb_connect(service, &error);
if (fd < 0) {
- fprintf(stderr, "error: %s\n", error->c_str());
- return -1;
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return false;
}
- if (!adb_status(fd, error)) {
+ if (!adb_status(fd, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
adb_close(fd);
- return -1;
+ return false;
}
- return 0;
+ return true;
}
bool adb_query(const std::string& service, std::string* result, std::string* error) {
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9895c49..5de0638 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -26,9 +26,9 @@
int adb_connect(const std::string& service, std::string* error);
int _adb_connect(const std::string& service, std::string* error);
-// Connect to adb, connect to the named service, return 0 if the connection
-// succeeded AND the service returned OKAY.
-int adb_command(const std::string& service, std::string* error);
+// Connect to adb, connect to the named service, returns true if the connection
+// succeeded AND the service returned OKAY. Outputs any returned error otherwise.
+bool adb_command(const std::string& service);
// Connects to the named adb service and fills 'result' with the response.
// Returns true on success; returns false and fills 'error' on failure.
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index cf193ab..a335eec 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -26,13 +26,12 @@
int gListenAll = 0; /* Not static because it is used in commandline.c. */
-alistener listener_list = {
+static alistener listener_list = {
.next = &listener_list,
.prev = &listener_list,
};
-void ss_listener_event_func(int _fd, unsigned ev, void *_l)
-{
+static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
asocket *s;
if(ev & FDE_READ) {
@@ -56,7 +55,7 @@
}
}
-void listener_event_func(int _fd, unsigned ev, void* _l)
+static void listener_event_func(int _fd, unsigned ev, void* _l)
{
alistener* listener = reinterpret_cast<alistener*>(_l);
asocket *s;
@@ -106,38 +105,27 @@
free(l);
}
-void listener_disconnect(void* listener, atransport* t)
-{
+static void listener_disconnect(void* listener, atransport* t) {
free_listener(reinterpret_cast<alistener*>(listener));
}
-int local_name_to_fd(const char *name)
-{
- int port;
-
- if(!strncmp("tcp:", name, 4)){
- int ret;
- port = atoi(name + 4);
-
+static int local_name_to_fd(const char* name) {
+ if (!strncmp("tcp:", name, 4)) {
+ int port = atoi(name + 4);
if (gListenAll > 0) {
- ret = socket_inaddr_any_server(port, SOCK_STREAM);
+ return socket_inaddr_any_server(port, SOCK_STREAM);
} else {
- ret = socket_loopback_server(port, SOCK_STREAM);
+ return socket_loopback_server(port, SOCK_STREAM);
}
-
- return ret;
}
#ifndef HAVE_WIN32_IPC /* no Unix-domain sockets on Win32 */
- // It's non-sensical to support the "reserved" space on the adb host side
- if(!strncmp(name, "local:", 6)) {
- return socket_local_server(name + 6,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- } else if(!strncmp(name, "localabstract:", 14)) {
- return socket_local_server(name + 14,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
- } else if(!strncmp(name, "localfilesystem:", 16)) {
- return socket_local_server(name + 16,
- ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
+ // It's nonsensical to support the "reserved" space on the adb host side
+ if (!strncmp(name, "local:", 6)) {
+ return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ } else if (!strncmp(name, "localabstract:", 14)) {
+ return socket_local_server(name + 14, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ } else if (!strncmp(name, "localfilesystem:", 16)) {
+ return socket_local_server(name + 16, ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM);
}
#endif
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 9a7ded1..67deb21 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -30,12 +30,6 @@
INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
};
-extern alistener listener_list;
-
-void listener_disconnect(void* _l, atransport* t);
-void listener_event_func(int _fd, unsigned ev, void *_l);
-void ss_listener_event_func(int _fd, unsigned ev, void *_l);
-
InstallStatus install_listener(const std::string& local_name,
const char* connect_to,
atransport* transport,
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 63d4151..dbc7ec8 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -57,9 +57,9 @@
#define DQ(...) ((void)0)
#endif /* !ADB_HOST */
-extern int adb_trace_mask;
-extern unsigned char adb_trace_output_count;
-void adb_trace_init(void);
+extern int adb_trace_mask;
+extern unsigned char adb_trace_output_count;
+void adb_trace_init(char**);
# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index f48182d..0cd6670 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -176,9 +176,7 @@
int main(int argc, char** argv) {
adb_sysdeps_init();
-
- android::base::InitLogging(argv);
- adb_trace_init();
+ adb_trace_init(argv);
D("Handling commandline()\n");
return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index d7bee91..7fbca31 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -680,14 +680,7 @@
}
std::string cmd = format_host_command(service, t, serial);
- std::string error;
- if (adb_command(cmd, &error)) {
- D("failure: %s *\n", error.c_str());
- fprintf(stderr,"error: %s\n", error.c_str());
- return false;
- }
-
- return true;
+ return adb_command(cmd);
}
static int send_shell_command(TransportType transport_type, const char* serial,
@@ -1249,90 +1242,50 @@
if (argc != 1) return usage();
return send_shell_command(transport_type, serial, "shell:bugreport");
}
- /* adb_command() wrapper commands */
else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
- std::string cmd;
- char host_prefix[64];
- char reverse = (char) !strcmp(argv[0], "reverse");
- char remove = 0;
- char remove_all = 0;
- char list = 0;
- char no_rebind = 0;
-
- // Parse options here.
- while (argc > 1 && argv[1][0] == '-') {
- if (!strcmp(argv[1], "--list"))
- list = 1;
- else if (!strcmp(argv[1], "--remove"))
- remove = 1;
- else if (!strcmp(argv[1], "--remove-all"))
- remove_all = 1;
- else if (!strcmp(argv[1], "--no-rebind"))
- no_rebind = 1;
- else {
- return usage();
- }
- argc--;
- argv++;
- }
-
- // Ensure we can only use one option at a time.
- if (list + remove + remove_all + no_rebind > 1) {
- return usage();
- }
+ bool reverse = !strcmp(argv[0], "reverse");
+ ++argv;
+ --argc;
+ if (argc < 1) return usage();
// Determine the <host-prefix> for this command.
+ std::string host_prefix;
if (reverse) {
- snprintf(host_prefix, sizeof host_prefix, "reverse");
+ host_prefix = "reverse";
} else {
if (serial) {
- snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
- serial);
+ host_prefix = android::base::StringPrintf("host-serial:%s", serial);
} else if (transport_type == kTransportUsb) {
- snprintf(host_prefix, sizeof host_prefix, "host-usb");
+ host_prefix = "host-usb";
} else if (transport_type == kTransportLocal) {
- snprintf(host_prefix, sizeof host_prefix, "host-local");
+ host_prefix = "host-local";
} else {
- snprintf(host_prefix, sizeof host_prefix, "host");
+ host_prefix = "host";
}
}
- // Implement forward --list
- if (list) {
- if (argc != 1) {
- return usage();
- }
-
- std::string query = android::base::StringPrintf("%s:list-forward", host_prefix);
- return adb_query_command(query);
- }
-
- // Implement forward --remove-all
- else if (remove_all) {
+ std::string cmd;
+ if (strcmp(argv[0], "--list") == 0) {
if (argc != 1) return usage();
- cmd = android::base::StringPrintf("%s:killforward-all", host_prefix);
- }
-
- // Implement forward --remove <local>
- else if (remove) {
+ return adb_query_command(host_prefix + ":list-forward");
+ } else if (strcmp(argv[0], "--remove-all") == 0) {
+ if (argc != 1) return usage();
+ cmd = host_prefix + ":killforward-all";
+ } else if (strcmp(argv[0], "--remove") == 0) {
+ // forward --remove <local>
if (argc != 2) return usage();
- cmd = android::base::StringPrintf("%s:killforward:%s", host_prefix, argv[1]);
- }
- // Or implement one of:
- // forward <local> <remote>
- // forward --no-rebind <local> <remote>
- else {
+ cmd = host_prefix + ":killforward:" + argv[1];
+ } else if (strcmp(argv[0], "--no-rebind") == 0) {
+ // forward --no-rebind <local> <remote>
if (argc != 3) return usage();
- const char* command = no_rebind ? "forward:norebind" : "forward";
- cmd = android::base::StringPrintf("%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+ cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+ } else {
+ // forward <local> <remote>
+ if (argc != 2) return usage();
+ cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
}
- std::string error;
- if (adb_command(cmd, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
- return 0;
+ return adb_command(cmd) ? 0 : 1;
}
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 99ff539..c0612cd 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -230,8 +230,6 @@
}
int main(int argc, char** argv) {
- android::base::InitLogging(argv);
-
while (true) {
static struct option opts[] = {
{"root_seclabel", required_argument, nullptr, 's'},
@@ -265,7 +263,7 @@
close_stdin();
- adb_trace_init();
+ adb_trace_init(argv);
/* If adbd runs inside the emulator this will enable adb tracing via
* adb-debug qemud service in the emulator. */
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 818ed97..379c702 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -26,6 +26,8 @@
#include <string.h>
#include <unistd.h>
+#include <list>
+
#include <base/stringprintf.h>
#include "adb.h"
@@ -33,15 +35,8 @@
static void transport_unref(atransport *t);
-static atransport transport_list = {
- .next = &transport_list,
- .prev = &transport_list,
-};
-
-static atransport pending_list = {
- .next = &pending_list,
- .prev = &pending_list,
-};
+static std::list<atransport*> transport_list;
+static std::list<atransport*> pending_list;
ADB_MUTEX_DEFINE( transport_lock );
@@ -553,8 +548,7 @@
adb_close(t->fd);
adb_mutex_lock(&transport_lock);
- t->next->prev = t->prev;
- t->prev->next = t->next;
+ transport_list.remove(t);
adb_mutex_unlock(&transport_lock);
run_transport_disconnects(t);
@@ -570,8 +564,7 @@
if (t->devpath)
free(t->devpath);
- memset(t,0xee,sizeof(atransport));
- free(t);
+ delete t;
update_transports();
return;
@@ -582,7 +575,7 @@
/* initial references are the two threads */
t->ref_count = 2;
- if(adb_socketpair(s)) {
+ if (adb_socketpair(s)) {
fatal_errno("cannot open transport socketpair");
}
@@ -608,14 +601,8 @@
}
adb_mutex_lock(&transport_lock);
- /* remove from pending list */
- t->next->prev = t->prev;
- t->prev->next = t->next;
- /* put us on the master device list */
- t->next = &transport_list;
- t->prev = transport_list.prev;
- t->next->prev = t;
- t->prev->next = t;
+ pending_list.remove(t);
+ transport_list.push_front(t);
adb_mutex_unlock(&transport_lock);
t->disconnects.next = t->disconnects.prev = &t->disconnects;
@@ -740,7 +727,6 @@
atransport* acquire_one_transport(ConnectionState state, TransportType type,
const char* serial, std::string* error_out) {
- atransport *t;
atransport *result = NULL;
int ambiguous = 0;
@@ -748,7 +734,7 @@
if (error_out) *error_out = android::base::StringPrintf("device '%s' not found", serial);
adb_mutex_lock(&transport_lock);
- for (t = transport_list.next; t != &transport_list; t = t->next) {
+ for (auto t : transport_list) {
if (t->connection_state == kCsNoPerm) {
if (error_out) *error_out = "insufficient permissions for device";
continue;
@@ -866,7 +852,8 @@
}
}
-static void append_transport(atransport* t, std::string* result, bool long_listing) {
+static void append_transport(const atransport* t, std::string* result,
+ bool long_listing) {
const char* serial = t->serial;
if (!serial || !serial[0]) {
serial = "(no serial number)";
@@ -890,7 +877,7 @@
std::string list_transports(bool long_listing) {
std::string result;
adb_mutex_lock(&transport_lock);
- for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
+ for (const auto t : transport_list) {
append_transport(t, &result, long_listing);
}
adb_mutex_unlock(&transport_lock);
@@ -898,11 +885,10 @@
}
/* hack for osx */
-void close_usb_devices()
-{
+void close_usb_devices() {
adb_mutex_lock(&transport_lock);
- for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
- if ( !t->kicked ) {
+ for (auto t : transport_list) {
+ if (!t->kicked) {
t->kicked = 1;
t->kick(t);
}
@@ -911,47 +897,39 @@
}
#endif // ADB_HOST
-int register_socket_transport(int s, const char *serial, int port, int local)
-{
- atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
- if (t == nullptr) {
- return -1;
- }
-
- atransport *n;
- char buff[32];
+int register_socket_transport(int s, const char *serial, int port, int local) {
+ atransport* t = new atransport();
if (!serial) {
- snprintf(buff, sizeof buff, "T-%p", t);
- serial = buff;
+ char buf[32];
+ snprintf(buf, sizeof(buf), "T-%p", t);
+ serial = buf;
}
+
D("transport: %s init'ing for socket %d, on port %d\n", serial, s, port);
if (init_socket_transport(t, s, port, local) < 0) {
- free(t);
+ delete t;
return -1;
}
adb_mutex_lock(&transport_lock);
- for (n = pending_list.next; n != &pending_list; n = n->next) {
- if (n->serial && !strcmp(serial, n->serial)) {
+ for (auto transport : pending_list) {
+ if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
- free(t);
+ delete t;
return -1;
}
}
- for (n = transport_list.next; n != &transport_list; n = n->next) {
- if (n->serial && !strcmp(serial, n->serial)) {
+ for (auto transport : transport_list) {
+ if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
- free(t);
+ delete t;
return -1;
}
}
- t->next = &pending_list;
- t->prev = pending_list.prev;
- t->next->prev = t;
- t->prev->next = t;
+ pending_list.push_front(t);
t->serial = strdup(serial);
adb_mutex_unlock(&transport_lock);
@@ -960,95 +938,83 @@
}
#if ADB_HOST
-atransport *find_transport(const char *serial)
-{
- atransport *t;
+atransport *find_transport(const char *serial) {
+ atransport* result = nullptr;
adb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
- if (t->serial && !strcmp(serial, t->serial)) {
+ for (auto t : transport_list) {
+ if (t->serial && strcmp(serial, t->serial) == 0) {
+ result = t;
break;
}
- }
+ }
adb_mutex_unlock(&transport_lock);
- if (t != &transport_list)
- return t;
- else
- return 0;
+ return result;
}
void unregister_transport(atransport *t)
{
adb_mutex_lock(&transport_lock);
- t->next->prev = t->prev;
- t->prev->next = t->next;
+ transport_list.remove(t);
adb_mutex_unlock(&transport_lock);
kick_transport(t);
transport_unref(t);
}
-// unregisters all non-emulator TCP transports
-void unregister_all_tcp_transports()
-{
- atransport *t, *next;
+// Unregisters all non-emulator TCP transports.
+void unregister_all_tcp_transports() {
adb_mutex_lock(&transport_lock);
- for (t = transport_list.next; t != &transport_list; t = next) {
- next = t->next;
+ for (auto it = transport_list.begin(); it != transport_list.end(); ) {
+ atransport* t = *it;
if (t->type == kTransportLocal && t->adb_port == 0) {
- t->next->prev = t->prev;
- t->prev->next = next;
- // we cannot call kick_transport when holding transport_lock
- if (!t->kicked)
- {
+ // We cannot call kick_transport when holding transport_lock.
+ if (!t->kicked) {
t->kicked = 1;
t->kick(t);
}
transport_unref_locked(t);
+
+ it = transport_list.erase(it);
+ } else {
+ ++it;
}
- }
+ }
adb_mutex_unlock(&transport_lock);
}
#endif
-void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
-{
- atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
- if (t == nullptr) fatal("cannot allocate USB atransport");
+void register_usb_transport(usb_handle* usb, const char* serial,
+ const char* devpath, unsigned writeable) {
+ atransport* t = new atransport();
+
D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
serial ? serial : "");
init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
if(serial) {
t->serial = strdup(serial);
}
- if(devpath) {
+
+ if (devpath) {
t->devpath = strdup(devpath);
}
adb_mutex_lock(&transport_lock);
- t->next = &pending_list;
- t->prev = pending_list.prev;
- t->next->prev = t;
- t->prev->next = t;
+ pending_list.push_front(t);
adb_mutex_unlock(&transport_lock);
register_transport(t);
}
// This should only be used for transports with connection_state == kCsNoPerm.
-void unregister_usb_transport(usb_handle* usb) {
+void unregister_usb_transport(usb_handle *usb) {
adb_mutex_lock(&transport_lock);
- for (atransport* t = transport_list.next; t != &transport_list;
- t = t->next) {
- if (t->usb == usb && t->connection_state == kCsNoPerm) {
- t->next->prev = t->prev;
- t->prev->next = t->next;
- break;
- }
- }
+ transport_list.remove_if([usb](atransport* t) {
+ return t->usb == usb && t->connection_state == kCsNoPerm;
+ });
adb_mutex_unlock(&transport_lock);
}
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2b3fe3c..4b74adf 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,34 +20,85 @@
#include "adb.h"
+class TestTransport : public atransport {
+public:
+ bool operator==(const atransport& rhs) const {
+ EXPECT_EQ(read_from_remote, rhs.read_from_remote);
+ EXPECT_EQ(write_to_remote, rhs.write_to_remote);
+ EXPECT_EQ(close, rhs.close);
+ EXPECT_EQ(kick, rhs.kick);
+
+ EXPECT_EQ(fd, rhs.fd);
+ EXPECT_EQ(transport_socket, rhs.transport_socket);
+
+ EXPECT_EQ(
+ 0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
+
+ EXPECT_EQ(ref_count, rhs.ref_count);
+ EXPECT_EQ(sync_token, rhs.sync_token);
+ EXPECT_EQ(connection_state, rhs.connection_state);
+ EXPECT_EQ(online, rhs.online);
+ EXPECT_EQ(type, rhs.type);
+
+ EXPECT_EQ(usb, rhs.usb);
+ EXPECT_EQ(sfd, rhs.sfd);
+
+ EXPECT_EQ(serial, rhs.serial);
+ EXPECT_EQ(product, rhs.product);
+ EXPECT_EQ(model, rhs.model);
+ EXPECT_EQ(device, rhs.device);
+ EXPECT_EQ(devpath, rhs.devpath);
+ EXPECT_EQ(adb_port, rhs.adb_port);
+ EXPECT_EQ(kicked, rhs.kicked);
+
+ EXPECT_EQ(
+ 0, memcmp(&disconnects, &rhs.disconnects, sizeof(adisconnect)));
+
+ EXPECT_EQ(key, rhs.key);
+ EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
+ EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
+ EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
+
+ return true;
+ }
+};
+
TEST(transport, kick_transport) {
- atransport t = {};
+ TestTransport t;
+
// Mutate some member so we can test that the function is run.
t.kick = [](atransport* trans) { trans->fd = 42; };
- atransport expected = t;
+
+ TestTransport expected;
+ expected.kick = t.kick;
expected.fd = 42;
expected.kicked = 1;
+
kick_transport(&t);
ASSERT_EQ(42, t.fd);
ASSERT_EQ(1, t.kicked);
- ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+ ASSERT_EQ(expected, t);
}
TEST(transport, kick_transport_already_kicked) {
// Ensure that the transport is not modified if the transport has already been
// kicked.
- atransport t = {};
+ TestTransport t;
t.kicked = 1;
t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
- atransport expected = t;
+
+ TestTransport expected;
+ expected.kicked = 1;
+ expected.kick = t.kick;
+
kick_transport(&t);
- ASSERT_EQ(0, memcmp(&expected, &t, sizeof(atransport)));
+ ASSERT_EQ(expected, t);
}
// Disabled because the function currently segfaults for a zeroed atransport. I
// want to make sure I understand how this is working at all before I try fixing
// that.
TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
- atransport t = {};
+ atransport t;
run_transport_disconnects(&t);
}
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index 5dbc5fb..638f845 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -17,6 +17,7 @@
#ifndef BASE_STRINGS_H
#define BASE_STRINGS_H
+#include <sstream>
#include <string>
#include <vector>
@@ -34,9 +35,24 @@
// Trims whitespace off both ends of the given string.
std::string Trim(const std::string& s);
-// Joins a vector of strings into a single string, using the given separator.
-template <typename StringT>
-std::string Join(const std::vector<StringT>& strings, char separator);
+// Joins a container of things into a single string, using the given separator.
+template <typename ContainerT>
+std::string Join(const ContainerT& things, char separator) {
+ if (things.empty()) {
+ return "";
+ }
+
+ std::ostringstream result;
+ result << *things.begin();
+ for (auto it = std::next(things.begin()); it != things.end(); ++it) {
+ result << separator << *it;
+ }
+ return result.str();
+}
+
+// We instantiate the common cases in strings.cpp.
+extern template std::string Join(const std::vector<std::string>&, char);
+extern template std::string Join(const std::vector<const char*>&, char);
// Tests whether 's' starts with 'prefix'.
bool StartsWith(const std::string& s, const char* prefix);
diff --git a/base/strings.cpp b/base/strings.cpp
index d3375d9..bac983b 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -79,25 +79,10 @@
return s.substr(start_index, end_index - start_index + 1);
}
-template <typename StringT>
-std::string Join(const std::vector<StringT>& strings, char separator) {
- if (strings.empty()) {
- return "";
- }
-
- std::string result(strings[0]);
- for (size_t i = 1; i < strings.size(); ++i) {
- result += separator;
- result += strings[i];
- }
- return result;
-}
-
-// Explicit instantiations.
-template std::string Join<std::string>(const std::vector<std::string>& strings,
- char separator);
-template std::string Join<const char*>(const std::vector<const char*>& strings,
- char separator);
+// These cases are probably the norm, so we mark them extern in the header to
+// aid compile time and binary size.
+template std::string Join(const std::vector<std::string>&, char);
+template std::string Join(const std::vector<const char*>&, char);
bool StartsWith(const std::string& s, const char* prefix) {
return s.compare(0, strlen(prefix), prefix) == 0;
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 46a1ab5..5f67575 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -20,6 +20,8 @@
#include <string>
#include <vector>
+#include <set>
+#include <unordered_set>
TEST(strings, split_empty) {
std::vector<std::string> parts = android::base::Split("", ",");
@@ -121,6 +123,17 @@
ASSERT_EQ(",,,", android::base::Join(list, ','));
}
+TEST(strings, join_simple_ints) {
+ std::set<int> list = {1, 2, 3};
+ ASSERT_EQ("1,2,3", android::base::Join(list, ','));
+}
+
+TEST(strings, join_unordered_set) {
+ std::unordered_set<int> list = {1, 2};
+ ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
+ "2,1" == android::base::Join(list, ','));
+}
+
TEST(strings, startswith_empty) {
ASSERT_FALSE(android::base::StartsWith("", "foo"));
ASSERT_TRUE(android::base::StartsWith("", ""));
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index dd53296..1a5f05e 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,4 +1,12 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
+
+common_cppflags := \
+ -std=gnu++11 \
+ -W \
+ -Wall \
+ -Wextra \
+ -Wunused \
+ -Werror \
include $(CLEAR_VARS)
@@ -17,11 +25,7 @@
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
-LOCAL_CPPFLAGS := \
- -std=gnu++11 \
- -W -Wall -Wextra \
- -Wunused \
- -Werror \
+LOCAL_CPPFLAGS := $(common_cppflags)
ifeq ($(TARGET_IS_64_BIT),true)
LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
@@ -70,3 +74,47 @@
LOCAL_MULTILIB := both
include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ utility.cpp \
+ test/dump_memory_test.cpp \
+ test/log_fake.cpp \
+
+LOCAL_MODULE := debuggerd_test
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace \
+ libbase \
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
+LOCAL_CPPFLAGS := $(common_cppflags)
+
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ utility.cpp \
+ test/dump_memory_test.cpp \
+ test/log_fake.cpp \
+
+LOCAL_MODULE := debuggerd_test
+
+LOCAL_SHARED_LIBRARIES := \
+ libbacktrace \
+ libbase \
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
+LOCAL_CPPFLAGS := $(common_cppflags)
+
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+LOCAL_MULTILIB := both
+
+include $(BUILD_NATIVE_TEST)
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 50e78c5..b7d6997 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -16,53 +16,39 @@
*/
#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/user.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
-void dump_memory_and_code(log_t* log, pid_t tid) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs regs;
- if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, ®s)) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- 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];
-
- // 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);
+ dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", ®_names[reg * 2]);
}
- // explicitly allow upload of code dump logging
- _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
if (regs.ARM_pc != regs.ARM_lr) {
- _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
- dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
}
}
void dump_registers(log_t* log, pid_t tid) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
@@ -82,7 +68,7 @@
user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
- _LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get FP registers: %s\n", strerror(errno));
return;
}
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 8b17d53..2e097da 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -17,50 +17,37 @@
#include <elf.h>
#include <errno.h>
-#include <inttypes.h>
+#include <stdint.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/ptrace.h>
-#include <sys/user.h>
#include <sys/uio.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
-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);
+#include "machine.h"
+#include "utility.h"
- if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
- _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
- __func__, strerror(errno));
- return;
- }
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+ struct user_pt_regs regs;
+ struct iovec io;
+ io.iov_base = ®s;
+ io.iov_len = sizeof(regs);
- for (int reg = 0; reg < 31; reg++) {
- uintptr_t addr = regs.regs[reg];
+ if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
+ _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s",
+ __func__, strerror(errno));
+ return;
+ }
- /*
- * 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;
- }
+ for (int reg = 0; reg < 31; reg++) {
+ dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
+ }
- _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
- dump_memory(log, tid, addr);
- }
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
- _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.pc);
-
- if (regs.pc != regs.sp) {
- _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
- dump_memory(log, tid, (uintptr_t)regs.sp);
- }
+ if (regs.pc != regs.sp) {
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
+ }
}
void dump_registers(log_t* log, pid_t tid) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 039b8ec..b84a4e5 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -279,7 +279,7 @@
char ehdr[EI_NIDENT];
ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &ehdr, sizeof(ehdr)));
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
return false;
}
@@ -304,14 +304,14 @@
if (TEMP_FAILURE_RETRY(write(sock_fd, &msg, sizeof(msg))) != (ssize_t) sizeof(msg)) {
ALOGE("Failed to write request to debuggerd32 socket: %s", strerror(errno));
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
return;
}
char ack;
if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) == -1) {
ALOGE("Failed to read ack from debuggerd32 socket: %s", strerror(errno));
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
return;
}
@@ -338,7 +338,7 @@
break;
}
}
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
}
#endif
@@ -365,7 +365,7 @@
ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n",
request.action);
}
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return;
}
#endif
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index fca9fbe..e65b147 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -19,9 +19,11 @@
#include <sys/types.h>
+#include <backtrace/Backtrace.h>
+
#include "utility.h"
-void dump_memory_and_code(log_t* log, pid_t tid);
+void dump_memory_and_code(log_t* log, Backtrace* backtrace);
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 1145963..f7b8a86 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -14,30 +14,29 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
#include <sys/ptrace.h>
-#include <sys/user.h>
+#include <backtrace/Backtrace.h>
-#include "../utility.h"
-#include "../machine.h"
+#include "machine.h"
+#include "utility.h"
-#define R(x) (static_cast<unsigned int>(x))
+#define R(x) (static_cast<uintptr_t>(x))
// 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) {
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+ static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
for (int reg = 0; reg < 32; reg++) {
// skip uninteresting registers
@@ -48,27 +47,14 @@
)
continue;
- 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, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr);
+ dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", ®_names[reg * 2]);
}
- unsigned int pc = R(r.cp0_epc);
- unsigned int ra = R(r.regs[31]);
-
- _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc);
-
+ uintptr_t pc = R(r.cp0_epc);
+ uintptr_t ra = R(r.regs[31]);
+ dump_memory(log, backtrace, pc, "code around pc:");
if (pc != ra) {
- _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra);
+ dump_memory(log, backtrace, ra, "code around ra:");
}
}
@@ -79,22 +65,31 @@
return;
}
- _LOG(log, logtype::REGISTERS, " zr %08x at %08x v0 %08x v1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR " at %08" PRIxPTR
+ " v0 %08" PRIxPTR " v1 %08" PRIxPTR "\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, logtype::REGISTERS, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR " a1 %08" PRIxPTR
+ " a2 %08" PRIxPTR " a3 %08" PRIxPTR "\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, logtype::REGISTERS, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR " t1 %08" PRIxPTR
+ " t2 %08" PRIxPTR " t3 %08" PRIxPTR "\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, logtype::REGISTERS, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR " t5 %08" PRIxPTR
+ " t6 %08" PRIxPTR " t7 %08" PRIxPTR "\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, logtype::REGISTERS, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR " s1 %08" PRIxPTR
+ " s2 %08" PRIxPTR " s3 %08" PRIxPTR "\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, logtype::REGISTERS, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
+ _LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR " s5 %08" PRIxPTR
+ " s6 %08" PRIxPTR " s7 %08" PRIxPTR "\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, logtype::REGISTERS, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
+ _LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR " t9 %08" PRIxPTR
+ " k0 %08" PRIxPTR " k1 %08" PRIxPTR "\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, logtype::REGISTERS, " gp %08x sp %08x s8 %08x ra %08x\n",
+ _LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR " sp %08" PRIxPTR
+ " s8 %08" PRIxPTR " ra %08" PRIxPTR "\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\n",
+ _LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR " lo %08" PRIxPTR
+ " bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
index ef9092f..293dcf6 100644
--- a/debuggerd/mips64/machine.cpp
+++ b/debuggerd/mips64/machine.cpp
@@ -14,30 +14,29 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <string.h>
#include <sys/ptrace.h>
-#include <sys/user.h>
+#include <backtrace/Backtrace.h>
-#include "../utility.h"
-#include "../machine.h"
+#include "machine.h"
+#include "utility.h"
-#define R(x) (static_cast<unsigned long>(x))
+#define R(x) (static_cast<uintptr_t>(x))
// 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) {
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
- static const char REG_NAMES[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+ static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
for (int reg = 0; reg < 32; reg++) {
// skip uninteresting registers
@@ -48,27 +47,14 @@
)
continue;
- 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 >= 0x4000000000000000) {
- continue;
- }
-
- _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]);
- dump_memory(log, tid, addr);
+ dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", ®_names[reg * 2]);
}
- unsigned long pc = R(r.cp0_epc);
- unsigned long ra = R(r.regs[31]);
-
- _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)pc);
-
+ uintptr_t pc = R(r.cp0_epc);
+ uintptr_t ra = R(r.regs[31]);
+ dump_memory(log, backtrace, pc, "code around pc:");
if (pc != ra) {
- _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
- dump_memory(log, tid, (uintptr_t)ra);
+ dump_memory(log, backtrace, ra, "code around ra:");
}
}
@@ -79,22 +65,31 @@
return;
}
- _LOG(log, logtype::REGISTERS, " zr %016lx at %016lx v0 %016lx v1 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR " at %016" PRIxPTR
+ " v0 %016" PRIxPTR " v1 %016" PRIxPTR "\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, logtype::REGISTERS, " a0 %016lx a1 %016lx a2 %016lx a3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR " a1 %016" PRIxPTR
+ " a2 %016" PRIxPTR " a3 %016" PRIxPTR "\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, logtype::REGISTERS, " a4 %016lx a5 %016lx a6 %016lx a7 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR " a5 %016" PRIxPTR
+ " a6 %016" PRIxPTR " a7 %016" PRIxPTR "\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, logtype::REGISTERS, " t0 %016lx t1 %016lx t2 %016lx t3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR " t1 %016" PRIxPTR
+ " t2 %016" PRIxPTR " t3 %016" PRIxPTR "\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, logtype::REGISTERS, " s0 %016lx s1 %016lx s2 %016lx s3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR " s1 %016" PRIxPTR
+ " s2 %016" PRIxPTR " s3 %016" PRIxPTR "\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, logtype::REGISTERS, " s4 %016lx s5 %016lx s6 %016lx s7 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR " s5 %016" PRIxPTR
+ " s6 %016" PRIxPTR " s7 %016" PRIxPTR "\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, logtype::REGISTERS, " t8 %016lx t9 %016lx k0 %016lx k1 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR " t9 %016" PRIxPTR
+ " k0 %016" PRIxPTR " k1 %016" PRIxPTR "\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, logtype::REGISTERS, " gp %016lx sp %016lx s8 %016lx ra %016lx\n",
+ _LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR " sp %016" PRIxPTR
+ " s8 %016" PRIxPTR " ra %016" PRIxPTR "\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, logtype::REGISTERS, " hi %016lx lo %016lx bva %016lx epc %016lx\n",
+ _LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR " lo %016" PRIxPTR
+ " bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
new file mode 100644
index 0000000..05ad12b
--- /dev/null
+++ b/debuggerd/test/BacktraceMock.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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 _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ucontext.h>
+
+#include <string>
+#include <vector>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+class BacktraceMapMock : public BacktraceMap {
+ public:
+ BacktraceMapMock() : BacktraceMap(0) {}
+ virtual ~BacktraceMapMock() {}
+};
+
+
+class BacktraceMock : public Backtrace {
+ public:
+ BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
+ if (map_ == nullptr) {
+ abort();
+ }
+ }
+ virtual ~BacktraceMock() {}
+
+ virtual bool Unwind(size_t, ucontext_t*) { return false; }
+ virtual bool ReadWord(uintptr_t, word_t*) { return false;}
+
+ virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
+
+ virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+ size_t offset = 0;
+ if (last_read_addr_ > 0) {
+ offset = addr - last_read_addr_;
+ }
+ size_t bytes_available = buffer_.size() - offset;
+
+ if (bytes_partial_read_ > 0) {
+ // Do a partial read.
+ if (bytes > bytes_partial_read_) {
+ bytes = bytes_partial_read_;
+ }
+ bytes_partial_read_ -= bytes;
+ } else if (bytes > bytes_available) {
+ bytes = bytes_available;
+ }
+
+ if (bytes > 0) {
+ memcpy(buffer, buffer_.data() + offset, bytes);
+ }
+
+ last_read_addr_ = addr;
+ return bytes;
+ }
+
+ void SetReadData(uint8_t* buffer, size_t bytes) {
+ buffer_.resize(bytes);
+ memcpy(buffer_.data(), buffer, bytes);
+ bytes_partial_read_ = 0;
+ last_read_addr_ = 0;
+ }
+
+ void SetPartialReadAmount(size_t bytes) {
+ if (bytes > buffer_.size()) {
+ abort();
+ }
+ bytes_partial_read_ = bytes;
+ }
+
+ private:
+ std::vector<uint8_t> buffer_;
+ size_t bytes_partial_read_ = 0;
+ uintptr_t last_read_addr_ = 0;
+};
+
+#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
new file mode 100644
index 0000000..fcb0108
--- /dev/null
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 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 <stdlib.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <base/file.h>
+
+#include "BacktraceMock.h"
+#include "log_fake.h"
+#include "utility.h"
+
+const char g_expected_full_dump[] =
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+" 0000000012345658 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 0000000012345668 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 0000000012345678 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 0000000012345688 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 0000000012345698 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 00000000123456a8 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 00000000123456b8 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
+" 00000000123456c8 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
+" 00000000123456d8 8786858483828180 8f8e8d8c8b8a8988 ................\n"
+" 00000000123456e8 9796959493929190 9f9e9d9c9b9a9998 ................\n"
+" 00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
+" 0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
+" 0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
+" 0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
+" 0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
+" 0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+#else
+" 12345658 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" 12345668 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" 12345678 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" 12345688 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" 12345698 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" 123456a8 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" 123456b8 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
+" 123456c8 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
+" 123456d8 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
+" 123456e8 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
+" 123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
+" 12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
+" 12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
+" 12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
+" 12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
+" 12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
+#endif
+
+const char g_expected_partial_dump[] = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 0000000012345640 6766656463626160 ---------------- `abcdefg........\n"
+" 0000000012345650 ---------------- ---------------- ................\n"
+" 0000000012345660 ---------------- ---------------- ................\n"
+" 0000000012345670 ---------------- ---------------- ................\n"
+" 0000000012345680 ---------------- ---------------- ................\n"
+" 0000000012345690 ---------------- ---------------- ................\n"
+" 00000000123456a0 ---------------- ---------------- ................\n"
+" 00000000123456b0 ---------------- ---------------- ................\n"
+" 00000000123456c0 ---------------- ---------------- ................\n"
+" 00000000123456d0 ---------------- ---------------- ................\n";
+#else
+" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" 12345640 63626160 67666564 -------- -------- `abcdefg........\n"
+" 12345650 -------- -------- -------- -------- ................\n"
+" 12345660 -------- -------- -------- -------- ................\n"
+" 12345670 -------- -------- -------- -------- ................\n"
+" 12345680 -------- -------- -------- -------- ................\n"
+" 12345690 -------- -------- -------- -------- ................\n"
+" 123456a0 -------- -------- -------- -------- ................\n"
+" 123456b0 -------- -------- -------- -------- ................\n"
+" 123456c0 -------- -------- -------- -------- ................\n"
+" 123456d0 -------- -------- -------- -------- ................\n";
+#endif
+
+class DumpMemoryTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ map_mock_.reset(new BacktraceMapMock());
+ backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+
+ char tmp_file[256];
+ const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, data_template, sizeof(data_template));
+ int tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+ tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ abort();
+ }
+ }
+ if (unlink(tmp_file) == -1) {
+ abort();
+ }
+
+ log_.tfd = tombstone_fd;
+ log_.amfd = -1;
+ log_.crashed_tid = 12;
+ log_.current_tid = 12;
+ log_.should_retrieve_logcat = false;
+
+ resetLogs();
+ }
+
+ virtual void TearDown() {
+ if (log_.tfd >= 0) {
+ close(log_.tfd);
+ }
+ }
+
+ std::unique_ptr<BacktraceMapMock> map_mock_;
+ std::unique_ptr<BacktraceMock> backtrace_mock_;
+
+ log_t log_;
+};
+
+TEST_F(DumpMemoryTest, aligned_addr) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, partial_read) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(96);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, unaligned_addr) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_unreadable) {
+ dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+" 00000000a2345658 ---------------- ---------------- ................\n"
+" 00000000a2345668 ---------------- ---------------- ................\n"
+" 00000000a2345678 ---------------- ---------------- ................\n"
+" 00000000a2345688 ---------------- ---------------- ................\n"
+" 00000000a2345698 ---------------- ---------------- ................\n"
+" 00000000a23456a8 ---------------- ---------------- ................\n"
+" 00000000a23456b8 ---------------- ---------------- ................\n"
+" 00000000a23456c8 ---------------- ---------------- ................\n"
+" 00000000a23456d8 ---------------- ---------------- ................\n"
+" 00000000a23456e8 ---------------- ---------------- ................\n"
+" 00000000a23456f8 ---------------- ---------------- ................\n"
+" 00000000a2345708 ---------------- ---------------- ................\n"
+" 00000000a2345718 ---------------- ---------------- ................\n"
+" 00000000a2345728 ---------------- ---------------- ................\n"
+" 00000000a2345738 ---------------- ---------------- ................\n"
+" 00000000a2345748 ---------------- ---------------- ................\n";
+#else
+" a2345658 -------- -------- -------- -------- ................\n"
+" a2345668 -------- -------- -------- -------- ................\n"
+" a2345678 -------- -------- -------- -------- ................\n"
+" a2345688 -------- -------- -------- -------- ................\n"
+" a2345698 -------- -------- -------- -------- ................\n"
+" a23456a8 -------- -------- -------- -------- ................\n"
+" a23456b8 -------- -------- -------- -------- ................\n"
+" a23456c8 -------- -------- -------- -------- ................\n"
+" a23456d8 -------- -------- -------- -------- ................\n"
+" a23456e8 -------- -------- -------- -------- ................\n"
+" a23456f8 -------- -------- -------- -------- ................\n"
+" a2345708 -------- -------- -------- -------- ................\n"
+" a2345718 -------- -------- -------- -------- ................\n"
+" a2345728 -------- -------- -------- -------- ................\n"
+" a2345738 -------- -------- -------- -------- ................\n"
+" a2345748 -------- -------- -------- -------- ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable) {
+ uint8_t buffer[104];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_unaligned_return) {
+ uint8_t buffer[104];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(102);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+ ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
+#else
+ ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str());
+#endif
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
+ uint8_t buffer[106];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(45);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+ ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 8\n"
+ "DEBUG Bytes after second read 106, is not a multiple of 8\n",
+ getFakeLogPrint().c_str());
+#else
+ ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 4\n"
+ "DEBUG Bytes after second read 106, is not a multiple of 4\n",
+ getFakeLogPrint().c_str());
+#endif
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, address_low_fence) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+" 0000000000001000 0000000000000000 0000000000000000 ................\n"
+" 0000000000001010 0000000000000000 0000000000000000 ................\n"
+" 0000000000001020 0000000000000000 0000000000000000 ................\n"
+" 0000000000001030 0000000000000000 0000000000000000 ................\n"
+" 0000000000001040 0000000000000000 0000000000000000 ................\n"
+" 0000000000001050 0000000000000000 0000000000000000 ................\n"
+" 0000000000001060 0000000000000000 0000000000000000 ................\n"
+" 0000000000001070 0000000000000000 0000000000000000 ................\n"
+" 0000000000001080 0000000000000000 0000000000000000 ................\n"
+" 0000000000001090 0000000000000000 0000000000000000 ................\n"
+" 00000000000010a0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010b0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010c0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010d0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010e0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010f0 0000000000000000 0000000000000000 ................\n";
+#else
+" 00001000 00000000 00000000 00000000 00000000 ................\n"
+" 00001010 00000000 00000000 00000000 00000000 ................\n"
+" 00001020 00000000 00000000 00000000 00000000 ................\n"
+" 00001030 00000000 00000000 00000000 00000000 ................\n"
+" 00001040 00000000 00000000 00000000 00000000 ................\n"
+" 00001050 00000000 00000000 00000000 00000000 ................\n"
+" 00001060 00000000 00000000 00000000 00000000 ................\n"
+" 00001070 00000000 00000000 00000000 00000000 ................\n"
+" 00001080 00000000 00000000 00000000 00000000 ................\n"
+" 00001090 00000000 00000000 00000000 00000000 ................\n"
+" 000010a0 00000000 00000000 00000000 00000000 ................\n"
+" 000010b0 00000000 00000000 00000000 00000000 ................\n"
+" 000010c0 00000000 00000000 00000000 00000000 ................\n"
+" 000010d0 00000000 00000000 00000000 00000000 ................\n"
+" 000010e0 00000000 00000000 00000000 00000000 ................\n"
+" 000010f0 00000000 00000000 00000000 00000000 ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_low) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_high) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_would_overflow) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+" 3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
+" 3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
+" 3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n"
+" 3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n"
+" 3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
+" 3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
+" 3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
+" 3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
+" 3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
+" 3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+#else
+" fffeff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" fffeff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" fffeff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" fffeff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" fffeff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" fffeff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" fffeff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
+" fffeff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
+" fffeff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
+" fffeff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
+" fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
+" fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
+" fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
+" fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
+" fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
+" fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
new file mode 100644
index 0000000..1161afe
--- /dev/null
+++ b/debuggerd/test/log_fake.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 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 <stdarg.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+
+std::string g_fake_log_buf;
+
+std::string g_fake_log_print;
+
+void resetLogs() {
+ g_fake_log_buf = "";
+ g_fake_log_print = "";
+}
+
+extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
+ g_fake_log_buf += tag;
+ g_fake_log_buf += ' ';
+ g_fake_log_buf += msg;
+ return 1;
+}
+
+std::string getFakeLogBuf() {
+ return g_fake_log_buf;
+}
+
+extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
+ g_fake_log_print += tag;
+ g_fake_log_print += ' ';
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&g_fake_log_print, fmt, ap);
+ va_end(ap);
+
+ g_fake_log_print += '\n';
+
+ return 1;
+}
+
+std::string getFakeLogPrint() {
+ return g_fake_log_print;
+}
diff --git a/debuggerd/test/log_fake.h b/debuggerd/test/log_fake.h
new file mode 100644
index 0000000..5418fce
--- /dev/null
+++ b/debuggerd/test/log_fake.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 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 _DEBUGGERD_TEST_LOG_FAKE_H
+#define _DEBUGGERD_TEST_LOG_FAKE_H
+
+#include <string>
+
+void resetLogs();
+std::string getFakeLogBuf();
+std::string getFakeLogPrint();
+
+#endif // _DEBUGGERD_TEST_LOG_FAKE_H
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index ccdfe85..614edb6 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -654,7 +654,7 @@
} else {
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
- dump_memory_and_code(log, tid);
+ dump_memory_and_code(log, backtrace.get());
if (map.get() != nullptr) {
dump_all_maps(backtrace.get(), map.get(), log, tid);
}
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e722f82..9f340a8 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -27,6 +27,7 @@
#include <backtrace/Backtrace.h>
#include <base/file.h>
+#include <base/stringprintf.h>
#include <log/log.h>
const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
@@ -118,68 +119,91 @@
return -1;
}
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
- char code_buffer[64];
- char ascii_buffer[32];
- uintptr_t p, end;
+#define MEMORY_BYTES_TO_DUMP 256
+#define MEMORY_BYTES_PER_LINE 16
- p = addr & ~(sizeof(long) - 1);
- /* Dump 32 bytes before addr */
- p -= 32;
- if (p > addr) {
- /* catch underflow */
- p = 0;
- }
- /* Dump 256 bytes */
- end = p + 256;
- /* catch overflow; 'end - p' has to be multiples of 16 */
- while (end < p) {
- end -= 16;
- }
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
+ std::string log_msg;
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&log_msg, fmt, ap);
+ va_end(ap);
- /* Dump the code around PC as:
- * addr contents ascii
- * 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
- * 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
- * On 32-bit machines, there are still 16 bytes per line but addresses and
- * words are of course presented differently.
- */
- while (p < end) {
- char* asc_out = ascii_buffer;
+ // Align the address to sizeof(long) and start 32 bytes before the address.
+ addr &= ~(sizeof(long) - 1);
+ if (addr >= 4128) {
+ addr -= 32;
+ }
- int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
-
- for (size_t i = 0; i < 16/sizeof(long); i++) {
- long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
- if (data == -1 && errno != 0) {
- // ptrace failed, probably because we're dumping memory in an
- // unmapped or inaccessible page.
-#ifdef __LP64__
- len += sprintf(code_buffer + len, "---------------- ");
+ // Don't bother if the address looks too low, or looks too high.
+ if (addr < 4096 ||
+#if defined(__LP64__)
+ addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
#else
- len += sprintf(code_buffer + len, "-------- ");
+ addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
#endif
- } else {
- len += sprintf(code_buffer + len, "%" PRIPTR " ",
- static_cast<uintptr_t>(data));
- }
+ return;
+ }
- for (size_t j = 0; j < sizeof(long); j++) {
- /*
- * Our isprint() allows high-ASCII characters that display
- * differently (often badly) in different viewers, so we
- * just use a simpler test.
- */
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
- p += sizeof(long);
- }
- *asc_out = '\0';
- _LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
+ _LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
+
+ // Dump 256 bytes
+ uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
+ memset(data, 0, MEMORY_BYTES_TO_DUMP);
+ size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
+ if (bytes % sizeof(uintptr_t) != 0) {
+ // This should never happen, but just in case.
+ ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+ bytes &= ~(sizeof(uintptr_t) - 1);
+ }
+
+ if (bytes < MEMORY_BYTES_TO_DUMP && bytes > 0) {
+ // Try to do one more read. This could happen if a read crosses a map, but
+ // the maps do not have any break between them. Only requires one extra
+ // read because a map has to contain at least one page, and the total
+ // number of bytes to dump is smaller than a page.
+ size_t bytes2 = backtrace->Read(addr + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+ sizeof(data) - bytes);
+ bytes += bytes2;
+ if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
+ // This should never happen, but we'll try and continue any way.
+ ALOGE("Bytes after second read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+ bytes &= ~(sizeof(uintptr_t) - 1);
}
+ }
+
+ // Dump the code around memory as:
+ // addr contents ascii
+ // 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
+ // 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
+ // On 32-bit machines, there are still 16 bytes per line but addresses and
+ // words are of course presented differently.
+ uintptr_t* data_ptr = data;
+ for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
+ std::string logline;
+ android::base::StringAppendF(&logline, " %" PRIPTR, addr);
+
+ addr += MEMORY_BYTES_PER_LINE;
+ std::string ascii;
+ for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++, data_ptr++) {
+ if (bytes >= sizeof(uintptr_t)) {
+ bytes -= sizeof(uintptr_t);
+ android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
+
+ // Fill out the ascii string from the data.
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
+ for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
+ if (*ptr >= 0x20 && *ptr < 0x7f) {
+ ascii += *ptr;
+ } else {
+ ascii += '.';
+ }
+ }
+ } else {
+ logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
+ ascii += std::string(sizeof(uintptr_t), '.');
+ }
+ }
+ _LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
+ }
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 49b46e8..263374d 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
#include <stdbool.h>
#include <sys/types.h>
+#include <backtrace/Backtrace.h>
+
// Figure out the abi based on defined macros.
#if defined(__arm__)
#define ABI_STRING "arm"
@@ -75,6 +77,6 @@
int wait_for_sigstop(pid_t, int*, bool*);
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 57330c1..c5f9259 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -14,18 +14,31 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
#include <sys/ptrace.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
-void dump_memory_and_code(log_t*, pid_t) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+ struct pt_regs r;
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
}
void dump_registers(log_t* log, pid_t tid) {
@@ -34,6 +47,7 @@
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
+
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
_LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
old mode 100755
new mode 100644
index af4f35a..4f09a5d
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -14,38 +14,51 @@
** limitations under the License.
*/
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <sys/ptrace.h>
+#include <string.h>
#include <sys/user.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
-void dump_memory_and_code(log_t*, pid_t) {
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+ struct user_regs_struct r;
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
}
void dump_registers(log_t* log, pid_t tid) {
- struct user_regs_struct r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
- return;
- }
- _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
- r.rax, r.rbx, r.rcx, r.rdx);
- _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
- r.rsi, r.rdi);
- _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
- r.r8, r.r9, r.r10, r.r11);
- _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
- r.r12, r.r13, r.r14, r.r15);
- _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
- r.cs, r.ss);
- _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
- r.rip, r.rbp, r.rsp, r.eflags);
+ struct user_regs_struct r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
+ r.rax, r.rbx, r.rcx, r.rdx);
+ _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
+ r.rsi, r.rdi);
+ _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
+ r.r8, r.r9, r.r10, r.r11);
+ _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
+ r.r12, r.r13, r.r14, r.r15);
+ _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
+ r.cs, r.ss);
+ _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
+ r.rip, r.rbp, r.rsp, r.eflags);
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index d5e94ac..bb2bed2 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -203,7 +203,7 @@
}
rc = ioctl(fd, BLKROSET, &ON);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return rc;
}
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 63b23b9..81c7c9a 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -169,20 +169,20 @@
if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) {
ERROR("Error seeking to superblock");
- TEMP_FAILURE_RETRY(close(data_device));
+ close(data_device);
return -1;
}
if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) {
ERROR("Error reading superblock");
- TEMP_FAILURE_RETRY(close(data_device));
+ close(data_device);
return -1;
}
ext4_parse_sb(&sb, &info);
*device_size = info.len;
- TEMP_FAILURE_RETRY(close(data_device));
+ close(data_device);
return 0;
}
@@ -301,7 +301,7 @@
out:
if (device != -1)
- TEMP_FAILURE_RETRY(close(device));
+ close(device);
if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
free(*signature);
@@ -470,7 +470,7 @@
out:
if (fd != -1) {
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
return rc;
@@ -622,7 +622,7 @@
out:
if (fd != -1) {
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
return rc;
@@ -670,7 +670,7 @@
out:
if (fd != -1) {
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
return rc;
@@ -745,7 +745,7 @@
free(signature);
if (fd != -1) {
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
return rc;
@@ -913,7 +913,7 @@
}
if (fd) {
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
}
return rc;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 9e5f9ff..ca31c50 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -591,7 +591,13 @@
int do_trigger(int nargs, char **args)
{
- action_for_each_trigger(args[1], action_add_queue_tail);
+ char prop_val[PROP_VALUE_MAX];
+ int res = expand_props(prop_val, args[1], sizeof(prop_val));
+ if (res) {
+ ERROR("trigger: cannot expand '%s'\n", args[1]);
+ return -EINVAL;
+ }
+ action_for_each_trigger(prop_val, action_add_queue_tail);
return 0;
}
diff --git a/init/util.cpp b/init/util.cpp
index 9c62f68..8216892 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -171,7 +171,7 @@
}
bool okay = android::base::ReadFdToString(fd, content);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return okay;
}
@@ -185,7 +185,7 @@
if (result == -1) {
NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno));
}
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return result;
}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 95cd4d1..2714d93 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -96,7 +96,7 @@
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());
+ BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
return;
}
@@ -109,9 +109,14 @@
// the thread run ahead causing problems.
// The number indicates that we are waiting for the second Wake() call
// overall which is made by the thread requesting an unwind.
- entry->Wait(2);
-
- ThreadEntry::Remove(entry);
+ if (entry->Wait(2)) {
+ // Do not remove the entry here because that can result in a deadlock
+ // if the code cannot properly send a signal to the thread under test.
+ entry->Wake();
+ } else {
+ // At this point, it is possible that entry has been freed, so just exit.
+ BACK_LOGE("Timed out waiting for unwind thread to indicate it completed.");
+ }
}
bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
@@ -128,17 +133,15 @@
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();
+ BACK_LOGE("sigaction failed: %s", strerror(errno));
ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
return false;
}
if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
- BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
+ BACK_LOGE("tgkill %d failed: %s", Tid(), strerror(errno));
sigaction(THREAD_SIGNAL, &oldact, nullptr);
- entry->Unlock();
ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
return false;
@@ -146,17 +149,30 @@
// Wait for the thread to get the ucontext. The number indicates
// that we are waiting for the first Wake() call made by the thread.
- entry->Wait(1);
+ bool wait_completed = entry->Wait(1);
// After the thread has received the signal, allow other unwinders to
// continue.
sigaction(THREAD_SIGNAL, &oldact, nullptr);
pthread_mutex_unlock(&g_sigaction_mutex);
- bool unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
+ bool unwind_done = false;
+ if (wait_completed) {
+ unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
- // Tell the signal handler to exit and release the entry.
- entry->Wake();
+ // Tell the signal handler to exit and release the entry.
+ entry->Wake();
+
+ // Wait for the thread to indicate it is done with the ThreadEntry.
+ if (!entry->Wait(3)) {
+ // Send a warning, but do not mark as a failure to unwind.
+ BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
+ }
+ } else {
+ BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
+ }
+
+ ThreadEntry::Remove(entry);
return unwind_done;
}
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
index 1632ec2..5c39f1c 100644
--- a/libbacktrace/BacktraceLog.h
+++ b/libbacktrace/BacktraceLog.h
@@ -25,4 +25,7 @@
#define BACK_LOGW(format, ...) \
ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+#define BACK_LOGE(format, ...) \
+ ALOGE("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
+
#endif // _LIBBACKTRACE_BACKTRACE_LOG_H
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
index e8b60c8..084c1aa 100644
--- a/libbacktrace/ThreadEntry.cpp
+++ b/libbacktrace/ThreadEntry.cpp
@@ -69,7 +69,7 @@
}
void ThreadEntry::Remove(ThreadEntry* entry) {
- pthread_mutex_unlock(&entry->mutex_);
+ entry->Unlock();
pthread_mutex_lock(&ThreadEntry::list_mutex_);
if (--entry->ref_count_ == 0) {
@@ -96,20 +96,24 @@
pthread_cond_destroy(&wait_cond_);
}
-void ThreadEntry::Wait(int value) {
+bool ThreadEntry::Wait(int value) {
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
- ts.tv_sec += 10;
+ ts.tv_sec += 5;
+ bool wait_completed = true;
pthread_mutex_lock(&wait_mutex_);
while (wait_value_ != value) {
int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
if (ret != 0) {
- BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret));
+ BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
+ wait_completed = false;
break;
}
}
pthread_mutex_unlock(&wait_mutex_);
+
+ return wait_completed;
}
void ThreadEntry::Wake() {
diff --git a/libbacktrace/ThreadEntry.h b/libbacktrace/ThreadEntry.h
index 94becf2..11924a3 100644
--- a/libbacktrace/ThreadEntry.h
+++ b/libbacktrace/ThreadEntry.h
@@ -29,7 +29,7 @@
void Wake();
- void Wait(int);
+ bool Wait(int);
void CopyUcontextFromSigcontext(void*);
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 4558719..3407ec3 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -68,7 +68,7 @@
}
if (send_request(sock_fd, &msg, sizeof(msg)) < 0) {
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
return -1;
}
@@ -95,7 +95,7 @@
break;
}
}
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
return result;
}
@@ -124,6 +124,6 @@
memcpy(pathbuf, buffer, n + 1);
}
}
- TEMP_FAILURE_RETRY(close(sock_fd));
+ close(sock_fd);
return result;
}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 24499ae..1da52d8 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -388,7 +388,6 @@
bool kick = false;
bool leading = true;
LogBufferElementLast last;
- log_time start(log_time::EPOCH);
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
@@ -417,8 +416,6 @@
continue;
}
- leading = false;
-
if (hasBlacklist && mPrune.naughty(e)) {
last.clear(e);
it = erase(it);
@@ -448,29 +445,24 @@
}
if (e->getUid() != worst) {
- if (start != log_time::EPOCH) {
+ if (leading) {
static const timespec too_old = {
EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
};
- start = e->getRealTime() + too_old;
+ LogBufferElementCollection::iterator last;
+ last = mLogElements.end();
+ --last;
+ if ((e->getRealTime() < ((*last)->getRealTime() - too_old))
+ || (e->getRealTime() > (*last)->getRealTime())) {
+ break;
+ }
}
+ leading = false;
last.clear(e);
++it;
continue;
}
- if ((start != log_time::EPOCH) && (e->getRealTime() > start)) {
- // KISS. Really a heuristic rather than algorithmically strong,
- // a crude mechanism, the following loops will move the oldest
- // watermark possibly wiping out the extra EXPIRE_HOUR_THRESHOLD
- // we just thought we were preserving. We count on the typical
- // pruneRows of 10% of total not being a sledgehammer.
- // A stronger algorithm would have us loop back to the top if
- // we have worst-UID enabled and we start expiring messages
- // below less than EXPIRE_HOUR_THRESHOLD old.
- break;
- }
-
pruneRows--;
if (pruneRows == 0) {
break;
@@ -479,15 +471,21 @@
kick = true;
unsigned short len = e->getMsgLen();
- stats.drop(e);
- e->setDropped(1);
- if (last.merge(e, 1)) {
- it = mLogElements.erase(it);
- stats.erase(e);
- delete e;
+
+ // do not create any leading drops
+ if (leading) {
+ it = erase(it);
} else {
- last.add(e);
- ++it;
+ stats.drop(e);
+ e->setDropped(1);
+ if (last.merge(e, 1)) {
+ it = mLogElements.erase(it);
+ stats.erase(e);
+ delete e;
+ } else {
+ last.add(e);
+ ++it;
+ }
}
if (worst_sizes < second_worst_sizes) {
break;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9fe1b4f..0966038 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -645,10 +645,7 @@
disabled
oneshot
-on property:ro.debuggable=1
- start perfprofd
-
service perfprofd /system/xbin/perfprofd
- disabled
+ class late_start
user root
oneshot