This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[PATCH] tracepoints: Generate Module.tracepoints file
- From: Jan Blunck <jblunck at suse dot de>
- To: Mathieu Desnoyers <mathieu dot desnoyers at polymtl dot ca>
- Cc: systemtap at sourceware dot org, ltt-dev Mailing List <ltt-dev at lists dot casi dot polymtl dot ca>
- Date: Thu, 18 Sep 2008 17:08:42 +0200
- Subject: [PATCH] tracepoints: Generate Module.tracepoints file
- Organization: SUSE LINUX Products GmbH, GF Markus Rex, HRB 16746 (AG Nuernberg)
This adds support to generate the Module.tracepoints file by modpost. This
can be read by tools like SystemTap very similar to the Module.markers file.
Signed-off-by: Jan Blunck <jblunck@suse.de>
---
Makefile | 6 +
scripts/Makefile.modpost | 5 +
scripts/mod/modpost.c | 173 +++++++++++++++++++++++++++++++++++++++++++++--
scripts/mod/modpost.h | 3
4 files changed, 178 insertions(+), 9 deletions(-)
Index: b/Makefile
===================================================================
--- a/Makefile
+++ b/Makefile
@@ -1178,7 +1178,8 @@ MRPROPER_FILES += .config .config.old in
include/linux/autoconf.h include/linux/version.h \
include/linux/utsrelease.h \
include/linux/bounds.h include/asm*/asm-offsets.h \
- Module.symvers Module.markers tags TAGS cscope*
+ Module.symvers Module.markers Module.tracepoints \
+ tags TAGS cscope*
# clean - Delete most, but leave enough to build external modules
#
@@ -1197,7 +1198,8 @@ clean: archclean $(clean-dirs)
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.symtypes' -o -name 'modules.order' \
- -o -name 'Module.markers' -o -name '.tmp_*.o.*' \) \
+ -o -name 'Module.markers' -o -name 'Module.tracepoints' \
+ -o -name '.tmp_*.o.*' \) \
-type f -print | xargs rm -f
# mrproper - Delete all generated files, including .config
Index: b/scripts/Makefile.modpost
===================================================================
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -61,8 +61,11 @@ kernelsymfile := $(objtree)/Module.symve
modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
kernelmarkersfile := $(objtree)/Module.markers
modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+kerneltracepointsfile := $(objtree)/Module.tracepoints
+moduletracepointsfile := $(firstword $(KBUILD_EXTMOD))/Module.tracepoints
markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
+tracepointsfile = $(if $(KBUILD_EXTMOD),$(moduletracepointsfile),$(kerneltracepointsfile))
# Step 1), find all modules listed in $(MODVERDIR)/
__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -87,6 +90,8 @@ modpost = scripts/mod/modpost
$(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \
$(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
$(if $(CONFIG_MARKERS),-M $(markersfile)) \
+ $(if $(CONFIG_TRACEPOINTS),-T $(kerneltracepointsfile)) \
+ $(if $(CONFIG_TRACEPOINTS),-t $(tracepointsfile)) \
$(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
$(if $(cross_build),-c) \
-N $(firstword $(wildcard $(dir $(MODVERDIR))/Module.supported \
Index: b/scripts/mod/modpost.c
===================================================================
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -439,6 +439,8 @@ static int parse_elf(struct elf_info *in
info->export_gpl_future_sec = i;
else if (strcmp(secname, "__markers_strings") == 0)
info->markers_strings_sec = i;
+ else if (strcmp(secname, "__tracepoints_strings") == 0)
+ info->tracepoints_strings_sec = i;
if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;
@@ -1545,6 +1547,63 @@ static void get_markers(struct elf_info
}
}
+static void get_tracepoints(struct elf_info *info, struct module *mod)
+{
+ const Elf_Shdr *sh = &info->sechdrs[info->tracepoints_strings_sec];
+ const char *strings = (const char *) info->hdr + sh->sh_offset;
+ const Elf_Sym *sym, *first_sym, *last_sym;
+ size_t n;
+
+ if (!info->tracepoints_strings_sec)
+ return;
+
+ /*
+ * First count the strings. We look for all the symbols defined
+ * in the __tracepoints_strings section named __tpstrtab_*. For
+ * these local names, the compiler puts a random .NNN suffix on,
+ * so the names don't correspond exactly.
+ */
+ first_sym = last_sym = NULL;
+ n = 0;
+ for (sym = info->symtab_start; sym < info->symtab_stop; sym++)
+ if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+ sym->st_shndx == info->tracepoints_strings_sec &&
+ !strncmp(info->strtab + sym->st_name,
+ "__tpstrtab_", sizeof "__tpstrtab_" - 1)) {
+ if (first_sym == NULL)
+ first_sym = sym;
+ last_sym = sym;
+ ++n;
+ }
+
+ if (n == 0)
+ return;
+
+ /*
+ * Now collect each name and format into a line for the output.
+ * Lines look like:
+ * marker_name vmlinux marker %s format %d
+ * The format string after the second \t can use whitespace.
+ */
+ mod->tracepoints = NOFAIL(malloc(sizeof mod->tracepoints[0] * n));
+ mod->ntracepoints = n;
+
+ n = 0;
+ for (sym = first_sym; sym <= last_sym; sym++)
+ if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+ sym->st_shndx == info->tracepoints_strings_sec &&
+ !strncmp(info->strtab + sym->st_name,
+ "__tpstrtab_", sizeof "__tpstrtab_" - 1)) {
+ const char *name = strings + sym->st_value;
+ const char *fmt = strchr(name, ':') + 1;
+ char *line = NULL;
+ asprintf(&line, "%.*s\t%s\t%s\n", fmt - name - 1, name,
+ mod->name, fmt);
+ NOFAIL(line);
+ mod->tracepoints[n++] = line;
+ }
+}
+
void *supported_file;
unsigned long supported_size;
@@ -1643,6 +1702,7 @@ static void read_symbols(char *modname)
sizeof(mod->srcversion)-1);
get_markers(&info, mod);
+ get_tracepoints(&info, mod);
parse_elf_finish(&info);
@@ -2091,6 +2151,91 @@ static void write_markers(const char *fn
write_if_changed(&buf, fname);
}
+static void add_tracepoint(struct module *mod, const char *name,
+ const char *fmt)
+{
+ char *line = NULL;
+ asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+ NOFAIL(line);
+
+ mod->tracepoints = NOFAIL(realloc(mod->tracepoints,
+ ((mod->ntracepoints + 1) *
+ sizeof mod->tracepoints[0])));
+ mod->tracepoints[mod->ntracepoints++] = line;
+}
+
+static void read_tracepoints(const char *fname)
+{
+ unsigned long size, pos = 0;
+ void *file = grab_file(fname, &size);
+ char *line;
+
+ if (!file) /* No old tracepoints, silently ignore */
+ return;
+
+ while ((line = get_next_line(&pos, file, size))) {
+ char *tracepoint, *modname, *fmt;
+ struct module *mod;
+
+ tracepoint = line;
+ modname = strchr(tracepoint, '\t');
+ if (!modname)
+ goto fail;
+ *modname++ = '\0';
+ fmt = strchr(modname, '\t');
+ if (!fmt)
+ goto fail;
+ *fmt++ = '\0';
+ if (*tracepoint == '\0' || *modname == '\0')
+ goto fail;
+
+ mod = find_module(modname);
+ if (!mod) {
+ if (is_vmlinux(modname))
+ have_vmlinux = 1;
+ mod = new_module(NOFAIL(strdup(modname)));
+ mod->skip = 1;
+ }
+
+ if (!mod->skip)
+ add_tracepoint(mod, tracepoint, fmt);
+ }
+ return;
+fail:
+ fatal("parse error in tracepoints list file\n");
+}
+
+static void write_tracepoints(const char *fname)
+{
+ struct buffer buf = { };
+ struct module *mod;
+ size_t i;
+
+ for (mod = modules; mod; mod = mod->next)
+ if ((!external_module || !mod->skip) &&
+ mod->tracepoints != NULL) {
+ /*
+ * Sort the strings so we can skip duplicates when
+ * we write them out.
+ */
+ qsort(mod->tracepoints, mod->ntracepoints,
+ sizeof mod->tracepoints[0], &compare_strings);
+ for (i = 0; i < mod->ntracepoints; ++i) {
+ char *line = mod->tracepoints[i];
+ buf_write(&buf, line, strlen(line));
+ while (i + 1 < mod->ntracepoints &&
+ !strcmp(mod->tracepoints[i],
+ mod->tracepoints[i + 1]))
+ free(mod->tracepoints[i++]);
+ free(mod->tracepoints[i]);
+ }
+ free(mod->tracepoints);
+ mod->tracepoints = NULL;
+ }
+
+ write_if_changed(&buf, fname);
+}
+
struct ext_sym_list {
struct ext_sym_list *next;
const char *file;
@@ -2104,13 +2249,15 @@ int main(int argc, char **argv)
char *dump_write = NULL;
char *markers_read = NULL;
char *markers_write = NULL;
+ char *tracepoints_read = NULL;
+ char *tracepoints_write = NULL;
const char *supported = NULL;
int opt;
int err;
struct ext_sym_list *extsym_iter;
struct ext_sym_list *extsym_start = NULL;
- while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:N:")) != -1) {
+ while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:N:t:T:")) != -1) {
switch (opt) {
case 'i':
kernel_read = optarg;
@@ -2148,12 +2295,18 @@ int main(int argc, char **argv)
case 'w':
warn_unresolved = 1;
break;
- case 'M':
- markers_write = optarg;
- break;
- case 'K':
- markers_read = optarg;
- break;
+ case 'M':
+ markers_write = optarg;
+ break;
+ case 'K':
+ markers_read = optarg;
+ break;
+ case 't':
+ tracepoints_write = optarg;
+ break;
+ case 'T':
+ tracepoints_read = optarg;
+ break;
case 'N':
supported = optarg;
break;
@@ -2219,5 +2372,11 @@ int main(int argc, char **argv)
if (markers_write)
write_markers(markers_write);
+ if (tracepoints_read)
+ read_tracepoints(tracepoints_read);
+
+ if (tracepoints_write)
+ write_tracepoints(tracepoints_write);
+
return err;
}
Index: b/scripts/mod/modpost.h
===================================================================
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -114,6 +114,8 @@ struct module {
struct buffer dev_table_buf;
char **markers;
size_t nmarkers;
+ char **tracepoints;
+ size_t ntracepoints;
char srcversion[25];
};
@@ -129,6 +131,7 @@ struct elf_info {
Elf_Section export_unused_gpl_sec;
Elf_Section export_gpl_future_sec;
Elf_Section markers_strings_sec;
+ Elf_Section tracepoints_strings_sec;
const char *strtab;
char *modinfo;
unsigned int modinfo_len;