summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.cc11
-rw-r--r--include/my_stacktrace.h2
-rw-r--r--mysys/stacktrace.c103
-rw-r--r--sql/mysqld.cc14
4 files changed, 112 insertions, 18 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index fc111bf7645..9613bc2e929 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -8074,13 +8074,16 @@ static void dump_backtrace(void)
{
struct st_connection *conn= cur_con;
- my_safe_print_str("read_command_buf", read_command_buf,
- sizeof(read_command_buf));
+ fprintf(stderr, "read_command_buf (%p): ", read_command_buf);
+ my_safe_print_str(read_command_buf, sizeof(read_command_buf));
+
if (conn)
{
- my_safe_print_str("conn->name", conn->name, conn->name_len);
+ fprintf(stderr, "conn->name (%p): ", conn->name);
+ my_safe_print_str(conn->name, conn->name_len);
#ifdef EMBEDDED_LIBRARY
- my_safe_print_str("conn->cur_query", conn->cur_query, conn->cur_query_len);
+ fprintf(stderr, "conn->cur_query (%p): ", conn->cur_query);
+ my_safe_print_str(conn->cur_query, conn->cur_query_len);
#endif
}
fputs("Attempting backtrace...\n", stderr);
diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h
index 78e3dbca577..8c2c97c68e5 100644
--- a/include/my_stacktrace.h
+++ b/include/my_stacktrace.h
@@ -45,7 +45,7 @@ C_MODE_START
#if defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE)
void my_init_stacktrace();
void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack);
-void my_safe_print_str(const char* name, const char* val, int max_len);
+void my_safe_print_str(const char* val, int max_len);
void my_write_core(int sig);
#if BACKTRACE_DEMANGLE
char *my_demangle(const char *mangled_name, int *status);
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);
}
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 7fec30520d0..cf8fd7f7d2e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -2427,7 +2427,7 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
if (!(test_flags & TEST_NO_STACKTRACE))
{
- fprintf(stderr, "thd: 0x%lx\n",(long) thd);
+ fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd);
fprintf(stderr, "Attempting backtrace. You can use the following "
"information to find out\nwhere mysqld died. If "
"you see no messages after this, something went\n"
@@ -2455,11 +2455,13 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
kreason= "KILLED_NO_VALUE";
break;
}
- fprintf(stderr, "Trying to get some variables.\n\
-Some pointers may be invalid and cause the dump to abort...\n");
- my_safe_print_str("thd->query", thd->query(), 1024);
- fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id);
- fprintf(stderr, "thd->killed=%s\n", kreason);
+ fprintf(stderr, "\nTrying to get some variables.\n"
+ "Some pointers may be invalid and cause the dump to abort.\n");
+ fprintf(stderr, "Query (%p): ", thd->query());
+ my_safe_print_str(thd->query(), min(1024, thd->query_length()));
+ fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id);
+ fprintf(stderr, "Status: %s\n", kreason);
+ fputc('\n', stderr);
}
fprintf(stderr, "\
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\