]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
dtrace: changed the logic for determining SDT probe point locations
authorKris Van Hees <kris.van.hees@oracle.com>
Sun, 29 Jul 2012 08:30:18 +0000 (04:30 -0400)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:40:27 +0000 (22:40 +0100)
The previous version did not account for probes that might be placed in
non-.text segments.  New code also avoids extra passes that were not necessary.

Added on-cpu and off-cpu sched probes.

Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
include/linux/sdt.h
kernel/dtrace/sdt_register.c
kernel/sched/core.c
scripts/Makefile
scripts/dtrace_relocs.c [deleted file]
scripts/dtrace_sdt.sh

index 62db6436dfb2554694f3ebed48a0f4f4a83a705c..4542171c6b7f3b86a1d9efab7ecd224869572da8 100644 (file)
@@ -129,8 +129,7 @@ extern void sdt_probe_enable(sdt_instr_t *);
 extern void sdt_probe_disable(sdt_instr_t *);
 
 typedef struct dtrace_sdt_probeinfo {
-       unsigned long offset;
-       unsigned long base;
+       unsigned long addr;
        unsigned long name_len;
        unsigned long func_len;
        char name[0];
index 25e9dda2cff1c9bdf16061beb1a3db00a229f0ed..6298c6b4d45b125f6017aaa654d5ee306d78f272 100644 (file)
@@ -31,8 +31,8 @@ void sdt_probe_disable(sdt_instr_t *addr)
 }
 EXPORT_SYMBOL(sdt_probe_disable);
 
