Merge "Make abort messages available to debuggerd."
This commit is contained in:
commit
240fb8623b
@ -32,6 +32,5 @@
|
|||||||
#include "libc_logging.h"
|
#include "libc_logging.h"
|
||||||
|
|
||||||
void __stack_chk_fail() {
|
void __stack_chk_fail() {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", "stack corruption detected");
|
__libc_fatal("stack corruption detected");
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
@ -28,27 +28,16 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "libc_logging.h"
|
#include "libc_logging.h"
|
||||||
|
|
||||||
// We log to stderr for the benefit of "adb shell" users, and the log for the benefit
|
|
||||||
// of regular app developers who want to see their asserts.
|
|
||||||
|
|
||||||
void __assert(const char* file, int line, const char* failed_expression) {
|
void __assert(const char* file, int line, const char* failed_expression) {
|
||||||
const char* fmt = "%s:%d: assertion \"%s\" failed\n";
|
__libc_fatal("%s:%d: assertion \"%s\" failed", file, line, failed_expression);
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression);
|
|
||||||
fprintf(stderr, fmt, file, line, failed_expression);
|
|
||||||
abort();
|
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
|
||||||
void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
|
void __assert2(const char* file, int line, const char* function, const char* failed_expression) {
|
||||||
const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n";
|
__libc_fatal("%s:%d: %s: assertion \"%s\" failed", file, line, function, failed_expression);
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression);
|
|
||||||
fprintf(stderr, fmt, file, line, function, failed_expression);
|
|
||||||
abort();
|
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
|
@ -16,15 +16,7 @@
|
|||||||
|
|
||||||
#include "dlmalloc.h"
|
#include "dlmalloc.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include "private/libc_logging.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <linux/ashmem.h>
|
|
||||||
|
|
||||||
#include <private/libc_logging.h>
|
|
||||||
|
|
||||||
// Send dlmalloc errors to the log.
|
// Send dlmalloc errors to the log.
|
||||||
static void __bionic_heap_corruption_error(const char* function);
|
static void __bionic_heap_corruption_error(const char* function);
|
||||||
@ -37,15 +29,12 @@ static void __bionic_heap_usage_error(const char* function, void* address);
|
|||||||
#include "../upstream-dlmalloc/malloc.c"
|
#include "../upstream-dlmalloc/malloc.c"
|
||||||
|
|
||||||
static void __bionic_heap_corruption_error(const char* function) {
|
static void __bionic_heap_corruption_error(const char* function) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", "@@@ ABORTING: heap corruption detected by %s",
|
__libc_fatal("@@@ ABORTING: heap corruption detected by %s", function);
|
||||||
function);
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __bionic_heap_usage_error(const char* function, void* address) {
|
static void __bionic_heap_usage_error(const char* function, void* address) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc",
|
__libc_fatal("@@@ ABORTING: invalid address or address of corrupt block %p passed to %s",
|
||||||
"@@@ ABORTING: invalid address or address of corrupt block %p passed to %s",
|
address, function);
|
||||||
address, function);
|
|
||||||
// So that we can get a memory dump around the specific address.
|
// So that we can get a memory dump around the specific address.
|
||||||
*((int**) 0xdeadbaad) = (int*) address;
|
*((int**) 0xdeadbaad) = (int*) address;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
#include "private/KernelArgumentBlock.h"
|
#include "private/KernelArgumentBlock.h"
|
||||||
#include "pthread_internal.h"
|
#include "pthread_internal.h"
|
||||||
|
|
||||||
|
extern "C" abort_msg_t** __abort_message_ptr;
|
||||||
extern "C" unsigned __get_sp(void);
|
extern "C" unsigned __get_sp(void);
|
||||||
extern "C" int __system_properties_init(void);
|
extern "C" int __system_properties_init(void);
|
||||||
|
|
||||||
@ -96,6 +97,7 @@ void __libc_init_common(KernelArgumentBlock& args) {
|
|||||||
errno = 0;
|
errno = 0;
|
||||||
__libc_auxv = args.auxv;
|
__libc_auxv = args.auxv;
|
||||||
__progname = args.argv[0] ? args.argv[0] : "<unknown>";
|
__progname = args.argv[0] ? args.argv[0] : "<unknown>";
|
||||||
|
__abort_message_ptr = args.abort_message_ptr;
|
||||||
|
|
||||||
// AT_RANDOM is a pointer to 16 bytes of randomness on the stack.
|
// AT_RANDOM is a pointer to 16 bytes of randomness on the stack.
|
||||||
__stack_chk_guard = *reinterpret_cast<uintptr_t*>(getauxval(AT_RANDOM));
|
__stack_chk_guard = *reinterpret_cast<uintptr_t*>(getauxval(AT_RANDOM));
|
||||||
|
@ -31,228 +31,96 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
/*** Generic output sink
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct Out {
|
|
||||||
void *opaque;
|
|
||||||
void (*send)(void *opaque, const char *data, int len);
|
|
||||||
};
|
|
||||||
|
|
||||||
static void out_send(Out *o, const char *data, size_t len) {
|
|
||||||
o->send(o->opaque, data, (int)len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
out_send_repeat(Out *o, char ch, int count)
|
|
||||||
{
|
|
||||||
char pad[8];
|
|
||||||
const int padSize = (int)sizeof(pad);
|
|
||||||
|
|
||||||
memset(pad, ch, sizeof(pad));
|
|
||||||
while (count > 0) {
|
|
||||||
int avail = count;
|
|
||||||
if (avail > padSize) {
|
|
||||||
avail = padSize;
|
|
||||||
}
|
|
||||||
o->send(o->opaque, pad, avail);
|
|
||||||
count -= avail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* forward declaration */
|
|
||||||
static void out_vformat(Out* o, const char* format, va_list args);
|
|
||||||
|
|
||||||
/*** Bounded buffer output
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct BufOut {
|
|
||||||
Out out[1];
|
|
||||||
char *buffer;
|
|
||||||
char *pos;
|
|
||||||
char *end;
|
|
||||||
int total;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void buf_out_send(void *opaque, const char *data, int len) {
|
|
||||||
BufOut *bo = reinterpret_cast<BufOut*>(opaque);
|
|
||||||
|
|
||||||
if (len < 0) {
|
|
||||||
len = strlen(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bo->total += len;
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
int avail = bo->end - bo->pos;
|
|
||||||
if (avail == 0)
|
|
||||||
break;
|
|
||||||
if (avail > len)
|
|
||||||
avail = len;
|
|
||||||
memcpy(bo->pos, data, avail);
|
|
||||||
bo->pos += avail;
|
|
||||||
bo->pos[0] = '\0';
|
|
||||||
len -= avail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Out*
|
|
||||||
buf_out_init(BufOut *bo, char *buffer, size_t size)
|
|
||||||
{
|
|
||||||
if (size == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
bo->out->opaque = bo;
|
|
||||||
bo->out->send = buf_out_send;
|
|
||||||
bo->buffer = buffer;
|
|
||||||
bo->end = buffer + size - 1;
|
|
||||||
bo->pos = bo->buffer;
|
|
||||||
bo->pos[0] = '\0';
|
|
||||||
bo->total = 0;
|
|
||||||
|
|
||||||
return bo->out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
buf_out_length(BufOut *bo)
|
|
||||||
{
|
|
||||||
return bo->total;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
vformat_buffer(char *buff, size_t buf_size, const char *format, va_list args)
|
|
||||||
{
|
|
||||||
BufOut bo;
|
|
||||||
Out *out;
|
|
||||||
|
|
||||||
out = buf_out_init(&bo, buff, buf_size);
|
|
||||||
if (out == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out_vformat(out, format, args);
|
|
||||||
|
|
||||||
return buf_out_length(&bo);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
int result = vformat_buffer(buffer, buffer_size, format, args);
|
|
||||||
va_end(args);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*** File descriptor output
|
|
||||||
***/
|
|
||||||
|
|
||||||
struct FdOut {
|
|
||||||
Out out[1];
|
|
||||||
int fd;
|
|
||||||
int total;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
fd_out_send(void *opaque, const char *data, int len)
|
|
||||||
{
|
|
||||||
FdOut *fdo = reinterpret_cast<FdOut*>(opaque);
|
|
||||||
|
|
||||||
if (len < 0)
|
|
||||||
len = strlen(data);
|
|
||||||
|
|
||||||
while (len > 0) {
|
|
||||||
int ret = write(fdo->fd, data, len);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data += ret;
|
|
||||||
len -= ret;
|
|
||||||
fdo->total += ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Out*
|
|
||||||
fd_out_init(FdOut *fdo, int fd)
|
|
||||||
{
|
|
||||||
fdo->out->opaque = fdo;
|
|
||||||
fdo->out->send = fd_out_send;
|
|
||||||
fdo->fd = fd;
|
|
||||||
fdo->total = 0;
|
|
||||||
|
|
||||||
return fdo->out;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
fd_out_length(FdOut *fdo)
|
|
||||||
{
|
|
||||||
return fdo->total;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int __libc_format_fd(int fd, const char* format, ...) {
|
|
||||||
FdOut fdo;
|
|
||||||
Out* out = fd_out_init(&fdo, fd);
|
|
||||||
if (out == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
out_vformat(out, format, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return fd_out_length(&fdo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** Log output
|
|
||||||
***/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static pthread_mutex_t gAbortMsgLock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static pthread_mutex_t gLogInitializationLock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t gLogInitializationLock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) {
|
__LIBC_HIDDEN__ abort_msg_t** __abort_message_ptr; // Accessible to __libc_init_common.
|
||||||
char buf[1024];
|
|
||||||
int buf_strlen = vformat_buffer(buf, sizeof(buf), fmt, args);
|
|
||||||
|
|
||||||
static int main_log_fd = -1;
|
// Must be kept in sync with frameworks/base/core/java/android/util/EventLog.java.
|
||||||
if (main_log_fd == -1) {
|
enum AndroidEventLogType {
|
||||||
ScopedPthreadMutexLocker locker(&gLogInitializationLock);
|
EVENT_TYPE_INT = 0,
|
||||||
main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
|
EVENT_TYPE_LONG = 1,
|
||||||
if (main_log_fd == -1) {
|
EVENT_TYPE_STRING = 2,
|
||||||
return -1;
|
EVENT_TYPE_LIST = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BufferOutputStream {
|
||||||
|
public:
|
||||||
|
BufferOutputStream(char* buffer, size_t size) : total(0) {
|
||||||
|
buffer_ = buffer;
|
||||||
|
end_ = buffer + size - 1;
|
||||||
|
pos_ = buffer_;
|
||||||
|
pos_[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
~BufferOutputStream() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(const char* data, int len) {
|
||||||
|
if (len < 0) {
|
||||||
|
len = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
int avail = end_ - pos_;
|
||||||
|
if (avail == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (avail > len) {
|
||||||
|
avail = len;
|
||||||
|
}
|
||||||
|
memcpy(pos_, data, avail);
|
||||||
|
pos_ += avail;
|
||||||
|
pos_[0] = '\0';
|
||||||
|
len -= avail;
|
||||||
|
total += avail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iovec vec[3];
|
int total;
|
||||||
vec[0].iov_base = &priority;
|
|
||||||
vec[0].iov_len = 1;
|
|
||||||
vec[1].iov_base = const_cast<char*>(tag);
|
|
||||||
vec[1].iov_len = strlen(tag) + 1;
|
|
||||||
vec[2].iov_base = const_cast<char*>(buf);
|
|
||||||
vec[2].iov_len = buf_strlen + 1;
|
|
||||||
|
|
||||||
return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
|
private:
|
||||||
}
|
char* buffer_;
|
||||||
|
char* pos_;
|
||||||
|
char* end_;
|
||||||
|
};
|
||||||
|
|
||||||
int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
struct FdOutputStream {
|
||||||
va_list args;
|
public:
|
||||||
va_start(args, format);
|
FdOutputStream(int fd) : total(0), fd_(fd) {
|
||||||
int result = __libc_format_log_va_list(priority, tag, format, args);
|
}
|
||||||
va_end(args);
|
|
||||||
return result;
|
void Send(const char* data, int len) {
|
||||||
}
|
if (len < 0) {
|
||||||
|
len = strlen(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
int rc = TEMP_FAILURE_RETRY(write(fd_, data, len));
|
||||||
|
if (rc == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data += rc;
|
||||||
|
len -= rc;
|
||||||
|
total += rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int total;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fd_;
|
||||||
|
};
|
||||||
|
|
||||||
/*** formatted output implementation
|
/*** formatted output implementation
|
||||||
***/
|
***/
|
||||||
@ -263,9 +131,7 @@ int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
|||||||
*
|
*
|
||||||
* NOTE: Does *not* handle a sign prefix.
|
* NOTE: Does *not* handle a sign prefix.
|
||||||
*/
|
*/
|
||||||
static unsigned
|
static unsigned parse_decimal(const char *format, int *ppos) {
|
||||||
parse_decimal(const char *format, int *ppos)
|
|
||||||
{
|
|
||||||
const char* p = format + *ppos;
|
const char* p = format + *ppos;
|
||||||
unsigned result = 0;
|
unsigned result = 0;
|
||||||
|
|
||||||
@ -273,8 +139,9 @@ parse_decimal(const char *format, int *ppos)
|
|||||||
int ch = *p;
|
int ch = *p;
|
||||||
unsigned d = (unsigned)(ch - '0');
|
unsigned d = (unsigned)(ch - '0');
|
||||||
|
|
||||||
if (d >= 10U)
|
if (d >= 10U) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
result = result*10 + d;
|
result = result*10 + d;
|
||||||
p++;
|
p++;
|
||||||
@ -341,10 +208,25 @@ static void format_integer(char* buf, size_t buf_size, uint64_t value, char conv
|
|||||||
format_unsigned(buf, buf_size, value, base, caps);
|
format_unsigned(buf, buf_size, value, base, caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Out>
|
||||||
|
static void SendRepeat(Out& o, char ch, int count) {
|
||||||
|
char pad[8];
|
||||||
|
memset(pad, ch, sizeof(pad));
|
||||||
|
|
||||||
|
const int pad_size = static_cast<int>(sizeof(pad));
|
||||||
|
while (count > 0) {
|
||||||
|
int avail = count;
|
||||||
|
if (avail > pad_size) {
|
||||||
|
avail = pad_size;
|
||||||
|
}
|
||||||
|
o.Send(pad, avail);
|
||||||
|
count -= avail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform formatted output to an output target 'o' */
|
/* Perform formatted output to an output target 'o' */
|
||||||
static void
|
template <typename Out>
|
||||||
out_vformat(Out *o, const char *format, va_list args)
|
static void out_vformat(Out& o, const char* format, va_list args) {
|
||||||
{
|
|
||||||
int nn = 0;
|
int nn = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -371,7 +253,7 @@ out_vformat(Out *o, const char *format, va_list args)
|
|||||||
} while (1);
|
} while (1);
|
||||||
|
|
||||||
if (mm > nn) {
|
if (mm > nn) {
|
||||||
out_send(o, format+nn, mm-nn);
|
o.Send(format+nn, mm-nn);
|
||||||
nn = mm;
|
nn = mm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +269,7 @@ out_vformat(Out *o, const char *format, va_list args)
|
|||||||
c = format[nn++];
|
c = format[nn++];
|
||||||
if (c == '\0') { /* single trailing '%' ? */
|
if (c == '\0') { /* single trailing '%' ? */
|
||||||
c = '%';
|
c = '%';
|
||||||
out_send(o, &c, 1);
|
o.Send(&c, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (c == '0') {
|
else if (c == '0') {
|
||||||
@ -508,28 +390,74 @@ out_vformat(Out *o, const char *format, va_list args)
|
|||||||
|
|
||||||
if (slen < width && !padLeft) {
|
if (slen < width && !padLeft) {
|
||||||
char padChar = padZero ? '0' : ' ';
|
char padChar = padZero ? '0' : ' ';
|
||||||
out_send_repeat(o, padChar, width - slen);
|
SendRepeat(o, padChar, width - slen);
|
||||||
}
|
}
|
||||||
|
|
||||||
out_send(o, str, slen);
|
o.Send(str, slen);
|
||||||
|
|
||||||
if (slen < width && padLeft) {
|
if (slen < width && padLeft) {
|
||||||
char padChar = padZero ? '0' : ' ';
|
char padChar = padZero ? '0' : ' ';
|
||||||
out_send_repeat(o, padChar, width - slen);
|
SendRepeat(o, padChar, width - slen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// must be kept in sync with frameworks/base/core/java/android/util/EventLog.java
|
int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) {
|
||||||
enum AndroidEventLogType {
|
BufferOutputStream os(buffer, buffer_size);
|
||||||
EVENT_TYPE_INT = 0,
|
va_list args;
|
||||||
EVENT_TYPE_LONG = 1,
|
va_start(args, format);
|
||||||
EVENT_TYPE_STRING = 2,
|
out_vformat(os, format, args);
|
||||||
EVENT_TYPE_LIST = 3,
|
va_end(args);
|
||||||
};
|
return os.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_fd(int fd, const char* format, ...) {
|
||||||
|
FdOutputStream os(fd);
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return os.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __libc_write_log(int priority, const char* tag, const char* msg) {
|
||||||
|
static int main_log_fd = -1;
|
||||||
|
if (main_log_fd == -1) {
|
||||||
|
ScopedPthreadMutexLocker locker(&gLogInitializationLock);
|
||||||
|
main_log_fd = TEMP_FAILURE_RETRY(open("/dev/log/main", O_CLOEXEC | O_WRONLY));
|
||||||
|
if (main_log_fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iovec vec[3];
|
||||||
|
vec[0].iov_base = &priority;
|
||||||
|
vec[0].iov_len = 1;
|
||||||
|
vec[1].iov_base = const_cast<char*>(tag);
|
||||||
|
vec[1].iov_len = strlen(tag) + 1;
|
||||||
|
vec[2].iov_base = const_cast<char*>(msg);
|
||||||
|
vec[2].iov_len = strlen(msg) + 1;
|
||||||
|
|
||||||
|
return TEMP_FAILURE_RETRY(writev(main_log_fd, vec, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_log_va_list(int priority, const char* tag, const char* format, va_list args) {
|
||||||
|
char buffer[1024];
|
||||||
|
BufferOutputStream os(buffer, sizeof(buffer));
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
return __libc_write_log(priority, tag, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __libc_format_log(int priority, const char* tag, const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int result = __libc_format_log_va_list(priority, tag, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
|
static int __libc_android_log_event(int32_t tag, char type, const void* payload, size_t len) {
|
||||||
struct iovec vec[3];
|
iovec vec[3];
|
||||||
vec[0].iov_base = &tag;
|
vec[0].iov_base = &tag;
|
||||||
vec[0].iov_len = sizeof(tag);
|
vec[0].iov_len = sizeof(tag);
|
||||||
vec[1].iov_base = &type;
|
vec[1].iov_base = &type;
|
||||||
@ -554,9 +482,45 @@ void __libc_android_log_event_uid(int32_t tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void __fortify_chk_fail(const char *msg, uint32_t tag) {
|
void __fortify_chk_fail(const char *msg, uint32_t tag) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg);
|
|
||||||
if (tag != 0) {
|
if (tag != 0) {
|
||||||
__libc_android_log_event_uid(tag);
|
__libc_android_log_event_uid(tag);
|
||||||
}
|
}
|
||||||
|
__libc_fatal("FORTIFY_SOURCE: %s. Calling abort().", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __libc_fatal(const char* format, ...) {
|
||||||
|
char msg[1024];
|
||||||
|
BufferOutputStream os(msg, sizeof(msg));
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
out_vformat(os, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// TODO: log to stderr for the benefit of "adb shell" users.
|
||||||
|
|
||||||
|
// Log to the log for the benefit of regular app developers (whose stdout and stderr are closed).
|
||||||
|
__libc_write_log(ANDROID_LOG_FATAL, "libc", msg);
|
||||||
|
|
||||||
|
__libc_set_abort_message(msg);
|
||||||
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __libc_set_abort_message(const char* msg) {
|
||||||
|
size_t size = sizeof(abort_msg_t) + strlen(msg) + 1;
|
||||||
|
void* map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
|
if (map == MAP_FAILED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__abort_message_ptr != NULL) {
|
||||||
|
ScopedPthreadMutexLocker locker(&gAbortMsgLock);
|
||||||
|
if (*__abort_message_ptr != NULL) {
|
||||||
|
munmap(*__abort_message_ptr, (*__abort_message_ptr)->size);
|
||||||
|
}
|
||||||
|
abort_msg_t* new_abort_message = reinterpret_cast<abort_msg_t*>(map);
|
||||||
|
new_abort_message->size = size;
|
||||||
|
strcpy(new_abort_message->msg, msg);
|
||||||
|
*__abort_message_ptr = new_abort_message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -600,7 +600,7 @@ int malloc_debug_initialize() {
|
|||||||
error_log("Unable to open /dev/qemu_trace");
|
error_log("Unable to open /dev/qemu_trace");
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
qtrace = mmap(0, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
if (qtrace == MAP_FAILED) {
|
if (qtrace == MAP_FAILED) {
|
||||||
|
@ -106,7 +106,7 @@ int __system_properties_init(void)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_area *pa = mmap(0, fd_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
prop_area *pa = mmap(NULL, fd_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
|
|
||||||
if (pa == MAP_FAILED) {
|
if (pa == MAP_FAILED) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -150,7 +150,7 @@ const prop_info *__system_property_find(const char *name)
|
|||||||
while(count--) {
|
while(count--) {
|
||||||
unsigned entry = *toc++;
|
unsigned entry = *toc++;
|
||||||
if(TOC_NAME_LEN(entry) != len) continue;
|
if(TOC_NAME_LEN(entry) != len) continue;
|
||||||
|
|
||||||
pi = TOC_TO_INFO(pa, entry);
|
pi = TOC_TO_INFO(pa, entry);
|
||||||
if(memcmp(name, pi->name, len)) continue;
|
if(memcmp(name, pi->name, len)) continue;
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ const prop_info *__system_property_find(const char *name)
|
|||||||
int __system_property_read(const prop_info *pi, char *name, char *value)
|
int __system_property_read(const prop_info *pi, char *name, char *value)
|
||||||
{
|
{
|
||||||
unsigned serial, len;
|
unsigned serial, len;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
serial = pi->serial;
|
serial = pi->serial;
|
||||||
while(SERIAL_DIRTY(serial)) {
|
while(SERIAL_DIRTY(serial)) {
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
|
struct abort_msg_t;
|
||||||
|
|
||||||
// When the kernel starts the dynamic linker, it passes a pointer to a block
|
// When the kernel starts the dynamic linker, it passes a pointer to a block
|
||||||
// of memory containing argc, the argv array, the environment variable array,
|
// of memory containing argc, the argv array, the environment variable array,
|
||||||
// and the array of ELF aux vectors. This class breaks that block up into its
|
// and the array of ELF aux vectors. This class breaks that block up into its
|
||||||
@ -67,6 +69,8 @@ class KernelArgumentBlock {
|
|||||||
char** envp;
|
char** envp;
|
||||||
Elf32_auxv_t* auxv;
|
Elf32_auxv_t* auxv;
|
||||||
|
|
||||||
|
abort_msg_t** abort_message_ptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Disallow copy and assignment.
|
// Disallow copy and assignment.
|
||||||
KernelArgumentBlock(const KernelArgumentBlock&);
|
KernelArgumentBlock(const KernelArgumentBlock&);
|
||||||
|
@ -67,6 +67,20 @@ enum {
|
|||||||
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
|
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct abort_msg_t {
|
||||||
|
size_t size;
|
||||||
|
char msg[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ void __libc_set_abort_message(const char* msg);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Formats a message to the log (priority 'fatal'), then aborts.
|
||||||
|
//
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ __noreturn void __libc_fatal(const char* format, ...)
|
||||||
|
__attribute__((__format__(printf, 1, 2)));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Formatting routines for the C library's internal debugging.
|
// Formatting routines for the C library's internal debugging.
|
||||||
// Unlike the usual alternatives, these don't allocate.
|
// Unlike the usual alternatives, these don't allocate.
|
||||||
|
@ -52,8 +52,12 @@ enum debugger_action_t {
|
|||||||
|
|
||||||
/* message sent over the socket */
|
/* message sent over the socket */
|
||||||
struct debugger_msg_t {
|
struct debugger_msg_t {
|
||||||
debugger_action_t action;
|
// version 1 included:
|
||||||
pid_t tid;
|
debugger_action_t action;
|
||||||
|
pid_t tid;
|
||||||
|
|
||||||
|
// version 2 added:
|
||||||
|
uintptr_t abort_msg_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
// see man(2) prctl, specifically the section about PR_GET_NAME
|
// see man(2) prctl, specifically the section about PR_GET_NAME
|
||||||
@ -154,14 +158,14 @@ static bool haveSiginfo(int signum) {
|
|||||||
sigemptyset(&newact.sa_mask);
|
sigemptyset(&newact.sa_mask);
|
||||||
|
|
||||||
if (sigaction(signum, &newact, &oldact) < 0) {
|
if (sigaction(signum, &newact, &oldact) < 0) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed testing for SA_SIGINFO: %s",
|
__libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
bool ret = (oldact.sa_flags & SA_SIGINFO) != 0;
|
bool ret = (oldact.sa_flags & SA_SIGINFO) != 0;
|
||||||
|
|
||||||
if (sigaction(signum, &oldact, NULL) == -1) {
|
if (sigaction(signum, &oldact, NULL) == -1) {
|
||||||
__libc_format_log(ANDROID_LOG_FATAL, "libc", "Restore failed in test for SA_SIGINFO: %s",
|
__libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -186,19 +190,17 @@ void debuggerd_signal_handler(int n, siginfo_t* info, void*) {
|
|||||||
int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
|
int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
|
||||||
|
|
||||||
if (s >= 0) {
|
if (s >= 0) {
|
||||||
/* debugger knows our pid from the credentials on the
|
// debuggerd knows our pid from the credentials on the
|
||||||
* local socket but we need to tell it our tid. It
|
// local socket but we need to tell it the tid of the crashing thread.
|
||||||
* is paranoid and will verify that we are giving a tid
|
// debuggerd will be paranoid and verify that we sent a tid
|
||||||
* that's actually in our process
|
// that's actually in our process.
|
||||||
*/
|
|
||||||
int ret;
|
|
||||||
debugger_msg_t msg;
|
debugger_msg_t msg;
|
||||||
msg.action = DEBUGGER_ACTION_CRASH;
|
msg.action = DEBUGGER_ACTION_CRASH;
|
||||||
msg.tid = tid;
|
msg.tid = tid;
|
||||||
ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
|
msg.abort_msg_address = reinterpret_cast<uintptr_t>(gAbortMessage);
|
||||||
|
int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
|
||||||
if (ret == sizeof(msg)) {
|
if (ret == sizeof(msg)) {
|
||||||
/* if the write failed, there is no point to read on
|
// if the write failed, there is no point trying to read a response.
|
||||||
* the file descriptor. */
|
|
||||||
ret = TEMP_FAILURE_RETRY(read(s, &tid, 1));
|
ret = TEMP_FAILURE_RETRY(read(s, &tid, 1));
|
||||||
int saved_errno = errno;
|
int saved_errno = errno;
|
||||||
notify_gdb_of_libraries();
|
notify_gdb_of_libraries();
|
||||||
|
@ -105,6 +105,8 @@ static soinfo* gLdPreloads[LDPRELOAD_MAX + 1];
|
|||||||
|
|
||||||
__LIBC_HIDDEN__ int gLdDebugVerbosity;
|
__LIBC_HIDDEN__ int gLdDebugVerbosity;
|
||||||
|
|
||||||
|
__LIBC_HIDDEN__ abort_msg_t* gAbortMessage = NULL; // For debuggerd.
|
||||||
|
|
||||||
enum RelocationKind {
|
enum RelocationKind {
|
||||||
kRelocAbsolute = 0,
|
kRelocAbsolute = 0,
|
||||||
kRelocRelative,
|
kRelocRelative,
|
||||||
@ -171,8 +173,7 @@ size_t linker_get_error_buffer_size() {
|
|||||||
*/
|
*/
|
||||||
extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
|
extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
|
||||||
|
|
||||||
static r_debug _r_debug = {1, NULL, &rtld_db_dlactivity,
|
static r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, RT_CONSISTENT, 0};
|
||||||
RT_CONSISTENT, 0};
|
|
||||||
static link_map_t* r_debug_tail = 0;
|
static link_map_t* r_debug_tail = 0;
|
||||||
|
|
||||||
static pthread_mutex_t gDebugMutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t gDebugMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
@ -1815,8 +1816,8 @@ extern "C" Elf32_Addr __linker_init(void* raw_args) {
|
|||||||
|
|
||||||
Elf32_Addr linker_addr = args.getauxval(AT_BASE);
|
Elf32_Addr linker_addr = args.getauxval(AT_BASE);
|
||||||
|
|
||||||
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr*) linker_addr;
|
Elf32_Ehdr* elf_hdr = (Elf32_Ehdr*) linker_addr;
|
||||||
Elf32_Phdr *phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
|
Elf32_Phdr* phdr = (Elf32_Phdr*)((unsigned char*) linker_addr + elf_hdr->e_phoff);
|
||||||
|
|
||||||
soinfo linker_so;
|
soinfo linker_so;
|
||||||
memset(&linker_so, 0, sizeof(soinfo));
|
memset(&linker_so, 0, sizeof(soinfo));
|
||||||
@ -1841,6 +1842,7 @@ extern "C" Elf32_Addr __linker_init(void* raw_args) {
|
|||||||
|
|
||||||
// We have successfully fixed our own relocations. It's safe to run
|
// We have successfully fixed our own relocations. It's safe to run
|
||||||
// the main part of the linker now.
|
// the main part of the linker now.
|
||||||
|
args.abort_message_ptr = &gAbortMessage;
|
||||||
Elf32_Addr start_address = __linker_init_post_relocation(args, linker_addr);
|
Elf32_Addr start_address = __linker_init_post_relocation(args, linker_addr);
|
||||||
|
|
||||||
set_soinfo_pool_protection(PROT_READ);
|
set_soinfo_pool_protection(PROT_READ);
|
||||||
|
@ -186,6 +186,7 @@ Elf32_Sym* dladdr_find_symbol(soinfo* si, const void* addr);
|
|||||||
Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
|
Elf32_Sym* dlsym_handle_lookup(soinfo* si, const char* name);
|
||||||
|
|
||||||
void debuggerd_init();
|
void debuggerd_init();
|
||||||
|
extern "C" abort_msg_t* gAbortMessage;
|
||||||
extern "C" void notify_gdb_of_libraries();
|
extern "C" void notify_gdb_of_libraries();
|
||||||
|
|
||||||
char* linker_get_error_buffer();
|
char* linker_get_error_buffer();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user