]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: migrate stacktrace dumping and move headers about: fix reloc overrun
authorKris Van Hees <kris.van.hees@oracle.com>
Fri, 14 Oct 2011 02:42:27 +0000 (22:42 -0400)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:39:56 +0000 (22:39 +0100)
Stacktrace dumping has been moved to the GPL-licensed dtrace_os.c because it
depends on a symbol that is exported as GPL-only.  Functionality in dtrace_isa
that requires stacktrace dumping can now use dtrace_stacktrace().

The GPL-licensed dtrace_os.h C header file is now made available through the
/include/linux hierarchy, and it is included in dtrace.h.

Fixed a bug in dtrace_relocs.c where section names where copied into a memory
area that was 1 byte short, causing various unpleasant forms of behaviour.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
include/linux/dtrace_os.h [moved from kernel/dtrace/systrace_os.h with 68% similarity]
kernel/dtrace/dtrace_os.c
scripts/dtrace_relocs.c

similarity index 68%
rename from kernel/dtrace/systrace_os.h
rename to include/linux/dtrace_os.h
index 914e3f057bcb4c688187bfecf4931e5b7a59852f..9b3268f60885ba3367d038f63fdf3bbecec4e462 100644 (file)
@@ -1,9 +1,12 @@
 /* Copyright (C) 2011 Oracle Corporation */
 
-#ifndef _SYSTRACE_OS_H_
-#define _SYSTRACE_OS_H_
+#ifndef _DTRACE_OS_H_
+#define _DTRACE_OS_H_
+
+#include <asm/unistd.h>
 
 typedef uint32_t dtrace_id_t;
+
 #define DTRACE_IDNONE 0
 
 typedef void (*sys_call_ptr_t)(void);
@@ -31,4 +34,18 @@ typedef struct systrace_info {
 
 extern systrace_info_t *dtrace_syscalls_init(void);
 
-#endif /* _SYSTRACE_OS_H_ */
+#define STACKTRACE_KERNEL      0x01
+#define STACKTRACE_USER                0x02
+#define STACKTRACE_SKIP                0x10
+
+typedef struct stacktrace_state {
+       uint64_t        *pcs;
+       uint64_t        *fps;
+       int             limit;
+       int             depth;
+       int             flags;
+} stacktrace_state_t;
+
+extern void dtrace_stacktrace(stacktrace_state_t *);
+
+#endif /* _DTRACE_OS_H_ */
index d062128e094073e445f3a72ef5ba26f2e3bb1119..56f9000e8a5477f80d815e1c8628548ad634480c 100644 (file)
@@ -6,12 +6,11 @@
  */
 
 #include <linux/cyclic.h>
+#include <linux/dtrace_os.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
-#include <asm/unistd.h>
-
-#include "systrace_os.h"
+#include <asm/stacktrace.h>
 
 /*
  * Return a high resolution timer value that is guaranteed to always increase.
@@ -183,8 +182,8 @@ static systrace_info_t      systrace_info = {
  */
 #undef __SYSCALL
 #define __SYSCALL(nr, sym)                     [nr] { __stringify(sym), },
-#undef _ASM_X86_UNISTD_64_H
-#include <asm/unistd_64.h>
+# undef _ASM_X86_UNISTD_64_H
+#include <asm/unistd.h>
                                            }
                                        };
 
@@ -236,3 +235,109 @@ systrace_info_t *dtrace_syscalls_init() {
        return &systrace_info;
 }
 EXPORT_SYMBOL(dtrace_syscalls_init);