-static int sdt_probe_resolve(struct module *mp, char *name, char *func,
-                            uintptr_t offset, uintptr_t base, void *nops)
+static int sdt_probe_add(struct module *mp, char *name, char *func,
+                        uintptr_t addr, void *nops)
 {
        sdt_probedesc_t *sdp;
        uint8_t *instr;
@@ -51,8 +51,8 @@ static int sdt_probe_resolve(struct module *mp, char *name, char *func,
                return 1;
        }
 
-       /* convert relative instr to absolute */
-       instr = (uint8_t *)((uintptr_t)_text + base + offset - 1);
+       /* adjust relocation address to beginning of call instruction */
+       instr = (uint8_t *)(addr - 1);
 
        /* TBD: use a kernel list? */
        sdp->sdpd_offset = (uintptr_t)instr;
@@ -97,9 +97,8 @@ void dtrace_register_builtins(void)
        for (cnt = 0; cnt < dtrace_sdt_nprobes; cnt++) {
                char    *func = pi->name + pi->name_len + 1;
 
-               if (sdt_probe_resolve(dtrace_kmod, pi->name, func,
-                                     pi->offset, pi->base, nops))
-                       pr_warning("%s: cannot resolve %s\n",
+               if (sdt_probe_add(dtrace_kmod, pi->name, func, pi->addr, nops))
+                       pr_warning("%s: failed to add SDT probe %s\n",
                                   __func__, pi->name);
 
                nextpi = (void *)pi + sizeof(dtrace_sdt_probeinfo_t)
index 123673291ffbb160734ed889b934d557611a1cf1..5c97598a45e85fa4ce6baaccb9106a686778800f 100644 (file)
@@ -2179,6 +2179,8 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
        trace_sched_switch(prev, next);
        sched_info_switch(rq, prev, next);
        perf_event_task_sched_out(prev, next);
+       DTRACE_SCHED2(off__cpu, struct task_struct *, next,
+                               struct task_struct *, next);
        fire_sched_out_preempt_notifiers(prev, next);
        prepare_lock_switch(rq, next);
        prepare_arch_switch(next);
@@ -2230,6 +2232,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
        finish_lock_switch(rq, prev);
        finish_arch_post_lock_switch();
 
+       DTRACE_SCHED(on__cpu);
        fire_sched_in_preempt_notifiers(current);
        if (mm)
                mmdrop(mm);
index df832ed9c0a384725f534398ebb1e59928cb9cd8..4cdb5168e91b5fd77764e542e66b3e6db2e2ce17 100644 (file)
@@ -3,7 +3,6 @@
 # the kernel for the build process.
 # ---------------------------------------------------------------------------
 # kallsyms:      Find all symbols in vmlinux
-# dtrace_relocs: find and save all __dtrace_probe_ calling probepoints
 # pnmttologo:    Convert pnm files to logo files
 # conmakehash:   Create chartable
 # conmakehash:  Create arrays for initializing the kernel console tables
@@ -12,7 +11,6 @@
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
-hostprogs-$(CONFIG_DTRACE)       += dtrace_relocs
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
diff --git a/scripts/dtrace_relocs.c b/scripts/dtrace_relocs.c
deleted file mode 100644 (file)
index a34f0e7..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-/* Generate assembler source containing __dtrace_probe_* calls (reloc info)
- *
- * inspired by scripts/kallsyms.c
- *
- * (C) 2011 Oracle Corporation
- *
- * Usage: dtrace_relocs input_file_text output_file_elf
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <elf.h>
-
-//#define INFO 1
-//#define SCANF        1
-
-struct sym_entry {
-       unsigned long long addr;
-       unsigned char is_section;
-       unsigned char section_used;
-       int section_index;
-       unsigned long long section_base;
-       unsigned int len;
-       char *sym;
-};
-
-struct text_range {
-       const char *stext, *etext;
-       unsigned long long start, end;
-};
-
-static unsigned long long _stext;      // from System.map
-
-static struct sym_entry *table;
-static unsigned int table_size, table_cnt;
-static int this_section_index;
-static unsigned long long this_section_addr;
-static int relocs_count;
-
-static void usage(void)
-{
-       fprintf(stderr, "Usage: dtrace_relocs input_file_text output_file_elf\n");
-       exit(1);
-}
-
-// skip over whitespace (spaces or tabs)
-static char *deblank(char *str)
-{
-       while (*str == ' ' || *str == '\t')
-                       str++;
-       return str;
-}
-
-static int find_section(char *sect, int sectlen)
-{
-       int ix;
-       struct sym_entry *sym = table;
-
-#if 0
-       fprintf(stderr, "%s: search for sect=<%s>, sectlen=%d:\n",
-               __func__, sect, sectlen);
-#endif
-
-       for (ix = 0; ix < table_cnt; ix++, sym++) {
-#if 0
-               if (sym->is_section && strlen(sym->sym) == sectlen)
-                       fprintf(stderr, "%s: ix=%d, symlen=%d, symname=<%s>\n",
-                               __func__, ix, strlen(sym->sym), sym->sym);
-#endif
-               if (sym->is_section && strlen(sym->sym) == sectlen &&
-                       strncmp(sym->sym, sect, sectlen) == 0) {
-                               sym->section_used = true;
-                               this_section_addr = sym->addr;
-                               return sym->section_index;
-               }
-       }
-
-       return -1;
-}
-
-static int get_this_section(char buf[500])
-{
-       char *sect;
-       int sectlen;
-       int sect_index;
-
-       if (strncmp(buf, "RELOCATION RECORDS FOR [", 24) != 0) {
-               fprintf(stderr, "Bad relocation header: %s\n", buf);
-               exit(2);
-       }
-
-       sect = buf + 24;
-       sectlen = strlen(sect); // includes a trailing newline
-#if 0
-       fprintf(stderr, "%s: sect=<%s>, sectlen=%d\n",
-               __func__, sect, sectlen);
-#endif
-       if (*(sect + sectlen - 3) != ']' || *(sect + sectlen - 2) != ':') {
-               fprintf(stderr, "Bad relocation header: %s\n", buf);
-               exit(2);
-       }
-       *(sect + sectlen - 3) = '\0';
-       sectlen -= 3;   // drop the "]:\n"
-#if 0
-       fprintf(stderr, "%s: isolated section name=<%s>\n", __func__, sect);
-#endif
-       sect_index = find_section(sect, sectlen);
-       if (sect_index < 0) {
-               fprintf(stderr, "Bad section name in relocation header: %s\n",
-                       sect);
-               exit(2);
-       }
-
-       return sect_index;
-}
-
-/*
- * scans 2 lines of section info;
- * first line is already in buf;
- * second line is noise for now;
- */
-static int get_section_info(FILE *fin, char buf[500], struct sym_entry *sect)
-{
-       int rc;
-       int sect_index;
-       char sect_name[200], sect_align[100];
-       unsigned long sect_size, file_offset;
-       unsigned long long vma, lma;
-       char sect_flags[500];
-       char *flags;
-
-       rc = sscanf(buf, " %d %s %lx %llx %llx %lx %s \n",
-               &sect_index, (char *)&sect_name, &sect_size, &vma, &lma,
-               &file_offset, (char *)&sect_align);
-#ifdef SCANF
-       fprintf(stderr, "%s: sscanf.1 rc= %d\n", __func__, rc);
-#endif
-       if (rc != 7)
-               return -1;
-
-       if (!fgets(sect_flags, sizeof(sect_flags), fin))
-               return -1;
-
-#ifdef SCANF
-       fprintf(stderr, "%s: fgets.2 read=<%s>", __func__, sect_flags);
-#endif
-       flags = deblank(sect_flags);
-
-       sect->addr = file_offset;
-       sect->is_section = true;
-       sect->section_used = false;
-       sect->section_index = sect_index;
-       sect->len = sect_size;
-       sect->sym = malloc(strlen(sect_name) + 1);
-       if (!sect->sym) {
-               fprintf(stderr, "relocs failure: "
-                       "unable to allocate required amount of memory\n");
-               exit(1);
-       }
-       strcpy((char *)sect->sym, sect_name);
-
-#ifdef INFO
-       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
-
-       return 0;
-}
-
-static int get_symbol_info(char buf[500], struct sym_entry *s)
-{
-       int rc;
-       unsigned long long relo_offset, pp_offset;
-       char relo_type[200];
-       char probepoint[200];
-
-       //rc = sscanf(buf, " %llx %s %200s-%llx \n",
-       rc = sscanf(buf, " %llx %s %[^ -]-%llx \n",
-               &relo_offset, (char *)&relo_type,
-               (char *)&probepoint, &pp_offset);
-#ifdef SCANF
-       fprintf(stderr, "%s: sscanf.1 rc= %d\n", __func__, rc);
-#endif
-       if (rc != 4)
-               return -1;
-
-       s->addr = relo_offset;
-       s->len = strlen(probepoint);
-       s->is_section = false;
-       s->section_used = false;
-       s->section_index = -1;
-       s->section_base = this_section_addr;
-       s->sym = malloc(s->len + 1);
-       if (!s->sym) {
-               fprintf(stderr, "relocs failure: "
-                       "unable to allocate required amount of memory\n");
-               exit(1);
-       }
-       strcpy((char *)s->sym, probepoint);
-
-#ifdef INFO
-       fprintf(stderr, "sym: addr/offset=0x%llx, strlen=%d, type=%s, name=%s\n",
-               s->addr, s->len, relo_type, s->sym);
-#endif
-
-       relocs_count++;
-       return 0;
-}
-
-static void get_text_addr(char buf[500], char *str_match,
-                       unsigned long long *_adr)
-{
-       int rc;
-       unsigned long long adr;
-       char relo_type[100];
-       char symbol_name[200];
-
-       rc = sscanf(buf, "%llx %s %s\n",
-               &adr, (char *)&relo_type,
-               (char *)&symbol_name);
-#ifdef SCANF
-       fprintf(stderr, "%s: sscanf.1 rc= %d\n", __func__, rc);
-#endif
-       if (rc != 3)
-               return;
-
-       if (strcmp(relo_type, "T"))
-               return;
-       if (strcmp(symbol_name, str_match))
-               return;
-
-       *_adr = adr;
-#ifdef INFO
-       fprintf(stderr, "found '%s':_addr/offset=0x%llx, type=%s, name=%s\n",
-               str_match, adr, relo_type, symbol_name);
-#endif
-}
-
-static void read_info(FILE *fin)
-{
-       char buf[500];
-       bool in_sections = false, in_symbols = false;
-
-       while (!feof(fin)) {
-               if (table_cnt >= table_size) {
-                       table_size += 10000;
-                       table = realloc(table, sizeof(*table) * table_size);
-                       if (!table) {
-                               fprintf(stderr, "out of memory\n");
-                               exit(1);
-                       }
-               }
-
-               if (!fgets(buf, sizeof(buf), fin))
-                       break;
-#ifdef SCANF
-               fprintf(stderr, "dtr: buf=<%s>\n", buf);
-#endif
-
-               if (strncmp(buf, "Sections:", 9) == 0) {
-                       in_sections = true;
-                       continue;
-               }
-               if (strncmp(buf, "RELOCATION RECORDS", 11) == 0) {
-                       in_sections = false;
-                       in_symbols = true;
-                       // isolate & look up section name, get its index
-                       // this call also sets 'this_section_addr'
-                       this_section_index = get_this_section(buf);
-                       continue;
-               }
-
-               if (in_sections) {
-                       if (strncmp(buf, "Idx ", 4) != 0)
-                               if (get_section_info(fin, buf, &table[table_cnt]) == 0)
-                                       table_cnt++;
-                       continue;
-               }
-
-               if (in_symbols) {
-                       if (get_symbol_info(buf, &table[table_cnt]) == 0)
-                               table_cnt++;
-                       else {
-                               if (_stext == 0)
-                                       get_text_addr(buf, "_stext", &_stext);
-                       }
-               }
-       }
-}
-
-static void output_label(FILE *fout, char *label)
-{
-       fprintf(fout, ".globl %s\n", label);
-       fprintf(fout, "\tALGN\n");
-       fprintf(fout, "%s:\n", label);
-}
-
-static void write_relocs(FILE *fout)
-{
-       unsigned int i;
-       int reloc_count = 0;
-
-       fprintf(fout, "#include <asm/types.h>\n");
-       fprintf(fout, "#if BITS_PER_LONG == 64\n");
-       fprintf(fout, "#define PTR .quad\n");
-       fprintf(fout, "#define ALGN .align 8\n");
-       fprintf(fout, "#else\n");
-       fprintf(fout, "#define PTR .long\n");
-       fprintf(fout, "#define ALGN .align 4\n");
-       fprintf(fout, "#endif\n");
-
-       fprintf(fout, "\t.section .rodata, \"a\"\n");
-       fprintf(fout, "\n");
-
-       output_label(fout, "dtrace_relocs_count");
-       fprintf(fout, "\tPTR\t%d\n", relocs_count);
-       fprintf(fout, "\n");
-
-       /*
-        * Provide proper symbols relocatability by their '_stext'
-        * relativeness.  The symbol names cannot be used to construct
-        * normal symbol references as the list of symbols contains
-        * symbols that are declared static and are private to their
-        * .o files.  This prevents .tmp_kallsyms.o or any other
-        * object from referencing them.
-        */
-       output_label(fout, "dtrace_relocs");
-       for (i = 0; i < table_cnt; i++) {
-               // for reloc symbols (not sections):
-               // print symbol relative address, section base address,
-               // call target string length, call target string/name;
-               if (!table[i].is_section) {
-                       fprintf(fout, "\tPTR\t%#llx\n", _stext + table[i].addr);
-                       fprintf(fout, "\tPTR\t%#llx\n", table[i].section_base);
-                       fprintf(fout, "\tPTR\t%d\n", table[i].len);
-                       fprintf(fout, "\t.asciz\t\"%s\"\n", table[i].sym);
-                       fprintf(fout, "\tALGN\n");
-                       reloc_count++;
-               }
-       }
-
-       fprintf(fout, "\n");
-
-       if (reloc_count != relocs_count) {
-               fprintf(fout, "relocs error: reloc counters do not agree (%d vs. %d\n)",
-                       relocs_count, reloc_count);
-               exit(3);
-       }
-}
-
-int main(int argc, char *argv[])
-{
-       char *infile, *outfile;
-       FILE *fin, *fout;
-
-
-       if (argc != 3)
-               usage();
-
-       infile = argv[1];
-       outfile = argv[2];
-
-       fin = fopen(infile, "r");
-       if (!fin) {
-               fprintf(stderr, "relocs: cannot open input file '%s'\n",
-                       infile);
-               exit(2);
-       }
-       fout = fopen(outfile, "w");
-       if (!fout) {
-               fprintf(stderr, "relocs: cannot create output file '%s'\n",
-                       outfile);
-               exit(2);
-       }
-
-       read_info(fin);
-       fclose(fin);
-
-       write_relocs(fout);
-       fclose(fout);
-
-       return 0;
-}
index b7a27de890435bdb54b3c7a8d9e42aabfc2ed0b9..0d85f18c556cf7c886d939f4008b1959d2c08672 100755 (executable)
 
 LANG=C
 
-fn="$1"
-
-objdump -htr "$fn" | \
-    awk '/^Sections:/ {
-            getline;
-            getline;
-            while ($0 !~ /SYMBOL/) {
-                sect = $2;
-                addr = $6;
+ofn="$1"
+lfn="$2"
 
+(
+    objdump -htr "$ofn" | \
+       awk -v lfn=${lfn} \
+           '/^Sections:/ {
                 getline;
-                if (/CODE/)
-                    sectbase[sect] = addr;
-
                 getline;
+                while ($0 !~ /SYMBOL/) {
+                    sect = $2;
+                    addr = $6;
+
+                    getline;
+                    if (/CODE/)
+                        sectbase[sect] = addr;
+
+                    getline;
+                }
+                next;
             }
-            next;
-        }
 
-        / F / {
-            printf "%16s %s F %s\n", $4, $1, $6;
-            next;
-        }
+            / F / {
+                printf "%16s %s F %s\n", $4, $1, $6;
 
-        /^RELOC/ {
-            sub(/^[^\[]+\[/, "");
-            sub(/].*$/, "");
-            sect = $1;
-            next;
+                if (!lfn)
+                    printf "%s t %s\n", $1, $6;
+
+                next;
+            }
+
+            /^RELOC/ {
+                sub(/^[^\[]+\[/, "");
+                sub(/].*$/, "");
+                sect = $1;
+                next;
+            }
+
+            /__dtrace_probe_/ {
+                $3 = substr($3, 16);
+                sub(/-.*$/, "", $3);
+                printf "%16s %s R %s %s\n", sect, $1, $3, sectbase[sect];
+                next;
+            }' | \
+       sort
+    [ "x${lfn}" != "x" ] && nm ${lfn}
+) | \
+    awk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) {
+            tmp = $0;
+            if (length(v0) > 8) {
+                d = length(v0);
+                v0h = strtonum("0x"substr(v0, 1, d - 8));
+                v0l = strtonum("0x"substr(v0, d - 8 + 1));
+                d = length(v1);
+                v1h = strtonum("0x"substr(v1, 1, d - 8));
+                v1l = strtonum("0x"substr(v1, d - 8 + 1));
+
+                v0h += v1h;
+                v0l += v1l;
+
+                d = sprintf("%x", v0l);
+                if (length(d) > 8)
+                    v0h++;
+
+                d = sprintf("%x%x", v0h, v0l);
+            } else {
+                v0 = strtonum("0x"v0);
+                v1 = strtonum("0x"v1);
+                d = sprintf("%x", v0 + v1);
+            }
+            $0 = tmp;
+
+            return d;
         }
 
-        /__dtrace_probe_/ {
-            $3 = substr($3, 16);
-            sub(/-.*$/, "", $3);
+        function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) {
+            tmp = $0;
+            if (length(v0) > 8) {
+                d = length(v0);
+                v0h = strtonum("0x"substr(v0, 1, d - 8));
+                v0l = strtonum("0x"substr(v0, d - 8 + 1));
+                d = length(v1);
+                v1h = strtonum("0x"substr(v1, 1, d - 8));
+                v1l = strtonum("0x"substr(v1, d - 8 + 1));
 
-            printf "%16s %s R %s %s\n", sect, $1, $3, sectbase[sect];
-            next;
-        }' | \
-    sort | \
-    awk 'BEGIN {
+                if (v0l > v1l) {
+                    if (v0h >= v1h) {
+                        d = sprintf("%x%x", v0h - v1h, v0l - v1l);
+                    } else {
+                        printf "#error Invalid addresses: %x vs %x", v0, v1 \
+                                                               > /dev/stderr;
+                        errc++;
+                    }
+                } else {
+                    printf "#error Invalid addresses: %x vs %x", v0, v1 \
+                                                               > /dev/stderr;
+                    errc++;
+                }
+            } else {
+                v0 = strtonum("0x"v0);
+                v1 = strtonum("0x"v1);
+                d = sprintf("%x", v0 - v1);
+            }
+            $0 = tmp;
+
+            return d;
+        }
+
+        BEGIN {
             print "#include <asm/types.h>";
             print "#if BITS_PER_LONG == 64";
             print "# define PTR .quad";
@@ -59,21 +128,38 @@ objdump -htr "$fn" | \
             print "dtrace_sdt_probes:";
         }
 
-        / F / {
-            fun = $4;
+        NF < 4 {
+            fun = $3;
+
+            if (fun in prdata) {
+                baseaddr = $1;
+                sub(/^0+/, "", baseaddr);
+
+                $0 = prdata[fun];
+                sub(/^0+/, "", $1);
+                sub(/^0+/, "", $4);
+
+                print "\tPTR\t0x" addl(baseaddr, subl($1, $4));
+                print "\tPTR\t" length($3);
+                print "\tPTR\t" length(fun);
+                print "\t.asciz\t\042" $3 "\042";
+                print "\t.asciz\t\042" fun "\042";
+                print "\tALGN";
+
+                probec++;
+            }
             next;
         }
 
-        / R / {
-            print "\tPTR\t0x" $2;
-            print "\tPTR\t0x" $5;
-            print "\tPTR\t" length($4);
-            print "\tPTR\t" length(fun);
-            print "\t.asciz\t\042" $4 "\042";
-            print "\t.asciz\t\042" fun "\042";
-            print "\tALGN";
+        $3 == "F" {
+            fun = $4;
+            addr = $2;
+            next;
+        }
 
-            probec++;
+        $3 == "R" {
+            prdata[fun] = $2 " " $5 " " $4 " " addr;
+            next;
         }
 
         END {
@@ -82,4 +168,9 @@ objdump -htr "$fn" | \
             print "\tALGN";
             print "dtrace_sdt_nprobes:";
             print "\tPTR\t" probec;
+
+            if (errc > 0) {
+                print errc " errors generating SDT probe data." > /dev/stderr;
+                exit 1;
+            }
         }'