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 */ 62 #define __trace_mark(name, call_private, format, args...) \ 63 do { \ 64 - static const char __mstrtab_name_##name[] \ 65 __attribute__((section("__markers_strings"))) \ 66 - = #name; \ 67 - static const char __mstrtab_format_##name[] \ 68 - __attribute__((section("__markers_strings"))) \ 69 - = format; \ 70 static struct marker __mark_##name \ 71 __attribute__((section("__markers"), aligned(8))) = \ 72 - { __mstrtab_name_##name, __mstrtab_format_##name, \ 73 0, 0, marker_probe_cb, \ 74 { __mark_empty_function, NULL}, NULL }; \ 75 __mark_check_format(format, ## args); \
··· 61 */ 62 #define __trace_mark(name, call_private, format, args...) \ 63 do { \ 64 + static const char __mstrtab_##name[] \ 65 __attribute__((section("__markers_strings"))) \ 66 + = #name "\0" format; \ 67 static struct marker __mark_##name \ 68 __attribute__((section("__markers"), aligned(8))) = \ 69 + { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ 70 0, 0, marker_probe_cb, \ 71 { __mark_empty_function, NULL}, NULL }; \ 72 __mark_check_format(format, ## args); \
+11
scripts/Makefile.modpost
··· 13 # 2) modpost is then used to 14 # 3) create one <module>.mod.c file pr. module 15 # 4) create one Module.symvers file with CRC for all exported symbols 16 # 5) compile all <module>.mod.c files 17 # 6) final link of the module to a <module.ko> file 18 ··· 46 47 kernelsymfile := $(objtree)/Module.symvers 48 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers 49 50 # Step 1), find all modules listed in $(MODVERDIR)/ 51 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) ··· 68 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ 69 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ 70 $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ 71 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) 72 73 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules ··· 88 # Declare generated files as targets for modpost 89 $(symverfile): __modpost ; 90 $(modules:.ko=.mod.c): __modpost ; 91 92 93 # Step 5), compile all *.mod.c files
··· 13 # 2) modpost is then used to 14 # 3) create one <module>.mod.c file pr. module 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 17 # 5) compile all <module>.mod.c files 18 # 6) final link of the module to a <module.ko> file 19 ··· 45 46 kernelsymfile := $(objtree)/Module.symvers 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)) 52 53 # Step 1), find all modules listed in $(MODVERDIR)/ 54 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) ··· 63 $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ 64 $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ 65 $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ 66 + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ 67 + $(if $(CONFIG_MARKERS),-M $(markersfile)) \ 68 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) 69 70 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules ··· 81 # Declare generated files as targets for modpost 82 $(symverfile): __modpost ; 83 $(modules:.ko=.mod.c): __modpost ; 84 + 85 + ifdef CONFIG_MARKERS 86 + $(markersfile): __modpost ; 87 + endif 88 89 90 # Step 5), compile all *.mod.c files
+163 -1
scripts/mod/modpost.c
··· 11 * Usage: modpost vmlinux module1.o module2.o ... 12 */ 13 14 #include <ctype.h> 15 #include "modpost.h" 16 #include "../../include/linux/license.h" ··· 437 info->export_unused_gpl_sec = i; 438 else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 439 info->export_gpl_future_sec = i; 440 441 if (sechdrs[i].sh_type != SHT_SYMTAB) 442 continue; ··· 1474 } 1475 } 1476 1477 static void read_symbols(char *modname) 1478 { 1479 const char *symname; ··· 1580 if (version || (all_versions && !is_vmlinux(modname))) 1581 get_src_version(modname, mod->srcversion, 1582 sizeof(mod->srcversion)-1); 1583 1584 parse_elf_finish(&info); 1585 ··· 1929 write_if_changed(&buf, fname); 1930 } 1931 1932 int main(int argc, char **argv) 1933 { 1934 struct module *mod; 1935 struct buffer buf = { }; 1936 char *kernel_read = NULL, *module_read = NULL; 1937 char *dump_write = NULL; 1938 int opt; 1939 int err; 1940 1941 - while ((opt = getopt(argc, argv, "i:I:msSo:aw")) != -1) { 1942 switch (opt) { 1943 case 'i': 1944 kernel_read = optarg; ··· 2053 case 'w': 2054 warn_unresolved = 1; 2055 break; 2056 default: 2057 exit(1); 2058 } ··· 2105 "To see full details build your kernel with:\n" 2106 "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 2107 sec_mismatch_count); 2108 2109 return err; 2110 }
··· 11 * Usage: modpost vmlinux module1.o module2.o ... 12 */ 13 14 + #define _GNU_SOURCE 15 + #include <stdio.h> 16 #include <ctype.h> 17 #include "modpost.h" 18 #include "../../include/linux/license.h" ··· 435 info->export_unused_gpl_sec = i; 436 else if (strcmp(secname, "__ksymtab_gpl_future") == 0) 437 info->export_gpl_future_sec = i; 438 + else if (strcmp(secname, "__markers_strings") == 0) 439 + info->markers_strings_sec = i; 440 441 if (sechdrs[i].sh_type != SHT_SYMTAB) 442 continue; ··· 1470 } 1471 } 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 + 1529 static void read_symbols(char *modname) 1530 { 1531 const char *symname; ··· 1520 if (version || (all_versions && !is_vmlinux(modname))) 1521 get_src_version(modname, mod->srcversion, 1522 sizeof(mod->srcversion)-1); 1523 + 1524 + get_markers(&info, mod); 1525 1526 parse_elf_finish(&info); 1527 ··· 1867 write_if_changed(&buf, fname); 1868 } 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 + 1956 int main(int argc, char **argv) 1957 { 1958 struct module *mod; 1959 struct buffer buf = { }; 1960 char *kernel_read = NULL, *module_read = NULL; 1961 char *dump_write = NULL; 1962 + char *markers_read = NULL; 1963 + char *markers_write = NULL; 1964 int opt; 1965 int err; 1966 1967 + while ((opt = getopt(argc, argv, "i:I:msSo:awM:K:")) != -1) { 1968 switch (opt) { 1969 case 'i': 1970 kernel_read = optarg; ··· 1903 case 'w': 1904 warn_unresolved = 1; 1905 break; 1906 + case 'M': 1907 + markers_write = optarg; 1908 + break; 1909 + case 'K': 1910 + markers_read = optarg; 1911 + break; 1912 default: 1913 exit(1); 1914 } ··· 1949 "To see full details build your kernel with:\n" 1950 "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", 1951 sec_mismatch_count); 1952 + 1953 + if (markers_read) 1954 + read_markers(markers_read); 1955 + 1956 + if (markers_write) 1957 + write_markers(markers_write); 1958 1959 return err; 1960 }
+3
scripts/mod/modpost.h
··· 112 int has_init; 113 int has_cleanup; 114 struct buffer dev_table_buf; 115 char srcversion[25]; 116 }; 117 ··· 128 Elf_Section export_gpl_sec; 129 Elf_Section export_unused_gpl_sec; 130 Elf_Section export_gpl_future_sec; 131 const char *strtab; 132 char *modinfo; 133 unsigned int modinfo_len;
··· 112 int has_init; 113 int has_cleanup; 114 struct buffer dev_table_buf; 115 + char **markers; 116 + size_t nmarkers; 117 char srcversion[25]; 118 }; 119 ··· 126 Elf_Section export_gpl_sec; 127 Elf_Section export_unused_gpl_sec; 128 Elf_Section export_gpl_future_sec; 129 + Elf_Section markers_strings_sec; 130 const char *strtab; 131 char *modinfo; 132 unsigned int modinfo_len;