[sheepdog] [PATCH 3/4] logger: dump stack frames when showing backtrace

MORITA Kazutaka morita.kazutaka at lab.ntt.co.jp
Wed Feb 27 18:15:37 CET 2013


This dumps all function arguments and local variables for each stack
frame using GDB.

Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
 lib/logger.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/lib/logger.c b/lib/logger.c
index a29eaaa..e49afaa 100644
--- a/lib/logger.c
+++ b/lib/logger.c
@@ -629,6 +629,90 @@ notrace void get_thread_name(char *name)
 
 #define SD_MAX_STACK_DEPTH 1024
 
+static int get_my_path(char *path, size_t size)
+{
+	/* readlink doesn't append '\0', so initialize here */
+	memset(path, 0, size);
+
+	return readlink("/proc/self/exe", path, size);
+}
+
+static bool check_gdb(void)
+{
+	return system("which gdb > /dev/null") == 0;
+}
+
+#define dump_stack_frames() ({			\
+	register void *current_sp asm("rsp");	\
+	__dump_stack_frames(current_sp);	\
+})
+
+__attribute__ ((__noinline__))
+static notrace int __dump_stack_frames(const void *base_sp)
+{
+	char path[PATH_MAX];
+	int i, stack_no = 0;
+
+	if (!check_gdb()) {
+		sd_eprintf("cannot find gdb");
+		return -1;
+	}
+
+	if (get_my_path(path, sizeof(path)) < 0)
+		return -1;
+
+	for (i = 1; i < SD_MAX_STACK_DEPTH; i++) {
+		char cmd[ARG_MAX], info[256];
+		FILE *f = NULL;
+		bool found = false;
+
+		snprintf(cmd, sizeof(cmd), "gdb -nw %s %d -batch"
+			 " -ex 'set width 80' -ex 'select-frame %p'"
+			 " -ex 'up %d' -ex 'info locals' 2> /dev/null",
+			 path, getpid(), base_sp, i);
+		f = popen(cmd, "r");
+		if (f == NULL)
+			return -1;
+		/*
+		 * The expected outputs of gdb are:
+		 *
+		 *  [some info we don't need]
+		 *  #<stack no> <addr> in <func>(<arg>) at <file>:<line>
+		 *  <line>   <source>
+		 *  <local variables>
+		 */
+		while (fgets(info, sizeof(info), f) != NULL) {
+			int no;
+			if (sscanf(info, "#%d ", &no) == 1) {
+				if (no <= stack_no) {
+					/* reached to the end of the stacks */
+					pclose(f);
+					return 0;
+				}
+				stack_no = no;
+				found = true;
+				sd_printf(SDOG_EMERG, "%s", info);
+				break;
+			}
+		}
+
+		if (!found) {
+			sd_eprintf("Cannot get info from GDB");
+			sd_eprintf("Set /proc/sys/kernel/yama/ptrace_scope to"
+				   " zero if you are using Ubuntu.");
+			pclose(f);
+			return -1;
+		}
+
+		while (fgets(info, sizeof(info), f) != NULL)
+			sd_printf(SDOG_EMERG, "%s", info);
+
+		pclose(f);
+	}
+
+	return 0;
+}
+
 __attribute__ ((__noinline__))
 notrace void sd_backtrace(void)
 {
@@ -637,7 +721,7 @@ notrace void sd_backtrace(void)
 
 	for (i = 1; i < n; i++) { /* addrs[0] is here, so skip it */
 		void *addr = addrs[i];
-		char cmd[ARG_MAX], path[PATH_MAX] = {0}, info[256], **str;
+		char cmd[ARG_MAX], path[PATH_MAX], info[256], **str;
 		FILE *f;
 
 		/* the called function is at the previous address
@@ -645,7 +729,7 @@ notrace void sd_backtrace(void)
 		addr = (void *)((char *)addr - 1);
 
 		/* try to get a line number with addr2line if possible */
-		if (readlink("/proc/self/exe", path, sizeof(path)) < 0)
+		if (get_my_path(path, sizeof(path)) < 0)
 			goto fallback;
 
 		snprintf(cmd, sizeof(cmd), "addr2line -s -e %s -f -i %p | "
@@ -673,4 +757,7 @@ fallback:
 		sd_printf(SDOG_EMERG, "%s", *str);
 		free(str);
 	}
+
+	/* dump the stack frames if possible*/
+	dump_stack_frames();
 }
-- 
1.8.1.3.566.gaa39828




More information about the sheepdog mailing list