+
+static int dtrace_stacktrace_stack(void *data, char *name)
+{
+       stacktrace_state_t      *st = (stacktrace_state_t *)data;
+
+       /*
+        * We do not skip anything for non-user stack analysis.
+        */
+       if (!(st->flags & STACKTRACE_USER))
+               return 0;
+
+       if (name != NULL && strlen(name) > 3) {
+               /*
+                * Sadly, the dump stack code calls us with both <EOE> and EOI.
+                * Consistency would be much nicer.
+                */
+               if ((name[0] == '<' && name[1] == 'E' && name[2] == 'O') ||
+                   (name[0] == 'E' && name[2] == 'O'))
+                       st->flags &= ~STACKTRACE_SKIP;
+       }
+
+       return 0;
+}
+
+static void dtrace_stacktrace_address(void *data, unsigned long addr,
+                                      int reliable)
+{
+       stacktrace_state_t      *st = (stacktrace_state_t *)data;
+
+       if (st->flags & STACKTRACE_SKIP)
+               return;
+
+       if (reliable == 2) {
+               if (st->fps)
+                       st->fps[st->depth] = addr;
+       } else {
+               if (st->pcs != NULL) {
+                       if (st->depth < st->limit)
+                               st->pcs[st->depth++] = addr;
+               } else
+                       st->depth++;
+       }
+}
+
+static inline int valid_sp(struct thread_info *tinfo, void *p,
+                          unsigned int size, void *end)
+{
+       void    *t = tinfo;
+
+       if (end) {
+               if (p < end && p >= (end - THREAD_SIZE))
+                       return 1;
+               else
+                       return 0;
+       }
+
+       return p > t && p < t + THREAD_SIZE - size;
+}
+
+struct frame {
+       struct frame    *fr_savfp;
+       unsigned long   fr_savpc;
+} __attribute__((packed));
+
+static unsigned long dtrace_stacktrace_walk_stack(
+                                       struct thread_info *tinfo,
+                                       unsigned long *stack,
+                                       unsigned long bp,
+                                       const struct stacktrace_ops *ops,
+                                       void *data, unsigned long *end,
+                                       int *graph)
+{
+       struct frame    *fr = (struct frame *)bp;
+       unsigned long   *pcp = &(fr->fr_savpc);
+
+       while (valid_sp(tinfo, pcp, sizeof(*pcp), end)) {
+               unsigned long   addr = *pcp;
+
+               fr = fr->fr_savfp;
+               ops->address(data, (unsigned long)fr, 2);
+               ops->address(data, addr, 1);
+               pcp = &(fr->fr_savpc);
+       }
+
+       return (unsigned long)fr;
+}
+
+static const struct stacktrace_ops     dtrace_stacktrace_ops = {
+       .stack          = dtrace_stacktrace_stack,
+       .address        = dtrace_stacktrace_address,
+       .walk_stack     = print_context_stack
+};
+
+static const struct stacktrace_ops     dtrace_fpstacktrace_ops = {
+       .stack          = dtrace_stacktrace_stack,
+       .address        = dtrace_stacktrace_address,
+       .walk_stack     = dtrace_stacktrace_walk_stack
+};
+
+void dtrace_stacktrace(stacktrace_state_t *st)
+{
+       dump_trace(NULL, NULL, NULL, 0,
+                  st->fps != NULL ? &dtrace_fpstacktrace_ops
+                                  : &dtrace_stacktrace_ops, st);
+}
+EXPORT_SYMBOL(dtrace_stacktrace);
index 01501bd07c186e1f2f236ba29f53dc574a6d0283..339dc2032380fa8bb705f84f6ffffa47df4fb250 100644 (file)
@@ -154,7 +154,7 @@ static int get_section_info(FILE *fin, char buf[500], struct sym_entry *sect)
        sect->section_used = false;
        sect->section_index = sect_index;
        sect->len = sect_size;
-       sect->sym = malloc(strlen(sect_name));
+       sect->sym = malloc(strlen(sect_name) + 1);
        if (!sect->sym) {
                fprintf(stderr, "relocs failure: "
                        "unable to allocate required amount of memory\n");
@@ -163,8 +163,8 @@ static int get_section_info(FILE *fin, char buf[500], struct sym_entry *sect)
        strcpy((char *)sect->sym, sect_name);
 
 #ifdef INFO
-       fprintf(stderr, "sect: index=%d, name=%s, addr/offset=0x%llx, sect_size=0x%x, align=%s, vma=0x%llx, lma=0x%llx, flags=%s\n",
-               sect_index, sect->sym, sect->addr, sect->len, sect_align,
+       fprintf(stderr, "sect: index=%d, name=%s (%d), addr/offset=0x%llx, sect_size=0x%x, align=%s, vma=0x%llx, lma=0x%llx, flags=%s\n",
+               sect_index, sect->sym, strlen(sect->sym), sect->addr, sect->len, sect_align,
                vma, lma, flags);
 #endif