diff options
author | Davi Arnaut <davi.arnaut@oracle.com> | 2010-11-30 17:06:53 -0200 |
---|---|---|
committer | Davi Arnaut <davi.arnaut@oracle.com> | 2010-11-30 17:06:53 -0200 |
commit | 1ab37fd3c0c221b616d82bbd45dd1625219b51b3 (patch) | |
tree | 4abb7ef6876679d4b98b722cfbfc15c06e604e99 /mysys | |
parent | 8a214b8e1d225b0fb8d8f792ef31bf139191e33b (diff) | |
parent | 0008e06489cc3c346ee4ab62f89f20ac404f9472 (diff) | |
download | mariadb-git-1ab37fd3c0c221b616d82bbd45dd1625219b51b3.tar.gz |
Merge of mysql-5.1-bugteam into mysql-5.5-bugteam.
Diffstat (limited to 'mysys')
-rw-r--r-- | mysys/stacktrace.c | 103 |
1 files changed, 96 insertions, 7 deletions
diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 451a2c7d06a..ed3a15ae27e 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -24,6 +24,11 @@ #include <unistd.h> #include <strings.h> +#ifdef __linux__ +#include <ctype.h> /* isprint */ +#include <sys/syscall.h> /* SYS_gettid */ +#endif + #if HAVE_EXECINFO_H #include <execinfo.h> #endif @@ -43,10 +48,96 @@ void my_init_stacktrace() #endif } -void my_safe_print_str(const char* name, const char* val, int max_len) +#ifdef __linux__ + +static void print_buffer(char *buffer, size_t count) +{ + for (; count && *buffer; --count) + { + int c= (int) *buffer++; + fputc(isprint(c) ? c : ' ', stderr); + } +} + +/** + Access the pages of this process through /proc/self/task/<tid>/mem + in order to safely print the contents of a memory address range. + + @param addr The address at the start of the memory region. + @param max_len The length of the memory region. + + @return Zero on success. +*/ +static int safe_print_str(const char *addr, int max_len) +{ + int fd; + pid_t tid; + off_t offset; + ssize_t nbytes= 0; + size_t total, count; + char buf[256]; + + tid= (pid_t) syscall(SYS_gettid); + + sprintf(buf, "/proc/self/task/%d/mem", tid); + + if ((fd= open(buf, O_RDONLY)) < 0) + return -1; + + total= max_len; + offset= (off_t) addr; + + /* Read up to the maximum number of bytes. */ + while (total) + { + count= min(sizeof(buf), total); + + if ((nbytes= pread(fd, buf, count, offset)) < 0) + { + /* Just in case... */ + if (errno == EINTR) + continue; + else + break; + } + + /* Advance offset into memory. */ + total-= nbytes; + offset+= nbytes; + addr+= nbytes; + + /* Output the printable characters. */ + print_buffer(buf, nbytes); + + /* Break if less than requested... */ + if ((count - nbytes)) + break; + } + + /* Output a new line if something was printed. */ + if (total != (size_t) max_len) + fputc('\n', stderr); + + if (nbytes == -1) + fprintf(stderr, "Can't read from address %p: %m.\n", addr); + + close(fd); + + return 0; +} + +#endif + +void my_safe_print_str(const char* val, int max_len) { - char *heap_end= (char*) sbrk(0); - fprintf(stderr, "%s at %p ", name, val); + char *heap_end; + +#ifdef __linux__ + if (!safe_print_str(val, max_len)) + return; +#endif + + heap_end= (char*) sbrk(0); if (!PTR_SANE(val)) { @@ -54,7 +145,6 @@ void my_safe_print_str(const char* name, const char* val, int max_len) return; } - fprintf(stderr, "= "); for (; max_len && PTR_SANE(val) && *val; --max_len) fputc(*val++, stderr); fputc('\n', stderr); @@ -607,10 +697,9 @@ void my_write_core(int unused) } -void my_safe_print_str(const char *name, const char *val, int len) +void my_safe_print_str(const char *val, int len) { - fprintf(stderr,"%s at %p", name, val); - __try + __try { fprintf(stderr,"=%.*s\n", len, val); } |