Linux Kernel Markers: create modpost file

This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous
to the Module.symvers file, the build will now write a Module.markers file
when CONFIG_MARKERS=y is set. This file lists the name, defining module, and
format string of each marker, separated by \t characters. This simple text
file can be used by offline build procedures for instrumentation code,
analogous to how System.map and Module.symvers can be useful to have for
kernels other than the one you are running right now.

The strings are made easy to extract by having the __trace_mark macro define
the name and format together in a single array called __mstrtab_* in the
__markers_strings section. This is straightforward and reliable as long as
the marker structs are always defined by this macro. It is an unreasonable
amount of hairy work to extract the string pointers from the __markers section
structs, which entails handling a relocation type for every machine under the
sun.

Mathieu :
- Ran through checkpatch.pl

Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: David Smith <dsmith@redhat.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Mathieu Desnoyers and committed by Linus Torvalds b2e3e658 fb40bd78

+180 -7
+3 -6
include/linux/marker.h
··· 61 61 */ 62 62 #define __trace_mark(name, call_private, format, args...) \ 63 63 do { \ 64 - static const char __mstrtab_name_##name[] \ 64 + static const char __mstrtab_##name[] \ 65 65 __attribute__((section("__markers_strings"))) \ 66 - = #name; \ 67 - static const char __mstrtab_format_##name[] \ 68 - __attribute__((section("__markers_strings"))) \ 69 - = format; \ 66 + = #name "\0" format; \ 70 67 static struct marker __mark_##name \ 71 68 __attribute__((section("__markers"), aligned(8))) = \ 72 - { __mstrtab_name_##name, __mstrtab_format_##name, \ 69 + { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ 73 70 0, 0, marker_probe_cb, \ 74 71 { __mark_empty_function, NULL}, NULL }; \ 75 72 __mark_check_format(format, ## args); \
+11
scripts/Makefile.modpost
··· 13 13 # 2) modpost is then used to 14 14 # 3) create one <module>.mod.c file pr. module 15 15 # 4) create one Module.symvers file with CRC for all exported symbols 16 + # 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers 16 17 # 5) compile all <module>.mod.c files 17 18 # 6) final link of the module to a <module.ko> file 18 19 ··· 46 45 47 46 kernelsymfile := $(objtree)/Module.symvers 48 47 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers 48 + kernelmarkersfile := $(objtree)/Module.markers 49 + modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers 50 + 51 + markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile)) 49 52 50 53 # Step 1), find all modules listed in $(MODVERDIR)/ 51 54 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) ··· 68 63 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ 69 64 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ 70 65 $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ 66 + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ 67 + $(if $(CONFIG_MARKERS),-M $(markersfile)) \ 71 68 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) 72 69 73 70 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules ··· 88 81 # Declare generated files as targets for modpost 89 82 $(symverfile): __modpost ; 90 83 $(modules:.ko=.mod.c): __modpost ; 84 + 85 + ifdef CONFIG_MARKERS 86 + $(markersfile): __modpost ; 87 + endif 91 88 92 89 93 90 # Step 5), compile all *.mod.c files
+163 -1
scripts/mod/modpost.c
··· 11 11 * Usage: modpost vmlinux module1.o module2.o ... 12 12 */ 13 13 14 + #define _GNU_SOURCE 15 + #include <stdio.h> 14 16 #include <ctype.h> 15 17 #include "modpost.h" 16 18 #include "../../include/linux/license.h" ··· 437 435 info->export_unused_gpl_sec = i; 438 436 else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 439 437 info->export_gpl_future_sec = i; 438 + else if (strcmp(secname, "__markers_strings") == 0) 439 + info->markers_strings_sec = i; 440 440 441 441 if (sechdrs[i].sh_type != SHT_SYMTAB) 442 442 continue; ··· 1474 1470 } 1475 1471 } 1476 1472 1473 + static void get_markers(struct elf_info *info, struct module *mod) 1474 + { 1475 + const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec]; 1476 + const char *strings = (const char *) info->hdr + sh->sh_offset; 1477 + const Elf_Sym *sym, *first_sym, *last_sym; 1478 + size_t n; 1479 + 1480 + if (!info->markers_strings_sec) 1481 + return; 1482 + 1483 + /* 1484 + * First count the strings. We look for all the symbols defined 1485 + * in the __markers_strings section named __mstrtab_*. For 1486 + * these local names, the compiler puts a random .NNN suffix on, 1487 + * so the names don't correspond exactly. 1488 + */ 1489 + first_sym = last_sym = NULL; 1490 + n = 0; 1491 + for (sym = info->symtab_start; sym < info->symtab_stop; sym++) 1492 + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT && 1493 + sym->st_shndx == info->markers_strings_sec && 1494 + !strncmp(info->strtab + sym->st_name, 1495 + "__mstrtab_", sizeof "__mstrtab_" - 1)) { 1496 + if (first_sym == NULL) 1497 + first_sym = sym; 1498 + last_sym = sym; 1499 + ++n; 1500 + } 1501 + 1502 + if (n == 0) 1503 + return; 1504 + 1505 + /* 1506 + * Now collect each name and format into a line for the output. 1507 + * Lines look like: 1508 + * marker_name vmlinux marker %s format %d 1509 + * The format string after the second \t can use whitespace. 1510 + */ 1511 + mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n)); 1512 + mod->nmarkers = n; 1513 + 1514 + n = 0; 1515 + for (sym = first_sym; sym <= last_sym; sym++) 1516 + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT && 1517 + sym->st_shndx == info->markers_strings_sec && 1518 + !strncmp(info->strtab + sym->st_name, 1519 + "__mstrtab_", sizeof "__mstrtab_" - 1)) { 1520 + const char *name = strings + sym->st_value; 1521 + const char *fmt = strchr(name, '\0') + 1; 1522 + char *line = NULL; 1523 + asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt); 1524 + NOFAIL(line); 1525 + mod->markers[n++] = line; 1526 + } 1527 + } 1528 + 1477 1529 static void read_symbols(char *modname) 1478 1530 { 1479 1531 const char *symname; ··· 1580 1520 if (version || (all_versions && !is_vmlinux(modname))) 1581 1521 get_src_version(modname, mod->srcversion, 1582 1522 sizeof(mod->srcversion)-1); 1523 + 1524 + get_markers(&info, mod); 1583 1525 1584 1526 parse_elf_finish(&info); 1585 1527 ··· 1929 1867 write_if_changed(&buf, fname); 1930 1868 } 1931 1869 1870 + static void add_marker(struct module *mod, const char *name, const char *fmt) 1871 + { 1872 + char *line = NULL; 1873 + asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt); 1874 + NOFAIL(line); 1875 + 1876 + mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) * 1877 + sizeof mod->markers[0]))); 1878 + mod->markers[mod->nmarkers++] = line; 1879 + } 1880 + 1881 + static void read_markers(const char *fname) 1882 + { 1883 + unsigned long size, pos = 0; 1884 + void *file = grab_file(fname, &size); 1885 + char *line; 1886 + 1887 + if (!file) /* No old markers, silently ignore */ 1888 + return; 1889 + 1890 + while ((line = get_next_line(&pos, file, size))) { 1891 + char *marker, *modname, *fmt; 1892 + struct module *mod; 1893 + 1894 + marker = line; 1895 + modname = strchr(marker, '\t'); 1896 + if (!modname) 1897 + goto fail; 1898 + *modname++ = '\0'; 1899 + fmt = strchr(modname, '\t'); 1900 + if (!fmt) 1901 + goto fail; 1902 + *fmt++ = '\0'; 1903 + if (*marker == '\0' || *modname == '\0') 1904 + goto fail; 1905 + 1906 + mod = find_module(modname); 1907 + if (!mod) { 1908 + if (is_vmlinux(modname)) 1909 + have_vmlinux = 1; 1910 + mod = new_module(NOFAIL(strdup(modname))); 1911 + mod->skip = 1; 1912 + } 1913 + 1914 + add_marker(mod, marker, fmt); 1915 + } 1916 + return; 1917 + fail: 1918 + fatal("parse error in markers list file\n"); 1919 + } 1920 + 1921 + static int compare_strings(const void *a, const void *b) 1922 + { 1923 + return strcmp(*(const char **) a, *(const char **) b); 1924 + } 1925 + 1926 + static void write_markers(const char *fname) 1927 + { 1928 + struct buffer buf = { }; 1929 + struct module *mod; 1930 + size_t i; 1931 + 1932 + for (mod = modules; mod; mod = mod->next) 1933 + if ((!external_module || !mod->skip) && mod->markers != NULL) { 1934 + /* 1935 + * Sort the strings so we can skip duplicates when 1936 + * we write them out. 1937 + */ 1938 + qsort(mod->markers, mod->nmarkers, 1939 + sizeof mod->markers[0], &compare_strings); 1940 + for (i = 0; i < mod->nmarkers; ++i) { 1941 + char *line = mod->markers[i]; 1942 + buf_write(&buf, line, strlen(line)); 1943 + while (i + 1 < mod->nmarkers && 1944 + !strcmp(mod->markers[i], 1945 + mod->markers[i + 1])) 1946 + free(mod->markers[i++]); 1947 + free(mod->markers[i]); 1948 + } 1949 + free(mod->markers); 1950 + mod->markers = NULL; 1951 + } 1952 + 1953 + write_if_changed(&buf, fname); 1954 + } 1955 + 1932 1956 int main(int argc, char **argv) 1933 1957 { 1934 1958 struct module *mod; 1935 1959 struct buffer buf = { }; 1936 1960 char *kernel_read = NULL, *module_read = NULL; 1937 1961 char *dump_write = NULL; 1962 + char *markers_read = NULL; 1963 + char *markers_write = NULL; 1938 1964 int opt; 1939 1965 int err; 1940 1966 1941 - while ((opt = getopt(argc, argv, "i:I:msSo:aw")) != -1) { 1967 + while ((opt = getopt(argc, argv, "i:I:msSo:awM:K:")) != -1) { 1942 1968 switch (opt) { 1943 1969 case 'i': 1944 1970 kernel_read = optarg; ··· 2053 1903 case 'w': 2054 1904 warn_unresolved = 1; 2055 1905 break; 1906 + case 'M': 1907 + markers_write = optarg; 1908 + break; 1909 + case 'K': 1910 + markers_read = optarg; 1911 + break; 2056 1912 default: 2057 1913 exit(1); 2058 1914 } ··· 2105 1949 "To see full details build your kernel with:\n" 2106 1950 "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2107 1951 sec_mismatch_count); 1952 + 1953 + if (markers_read) 1954 + read_markers(markers_read); 1955 + 1956 + if (markers_write) 1957 + write_markers(markers_write); 2108 1958 2109 1959 return err; 2110 1960 }
+3
scripts/mod/modpost.h
··· 112 112 int has_init; 113 113 int has_cleanup; 114 114 struct buffer dev_table_buf; 115 + char **markers; 116 + size_t nmarkers; 115 117 char srcversion[25]; 116 118 }; 117 119 ··· 128 126 Elf_Section export_gpl_sec; 129 127 Elf_Section export_unused_gpl_sec; 130 128 Elf_Section export_gpl_future_sec; 129 + Elf_Section markers_strings_sec; 131 130 const char *strtab; 132 131 char *modinfo; 133 132 unsigned int modinfo_len;