public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
       [not found]         ` <20070921130752.GB9431@infradead.org>
@ 2007-09-21 16:11           ` Frank Ch. Eigler
  2007-09-21 18:58             ` Christoph Hellwig
  0 siblings, 1 reply; 18+ messages in thread
From: Frank Ch. Eigler @ 2007-09-21 16:11 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: systemtap

Hi -

On Fri, Sep 21, 2007 at 02:07:52PM +0100, Christoph Hellwig wrote:

> [...]  markers are already getting far too complex, [...]

Collecting these strings into a dedicated section does not constitute
added complexity worth talking about.

> Once the systemtap people are ready for merging their stuff into
> the kernel tree we can cater towards their needs.

You keep saying only that.  If you've given thought to how this could
actually look and work, please do be a generous fellow and share.


- FChE

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-09-21 16:11           ` [patch 1/4] Linux Kernel Markers - Architecture Independent Code Frank Ch. Eigler
@ 2007-09-21 18:58             ` Christoph Hellwig
  2007-09-21 20:00               ` Frank Ch. Eigler
  0 siblings, 1 reply; 18+ messages in thread
From: Christoph Hellwig @ 2007-09-21 18:58 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: Christoph Hellwig, systemtap

On Fri, Sep 21, 2007 at 09:33:48AM -0400, Frank Ch. Eigler wrote:
> > Once the systemtap people are ready for merging their stuff into
> > the kernel tree we can cater towards their needs.
> 
> You keep saying only that.  If you've given thought to how this could
> actually look and work, please do be a generous fellow and share.

It's pretty simple - everything that pokes into kernel internals belongs
into the kernel tree, otherwise it's unsupported.

That's the highlevel outline, if you look at the details there's a lot
more wrong about systemtap, but we'll get to that and fix it once you
actually submit bits.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-09-21 18:58             ` Christoph Hellwig
@ 2007-09-21 20:00               ` Frank Ch. Eigler
  0 siblings, 0 replies; 18+ messages in thread
From: Frank Ch. Eigler @ 2007-09-21 20:00 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: systemtap

Hi -

On Fri, Sep 21, 2007 at 05:32:33PM +0100, Christoph Hellwig wrote:
> > > Once the systemtap people are ready for merging their stuff into
> > > the kernel tree we can cater towards their needs.
> > 
> > You keep saying only that.  If you've given thought to how this could
> > actually look and work, please do be a generous fellow and share.
> 
> It's pretty simple - everything that pokes into kernel internals belongs
> into the kernel tree, otherwise it's unsupported.

That's not a meaningful answer.  The whole purpose of systemtap is to
allow users to poke at kernel and (soon?) user-space internals of
their choosing.

- FChE

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
       [not found]           ` <20070921133820.GD13129@Krystal>
@ 2007-10-15 20:11             ` Frank Ch. Eigler
  2007-10-15 23:12               ` Mathieu Desnoyers
  0 siblings, 1 reply; 18+ messages in thread
From: Frank Ch. Eigler @ 2007-10-15 20:11 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Denys Vlasenko, systemtap, Christoph Hellwig, Rusty Russell,
	akpm, linux-kernel

Hi -

I wrote:

> [...]
> > The marker metadata must be stored in at least one place in the kernel
> > image - this just happens to be a convenient one that David Smith's
> > recent systemtap code used.  Without it, we'd probably have to do a
> > more complicated search, following the pointers within the __markers
> > structs.  [...]

Our team is farther along adapting to this change against 2.6.23-mm1,
and we have run into a complication.  It's more of a distribution
issue.

We would prefer to retain systemtap's capability to build
instrumentation for a kernel other than the currently running one.
Such instrumentation can be then copied and run on a distinct machine.
This has meant relying on development data: make install_headers +
Makefiles (as packaged by Fedora/RHEL), and to a lesser extent
separated debugging information.

Markers are attractive partly because they don't require debugging
information, so the data needs to be found in an executable image.
But we prefer not to force the executable image itself to be
installed, for example because /boot is relatively small.  So we would
prefer something in between: something small that we can put into the
development package.

If there exists sympathy to this problem, Roland McGrath supposes we
could implement a standardized solution, a file like Module.symvers,
containing the marker names & format strings extracted at build time.
Any opinions?


PS. I wonder why the marker name/format strings are put into a
__markers_strings object section at all, considering that the only
place where that is used again appears to be this code in
kernel/module.c:

        markersstringsindex = find_sec(hdr, sechdrs, secstrings,
                                        "__markers_strings");

and the "markersstringsindex" variable is never used.


- FChE

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-10-15 20:11             ` Frank Ch. Eigler
@ 2007-10-15 23:12               ` Mathieu Desnoyers
  2007-10-15 23:50                 ` Roland McGrath
  0 siblings, 1 reply; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-10-15 23:12 UTC (permalink / raw)
  To: Frank Ch. Eigler
  Cc: Denys Vlasenko, systemtap, Christoph Hellwig, Rusty Russell,
	akpm, linux-kernel

* Frank Ch. Eigler (fche@redhat.com) wrote:
> Hi -
> 
> I wrote:
> 
> > [...]
> > > The marker metadata must be stored in at least one place in the kernel
> > > image - this just happens to be a convenient one that David Smith's
> > > recent systemtap code used.  Without it, we'd probably have to do a
> > > more complicated search, following the pointers within the __markers
> > > structs.  [...]
> 
> Our team is farther along adapting to this change against 2.6.23-mm1,
> and we have run into a complication.  It's more of a distribution
> issue.
> 
> We would prefer to retain systemtap's capability to build
> instrumentation for a kernel other than the currently running one.
> Such instrumentation can be then copied and run on a distinct machine.
> This has meant relying on development data: make install_headers +
> Makefiles (as packaged by Fedora/RHEL), and to a lesser extent
> separated debugging information.
> 
> Markers are attractive partly because they don't require debugging
> information, so the data needs to be found in an executable image.
> But we prefer not to force the executable image itself to be
> installed, for example because /boot is relatively small.  So we would
> prefer something in between: something small that we can put into the
> development package.
> 
> If there exists sympathy to this problem, Roland McGrath supposes we
> could implement a standardized solution, a file like Module.symvers,
> containing the marker names & format strings extracted at build time.
> Any opinions?
> 

Hi Frank,

I think the main issue with the solution you propose is that it doesn't
deal with markers in modules, am I right ?

I will soon come with a marker iterator and a module that provides a
userspace -and in kernel- interface to enable/disable markers. Actually,
I already have the code ready in my LTTng snapshots. I can provide a
link if you want to have a look.

> 
> PS. I wonder why the marker name/format strings are put into a
> __markers_strings object section at all, considering that the only
> place where that is used again appears to be this code in
> kernel/module.c:
> 
>         markersstringsindex = find_sec(hdr, sechdrs, secstrings,
>                                         "__markers_strings");
> 
> and the "markersstringsindex" variable is never used.
> 

Considering that  I want to minimize the impact on the system, I put the
marker strings in their own memory location rather than clobbering the
memory containing the kernel strings (which will likely be used more
often than markers). It makes sure that I don't pollute cachelines
otherwise containing useful kernel strings.

Mathieu

> 
> - FChE

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-10-15 23:12               ` Mathieu Desnoyers
@ 2007-10-15 23:50                 ` Roland McGrath
  2007-10-25 19:17                   ` Mathieu Desnoyers
  0 siblings, 1 reply; 18+ messages in thread
From: Roland McGrath @ 2007-10-15 23:50 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Frank Ch. Eigler, Denys Vlasenko, systemtap, Christoph Hellwig,
	Rusty Russell, akpm, linux-kernel

> I think the main issue with the solution you propose is that it doesn't
> deal with markers in modules, am I right ?

My suggestion applies as well to modules as anything else.  
What "like Module.symvers" means is something like:

name1	vmlinux		%s
name2	fs/nfs/nfs	%d

All the modules built by the same kernel build go into this one file.

Modules packaged separately for the same kernel could provide additional
files of the same kind.

> I will soon come with a marker iterator and a module that provides a
> userspace -and in kernel- interface to enable/disable markers. Actually,
> I already have the code ready in my LTTng snapshots. I can provide a
> link if you want to have a look.

That's clearly straightforward to do given the basic markers data structures.

It does not address the need for an offline list of markers available in a
particular kernel build or set of modules that you are not running right now.
The approach now available for that is grovelling through the markers data
structures extracted from vmlinux and .ko ELF files offline.  That is more
work than one should have to do, and has lots of problems with coping with
different packaging details, etc.


Thanks,
Roland

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-10-15 23:50                 ` Roland McGrath
@ 2007-10-25 19:17                   ` Mathieu Desnoyers
  2007-10-26 14:30                     ` Frank Ch. Eigler
  0 siblings, 1 reply; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-10-25 19:17 UTC (permalink / raw)
  To: Roland McGrath
  Cc: Frank Ch. Eigler, Denys Vlasenko, systemtap, Christoph Hellwig,
	Rusty Russell, akpm, linux-kernel

* Roland McGrath (roland@redhat.com) wrote:
> > I think the main issue with the solution you propose is that it doesn't
> > deal with markers in modules, am I right ?
> 
> My suggestion applies as well to modules as anything else.  
> What "like Module.symvers" means is something like:
> 
> name1	vmlinux		%s
> name2	fs/nfs/nfs	%d
> 
> All the modules built by the same kernel build go into this one file.
> 
> Modules packaged separately for the same kernel could provide additional
> files of the same kind.
> 
> > I will soon come with a marker iterator and a module that provides a
> > userspace -and in kernel- interface to enable/disable markers. Actually,
> > I already have the code ready in my LTTng snapshots. I can provide a
> > link if you want to have a look.
> 
> That's clearly straightforward to do given the basic markers data structures.
> 
> It does not address the need for an offline list of markers available in a
> particular kernel build or set of modules that you are not running right now.
> The approach now available for that is grovelling through the markers data
> structures extracted from vmlinux and .ko ELF files offline.  That is more
> work than one should have to do, and has lots of problems with coping with
> different packaging details, etc.
> 

Since gcc is required to build the systemtap probes on the development
marchine, I don't see why it would be much harder to also require prople
to install drawf ? Or maybe the "crash" tool ?

I guess you must already need to extract the symbols for your kprobes.
Do you use kallsyms for this ? The way I see it, you could maybe extract
kallsyms symbols corresponding to the markers data structures quite
easily.

I would rather prefer not to implement superfluous built-time data
extraction in the kernel build system just to make userspace simpler. If
we can leverage what currently exists, that would be better.

Mathieu

> 
> Thanks,
> Roland

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code
  2007-10-25 19:17                   ` Mathieu Desnoyers
@ 2007-10-26 14:30                     ` Frank Ch. Eigler
  2007-11-01  1:07                       ` [PATCH] markers: modpost Roland McGrath
  0 siblings, 1 reply; 18+ messages in thread
From: Frank Ch. Eigler @ 2007-10-26 14:30 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: Roland McGrath, Frank Ch. Eigler, Denys Vlasenko, systemtap,
	Christoph Hellwig, Rusty Russell, akpm, linux-kernel

Hi -

On Thu, Oct 25, 2007 at 03:17:22PM -0400, Mathieu Desnoyers wrote:
> [...]
> Since gcc is required to build the systemtap probes on the development
> marchine, I don't see why it would be much harder to also require prople
> to install drawf ? Or maybe the "crash" tool ?

The crash tool requires the dwarf data to work.  The dwarf data for an
entire kernel (including all the modules) is on the order of hundreds
of megabytes.  The symbol & marker list would be one thousandth the
size.  You can see the deployment attractiveness of the latter.

> I guess you must already need to extract the symbols for your kprobes.
> Do you use kallsyms for this? 

Nope.  /proc/kallsyms is a another run-time-only source of data, and
so is not applicable for off-line (ahead-of-time) mapping.

> I would rather prefer not to implement superfluous built-time data
> extraction in the kernel build system just to make userspace
> simpler. [...]

It is not superfluous, as it would solve a real distribution problem.


- FChE

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] markers: modpost
  2007-10-26 14:30                     ` Frank Ch. Eigler
@ 2007-11-01  1:07                       ` Roland McGrath
  2007-11-01  1:12                         ` Roland McGrath
  2007-11-01  2:46                         ` Mathieu Desnoyers
  0 siblings, 2 replies; 18+ messages in thread
From: Roland McGrath @ 2007-11-01  1:07 UTC (permalink / raw)
  To: Andrew Morton, Mathieu Desnoyers; +Cc: linux-kernel, systemtap


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 method of extracting the strings is somewhat crude, but is very
simple and should work fine in practice for the foreseeable future.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  174 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 187 insertions(+), 1 deletions(-)

diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index d988f5d..6321870 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 93ac52a..df80bfc 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,73 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static size_t strlen_with_padding(const char *start, const char *limit)
+{
+	const char *p = memchr(start, '\0', limit - start);
+	if (p == NULL)
+		return 0;
+	do
+		++p;
+	while (p < limit && *p == '\0');
+	return p - start;
+}
+
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
+	const char *strings;
+	const char *strings_end;
+	const char *p;
+	size_t n, i;
+
+	if (!info->markers_strings_sec)
+		return;
+
+	strings = (const char *) info->hdr + sh->sh_offset;
+	strings_end = strings + sh->sh_size;
+
+	/*
+	 * First count the strings.  They come in pairs of name, format.
+	 */
+	for (n = 0, p = strings; p < strings_end; ++n) {
+		size_t len = strlen_with_padding(p, strings_end);
+		if (len == 0)
+			break;
+		p += len;
+	}
+	if (n % 2 != 0 || p != strings_end) {
+		warn("%s.ko has bad __markers_strings, ignoring it\n",
+		     mod->name);
+		return;
+	}
+
+	if (n == 0)
+		return;
+
+	/*
+	 * Now collect each pair into a formatted 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->markers = NOFAIL(malloc(sizeof mod->markers[0] * n / 2));
+	mod->nmarkers = n / 2;
+
+	p = strings;
+	for (i = 0; i < n; i += 2) {
+		const char *name, *fmt;
+		name = p;
+		p += strlen_with_padding(p, strings_end);
+		fmt = p;
+		p += strlen_with_padding(p, strings_end);
+
+		mod->markers[i / 2] = NULL;
+		asprintf(&mod->markers[i / 2], "%s\t%s\t%s\n",
+			 name, mod->name, fmt);
+		NOFAIL(mod->markers[i / 2]);
+	}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1372,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1722,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(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->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1814,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1843,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1890,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 0ffed17..175301a 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-01  1:07                       ` [PATCH] markers: modpost Roland McGrath
@ 2007-11-01  1:12                         ` Roland McGrath
  2007-11-01  2:46                         ` Mathieu Desnoyers
  1 sibling, 0 replies; 18+ messages in thread
From: Roland McGrath @ 2007-11-01  1:12 UTC (permalink / raw)
  To: Frank Eigler; +Cc: systemtap

Frank, I hope you can take it away from there.  If it needs to be reworked,
there should be enough made clear by my patch for someone else on the team
to follow up on the details.  

A simple change of a couple of lines will be required for the Fedora-style
packaging to pick up the file once the patch goes in.  

If the patch turns out noncontroversial and is on track upstream but does
not look like it will hit 2.6.24, I will throw it into Fedora development
(rawhide) builds early for you.


Thanks,
Roland


--- kernel.spec	31 Oct 2007 17:58:34 -0700	1.228
+++ kernel.spec	31 Oct 2007 18:00:41 -0700	
@@ -1276,6 +1276,10 @@ BuildKernel() {
     # first copy everything
     cp --parents `find  -type f -name "Makefile*" -o -name "Kconfig*"` $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
     cp Module.symvers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
+    if [ -s Module.markers ]; then
+      cp Module.markers $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
+    fi
+    cp System.map $RPM_BUILD_ROOT/lib/modules/$KernelVer/build
     # then drop all but the needed Makefiles/Kconfig files
     rm -rf $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/Documentation
     rm -rf $RPM_BUILD_ROOT/lib/modules/$KernelVer/build/scripts

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-01  1:07                       ` [PATCH] markers: modpost Roland McGrath
  2007-11-01  1:12                         ` Roland McGrath
@ 2007-11-01  2:46                         ` Mathieu Desnoyers
  2007-11-01  9:38                           ` Roland McGrath
  1 sibling, 1 reply; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-11-01  2:46 UTC (permalink / raw)
  To: Roland McGrath; +Cc: Andrew Morton, linux-kernel, systemtap

* Roland McGrath (roland@redhat.com) wrote:
> 
> 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 method of extracting the strings is somewhat crude, but is very
> simple and should work fine in practice for the foreseeable future.
> 

Hi Roland,

I'm ok with the idea of extracting such information, but I doubt one can
assume the strings will always be layed out in the same order in the
__markers_strings section. We also shouldn't assume that a marker name
will be a neighbor of its format string.

If we want to do it safely, I think we should iterate from
__start___markers to __stop___markers symbols of vmlinux and get the
pointers to the name/format string pairs.

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

Mathieu


> Signed-off-by: Roland McGrath <roland@redhat.com>
> ---
>  scripts/Makefile.modpost |   11 +++
>  scripts/mod/modpost.c    |  174 +++++++++++++++++++++++++++++++++++++++++++++-
>  scripts/mod/modpost.h    |    3 +
>  3 files changed, 187 insertions(+), 1 deletions(-)
> 
> diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
> index d988f5d..6321870 100644
> --- a/scripts/Makefile.modpost
> +++ b/scripts/Makefile.modpost
> @@ -13,6 +13,7 @@
>  # 2) modpost is then used to
>  # 3)  create one <module>.mod.c file pr. module
>  # 4)  create one Module.symvers file with CRC for all exported symbols
> +# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
>  # 5) compile all <module>.mod.c files
>  # 6) final link of the module to a <module.ko> file
>  
> @@ -45,6 +46,10 @@ include scripts/Makefile.lib
>  
>  kernelsymfile := $(objtree)/Module.symvers
>  modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
> +kernelmarkersfile := $(objtree)/Module.markers
> +modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
> +
> +markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
>  
>  # Step 1), find all modules listed in $(MODVERDIR)/
>  __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
> @@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
>   $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
>   $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
>   $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
> + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
> + $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
>   $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
>  
>  quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
> @@ -81,6 +88,10 @@ vmlinux.o: FORCE
>  $(symverfile):         __modpost ;
>  $(modules:.ko=.mod.c): __modpost ;
>  
> +ifdef CONFIG_MARKERS
> +$(markersfile):	       __modpost ;
> +endif
> +
>  
>  # Step 5), compile all *.mod.c files
>  
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 93ac52a..df80bfc 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -11,6 +11,8 @@
>   * Usage: modpost vmlinux module1.o module2.o ...
>   */
>  
> +#define _GNU_SOURCE
> +#include <stdio.h>
>  #include <ctype.h>
>  #include "modpost.h"
>  #include "../../include/linux/license.h"
> @@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
>  			info->export_unused_gpl_sec = i;
>  		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
>  			info->export_gpl_future_sec = i;
> +		else if (strcmp(secname, "__markers_strings") == 0)
> +			info->markers_strings_sec = i;
>  
>  		if (sechdrs[i].sh_type != SHT_SYMTAB)
>  			continue;
> @@ -1249,6 +1253,73 @@ static int exit_section_ref_ok(const char *name)
>  	return 0;
>  }
>  
> +static size_t strlen_with_padding(const char *start, const char *limit)
> +{
> +	const char *p = memchr(start, '\0', limit - start);
> +	if (p == NULL)
> +		return 0;
> +	do
> +		++p;
> +	while (p < limit && *p == '\0');
> +	return p - start;
> +}
> +
> +static void get_markers(struct elf_info *info, struct module *mod)
> +{
> +	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
> +	const char *strings;
> +	const char *strings_end;
> +	const char *p;
> +	size_t n, i;
> +
> +	if (!info->markers_strings_sec)
> +		return;
> +
> +	strings = (const char *) info->hdr + sh->sh_offset;
> +	strings_end = strings + sh->sh_size;
> +
> +	/*
> +	 * First count the strings.  They come in pairs of name, format.
> +	 */
> +	for (n = 0, p = strings; p < strings_end; ++n) {
> +		size_t len = strlen_with_padding(p, strings_end);
> +		if (len == 0)
> +			break;
> +		p += len;
> +	}
> +	if (n % 2 != 0 || p != strings_end) {
> +		warn("%s.ko has bad __markers_strings, ignoring it\n",
> +		     mod->name);
> +		return;
> +	}
> +
> +	if (n == 0)
> +		return;
> +
> +	/*
> +	 * Now collect each pair into a formatted 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->markers = NOFAIL(malloc(sizeof mod->markers[0] * n / 2));
> +	mod->nmarkers = n / 2;
> +
> +	p = strings;
> +	for (i = 0; i < n; i += 2) {
> +		const char *name, *fmt;
> +		name = p;
> +		p += strlen_with_padding(p, strings_end);
> +		fmt = p;
> +		p += strlen_with_padding(p, strings_end);
> +
> +		mod->markers[i / 2] = NULL;
> +		asprintf(&mod->markers[i / 2], "%s\t%s\t%s\n",
> +			 name, mod->name, fmt);
> +		NOFAIL(mod->markers[i / 2]);
> +	}
> +}
> +
>  static void read_symbols(char *modname)
>  {
>  	const char *symname;
> @@ -1301,6 +1372,8 @@ static void read_symbols(char *modname)
>  		get_src_version(modname, mod->srcversion,
>  				sizeof(mod->srcversion)-1);
>  
> +	get_markers(&info, mod);
> +
>  	parse_elf_finish(&info);
>  
>  	/* Our trick to get versioning for struct_module - it's
> @@ -1649,6 +1722,91 @@ static void write_dump(const char *fname)
>  	write_if_changed(&buf, fname);
>  }
>  
> +static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
> +						     sizeof mod->markers[0])));
> +	mod->markers[mod->nmarkers++] = line;
> +}
> +
> +static void read_markers(const char *fname)
> +{
> +	unsigned long size, pos = 0;
> +	void *file = grab_file(fname, &size);
> +	char *line;
> +
> +        if (!file)
> +		/* No old markers, silently ignore */
> +		return;
> +
> +	while ((line = get_next_line(&pos, file, size))) {
> +		char *marker, *modname, *fmt;
> +		struct module *mod;
> +
> +		marker = line;
> +		if (!(modname = strchr(marker, '\t')))
> +			goto fail;
> +		*modname++ = '\0';
> +		if (!(fmt = strchr(modname, '\t')))
> +			goto fail;
> +		*fmt++ = '\0';
> +		if (*marker == '\0' || *modname == '\0')
> +			goto fail;
> +
> +		if (!(mod = find_module(modname))) {
> +			if (is_vmlinux(modname)) {
> +				have_vmlinux = 1;
> +			}
> +			mod = new_module(NOFAIL(strdup(modname)));
> +			mod->skip = 1;
> +		}
> +
> +		add_marker(mod, marker, fmt);
> +	}
> +	return;
> +fail:
> +	fatal("parse error in markers list file\n");
> +}
> +
> +static int compare_strings(const void *a, const void *b)
> +{
> +	return strcmp(*(const char **) a, *(const char **) b);
> +}
> +
> +static void write_markers(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->markers != NULL) {
> +			/*
> +			 * Sort the strings so we can skip duplicates when
> +			 * we write them out.
> +			 */
> +			qsort(mod->markers, mod->nmarkers,
> +			      sizeof mod->markers[0], &compare_strings);
> +			for (i = 0; i < mod->nmarkers; ++i) {
> +				char *line = mod->markers[i];
> +				buf_write(&buf, line, strlen(line));
> +				while (i + 1 < mod->nmarkers &&
> +				       !strcmp(mod->markers[i],
> +					       mod->markers[i + 1]))
> +					free(mod->markers[i++]);
> +				free(mod->markers[i]);
> +			}
> +			free(mod->markers);
> +			mod->markers = NULL;
> +		}
> +
> +	write_if_changed(&buf, fname);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	struct module *mod;
> @@ -1656,10 +1814,12 @@ int main(int argc, char **argv)
>  	char fname[SZ];
>  	char *kernel_read = NULL, *module_read = NULL;
>  	char *dump_write = NULL;
> +	char *markers_read = NULL;
> +	char *markers_write = NULL;
>  	int opt;
>  	int err;
>  
> -	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
> +	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
>  		switch(opt) {
>  			case 'i':
>  				kernel_read = optarg;
> @@ -1683,6 +1843,12 @@ int main(int argc, char **argv)
>  			case 'w':
>  				warn_unresolved = 1;
>  				break;
> +			case 'M':
> +				markers_write = optarg;
> +				break;
> +			case 'K':
> +				markers_read = optarg;
> +				break;
>  			default:
>  				exit(1);
>  		}
> @@ -1724,5 +1890,11 @@ int main(int argc, char **argv)
>  	if (dump_write)
>  		write_dump(dump_write);
>  
> +	if (markers_read)
> +		read_markers(markers_read);
> +
> +	if (markers_write)
> +		write_markers(markers_write);
> +
>  	return err;
>  }
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index 0ffed17..175301a 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -110,6 +110,8 @@ struct module {
>  	int has_init;
>  	int has_cleanup;
>  	struct buffer dev_table_buf;
> +	char **markers;
> +	size_t nmarkers;
>  	char	     srcversion[25];
>  };
>  
> @@ -124,6 +126,7 @@ struct elf_info {
>  	Elf_Section  export_gpl_sec;
>  	Elf_Section  export_unused_gpl_sec;
>  	Elf_Section  export_gpl_future_sec;
> +	Elf_Section  markers_strings_sec;
>  	const char   *strtab;
>  	char	     *modinfo;
>  	unsigned int modinfo_len;

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-01  2:46                         ` Mathieu Desnoyers
@ 2007-11-01  9:38                           ` Roland McGrath
  2007-11-01 11:24                             ` Mathieu Desnoyers
  0 siblings, 1 reply; 18+ messages in thread
From: Roland McGrath @ 2007-11-01  9:38 UTC (permalink / raw)
  To: Mathieu Desnoyers; +Cc: Andrew Morton, linux-kernel, systemtap

> If we want to do it safely, I think we should iterate from
> __start___markers to __stop___markers symbols of vmlinux and get the
> pointers to the name/format string pairs.
> 
> The same can then be done with modules using the __markers section.
> 
> Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work.
cf "somewhat crude" and "foreseeable future" in my patch's log entry.
Knock yourself out if you're looking for more tedious hacking to do in
modpost.c, but I say fix it when it breaks.


Thanks,
Roland

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-01  9:38                           ` Roland McGrath
@ 2007-11-01 11:24                             ` Mathieu Desnoyers
  2007-11-08 19:31                               ` David Smith
  0 siblings, 1 reply; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-11-01 11:24 UTC (permalink / raw)
  To: Roland McGrath; +Cc: Andrew Morton, linux-kernel, systemtap

* Roland McGrath (roland@redhat.com) wrote:
> > If we want to do it safely, I think we should iterate from
> > __start___markers to __stop___markers symbols of vmlinux and get the
> > pointers to the name/format string pairs.
> > 
> > The same can then be done with modules using the __markers section.
> > 
> > Or maybe is there some reason not to do that ?
> 
> It's just rather a pain in the ass, a whole lot more fiddly work.
> cf "somewhat crude" and "foreseeable future" in my patch's log entry.
> Knock yourself out if you're looking for more tedious hacking to do in
> modpost.c, but I say fix it when it breaks.
> 

Hmmmm, I have rarely seen code go into mainline without addressing valid
technical criticism first. Please fix.

I'll look into it if I find the time.

Mathieu

> 
> Thanks,
> Roland

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-01 11:24                             ` Mathieu Desnoyers
@ 2007-11-08 19:31                               ` David Smith
  2007-11-08 19:36                                 ` Mathieu Desnoyers
  0 siblings, 1 reply; 18+ messages in thread
From: David Smith @ 2007-11-08 19:31 UTC (permalink / raw)
  To: Mathieu Desnoyers; +Cc: Roland McGrath, Andrew Morton, linux-kernel, systemtap

Mathieu Desnoyers wrote:
> * Roland McGrath (roland@redhat.com) wrote:
>>> If we want to do it safely, I think we should iterate from
>>> __start___markers to __stop___markers symbols of vmlinux and get the
>>> pointers to the name/format string pairs.
>>>
>>> The same can then be done with modules using the __markers section.
>>>
>>> Or maybe is there some reason not to do that ?
>> It's just rather a pain in the ass, a whole lot more fiddly work.
>> cf "somewhat crude" and "foreseeable future" in my patch's log entry.
>> Knock yourself out if you're looking for more tedious hacking to do in
>> modpost.c, but I say fix it when it breaks.
>>
> 
> Hmmmm, I have rarely seen code go into mainline without addressing valid
> technical criticism first. Please fix.
> 
> I'll look into it if I find the time.
> 
> Mathieu

Mathieu,

Here's an updated patch, written by Roland (that I tested for him), that
looks for all marker symbols in the __markers_strings section.  It doesn't
get the pointers from the __markers section because that is very difficult
to do in modpost (having to handle the architecture-dependent relocations
applied to those pointers).

See what you think.

---
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 method of extracting the strings is somewhat crude, but is pretty
simple and should work fine in practice for the foreseeable future.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  184 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 197 insertions(+), 1 deletions(-)

diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index d988f5d..6321870 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 93ac52a..bbaf26d 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,83 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
+	const char *strings = (const char *) info->hdr + sh->sh_offset;
+	const Elf_Sym *sym, *first_sym, *last_sym;
+	const char *name;
+	size_t n;
+
+	if (!info->markers_strings_sec)
+		return;
+
+	/*
+	 * First count the strings.  They come in pairs of name, format.
+	 * We look for all the symbols defined in the __markers_strings
+	 * section.  They are named __mstrtab_name_* and __mstrtab_format_*
+	 * in matching pairs.  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->markers_strings_sec) {
+			if (first_sym == NULL)
+				first_sym = sym;
+			last_sym = sym;
+			++n;
+			name = info->strtab + sym->st_name;
+			if (n % 2 == 0 ?
+			    !strncmp(name, "__mstrtab_name_",
+				     sizeof "__mstrtab_name_" - 1) :
+			    !strncmp(name, "__mstrtab_format_",
+				     sizeof "__mstrtab_format_" - 1)) {
+				warn("%s.ko has unexpected symbol \"%s\"\n",
+				     mod->name, name);
+				first_sym = NULL;
+			}
+		}
+
+	if (n % 2 != 0 || first_sym == NULL) {
+		warn("%s.ko has bad __markers_strings, ignoring it\n",
+		     mod->name);
+		return;
+	}
+
+	if (n == 0)
+		return;
+
+	/*
+	 * Now collect each pair into a formatted line for the output.
+	 * Lines look like:
+	 *	marker_name	vmlinux	marker %s format %d
+	 * The format string after the second \t can use whitespace.
+	 */
+	n /= 2;
+	mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
+	mod->nmarkers = n;
+
+	name = NULL;
+	n = 0;
+	for (sym = first_sym; sym <= last_sym; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec) {
+			const char *str = strings + sym->st_value;
+			if (name == NULL)
+				name = str;
+			else {
+				char *line = NULL;
+				asprintf(&line, "%s\t%s\t%s\n",
+					 name, mod->name, str);
+				NOFAIL(line);
+				mod->markers[n++] = line;
+				name = NULL;
+			}
+		}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1382,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1732,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(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->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1824,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1853,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1900,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 0ffed17..175301a 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;





^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-08 19:31                               ` David Smith
@ 2007-11-08 19:36                                 ` Mathieu Desnoyers
  2007-11-08 19:45                                   ` David Smith
  2007-11-09 16:36                                   ` David Smith
  0 siblings, 2 replies; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-11-08 19:36 UTC (permalink / raw)
  To: David Smith; +Cc: Roland McGrath, Andrew Morton, linux-kernel, systemtap

* David Smith (dsmith@redhat.com) wrote:
> Mathieu Desnoyers wrote:
> > * Roland McGrath (roland@redhat.com) wrote:
> >>> If we want to do it safely, I think we should iterate from
> >>> __start___markers to __stop___markers symbols of vmlinux and get the
> >>> pointers to the name/format string pairs.
> >>>
> >>> The same can then be done with modules using the __markers section.
> >>>
> >>> Or maybe is there some reason not to do that ?
> >> It's just rather a pain in the ass, a whole lot more fiddly work.
> >> cf "somewhat crude" and "foreseeable future" in my patch's log entry.
> >> Knock yourself out if you're looking for more tedious hacking to do in
> >> modpost.c, but I say fix it when it breaks.
> >>
> > 
> > Hmmmm, I have rarely seen code go into mainline without addressing valid
> > technical criticism first. Please fix.
> > 
> > I'll look into it if I find the time.
> > 
> > Mathieu
> 
> Mathieu,
> 
> Here's an updated patch, written by Roland (that I tested for him), that
> looks for all marker symbols in the __markers_strings section.  It doesn't
> get the pointers from the __markers section because that is very difficult
> to do in modpost (having to handle the architecture-dependent relocations
> applied to those pointers).
> 

Hrm, what would happen if a gcc optimization eventually decides to mix
the memory layout of the strings ? Is there something that specifies
that they won't ?

> See what you think.
> 
> ---
> 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 method of extracting the strings is somewhat crude, but is pretty
> simple and should work fine in practice for the foreseeable future.
> 
> Signed-off-by: Roland McGrath <roland@redhat.com>
> ---
>  scripts/Makefile.modpost |   11 +++
>  scripts/mod/modpost.c    |  184 +++++++++++++++++++++++++++++++++++++++++++++-
>  scripts/mod/modpost.h    |    3 +
>  3 files changed, 197 insertions(+), 1 deletions(-)
> 
> diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
> index d988f5d..6321870 100644
> --- a/scripts/Makefile.modpost
> +++ b/scripts/Makefile.modpost
> @@ -13,6 +13,7 @@
>  # 2) modpost is then used to
>  # 3)  create one <module>.mod.c file pr. module
>  # 4)  create one Module.symvers file with CRC for all exported symbols
> +# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
>  # 5) compile all <module>.mod.c files
>  # 6) final link of the module to a <module.ko> file
>  
> @@ -45,6 +46,10 @@ include scripts/Makefile.lib
>  
>  kernelsymfile := $(objtree)/Module.symvers
>  modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
> +kernelmarkersfile := $(objtree)/Module.markers
> +modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
> +
> +markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
>  
>  # Step 1), find all modules listed in $(MODVERDIR)/
>  __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
> @@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
>   $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
>   $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
>   $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
> + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
> + $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
>   $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
>  
>  quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
> @@ -81,6 +88,10 @@ vmlinux.o: FORCE
>  $(symverfile):         __modpost ;
>  $(modules:.ko=.mod.c): __modpost ;
>  
> +ifdef CONFIG_MARKERS
> +$(markersfile):	       __modpost ;
> +endif
> +
>  
>  # Step 5), compile all *.mod.c files
>  
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 93ac52a..bbaf26d 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -11,6 +11,8 @@
>   * Usage: modpost vmlinux module1.o module2.o ...
>   */
>  
> +#define _GNU_SOURCE
> +#include <stdio.h>
>  #include <ctype.h>
>  #include "modpost.h"
>  #include "../../include/linux/license.h"
> @@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
>  			info->export_unused_gpl_sec = i;
>  		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
>  			info->export_gpl_future_sec = i;
> +		else if (strcmp(secname, "__markers_strings") == 0)
> +			info->markers_strings_sec = i;
>  
>  		if (sechdrs[i].sh_type != SHT_SYMTAB)
>  			continue;
> @@ -1249,6 +1253,83 @@ static int exit_section_ref_ok(const char *name)
>  	return 0;
>  }
>  
> +static void get_markers(struct elf_info *info, struct module *mod)
> +{
> +	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
> +	const char *strings = (const char *) info->hdr + sh->sh_offset;
> +	const Elf_Sym *sym, *first_sym, *last_sym;
> +	const char *name;
> +	size_t n;
> +
> +	if (!info->markers_strings_sec)
> +		return;
> +
> +	/*
> +	 * First count the strings.  They come in pairs of name, format.
> +	 * We look for all the symbols defined in the __markers_strings
> +	 * section.  They are named __mstrtab_name_* and __mstrtab_format_*
> +	 * in matching pairs.  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->markers_strings_sec) {
> +			if (first_sym == NULL)
> +				first_sym = sym;
> +			last_sym = sym;
> +			++n;
> +			name = info->strtab + sym->st_name;
> +			if (n % 2 == 0 ?
> +			    !strncmp(name, "__mstrtab_name_",
> +				     sizeof "__mstrtab_name_" - 1) :
> +			    !strncmp(name, "__mstrtab_format_",
> +				     sizeof "__mstrtab_format_" - 1)) {
> +				warn("%s.ko has unexpected symbol \"%s\"\n",
> +				     mod->name, name);
> +				first_sym = NULL;
> +			}
> +		}
> +
> +	if (n % 2 != 0 || first_sym == NULL) {
> +		warn("%s.ko has bad __markers_strings, ignoring it\n",
> +		     mod->name);
> +		return;
> +	}
> +
> +	if (n == 0)
> +		return;
> +
> +	/*
> +	 * Now collect each pair into a formatted line for the output.
> +	 * Lines look like:
> +	 *	marker_name	vmlinux	marker %s format %d
> +	 * The format string after the second \t can use whitespace.
> +	 */
> +	n /= 2;
> +	mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
> +	mod->nmarkers = n;
> +
> +	name = NULL;
> +	n = 0;
> +	for (sym = first_sym; sym <= last_sym; sym++)
> +		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
> +		    sym->st_shndx == info->markers_strings_sec) {
> +			const char *str = strings + sym->st_value;
> +			if (name == NULL)
> +				name = str;
> +			else {
> +				char *line = NULL;
> +				asprintf(&line, "%s\t%s\t%s\n",
> +					 name, mod->name, str);
> +				NOFAIL(line);
> +				mod->markers[n++] = line;
> +				name = NULL;
> +			}
> +		}
> +}
> +
>  static void read_symbols(char *modname)
>  {
>  	const char *symname;
> @@ -1301,6 +1382,8 @@ static void read_symbols(char *modname)
>  		get_src_version(modname, mod->srcversion,
>  				sizeof(mod->srcversion)-1);
>  
> +	get_markers(&info, mod);
> +
>  	parse_elf_finish(&info);
>  
>  	/* Our trick to get versioning for struct_module - it's
> @@ -1649,6 +1732,91 @@ static void write_dump(const char *fname)
>  	write_if_changed(&buf, fname);
>  }
>  
> +static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
> +						     sizeof mod->markers[0])));
> +	mod->markers[mod->nmarkers++] = line;
> +}
> +
> +static void read_markers(const char *fname)
> +{
> +	unsigned long size, pos = 0;
> +	void *file = grab_file(fname, &size);
> +	char *line;
> +
> +        if (!file)
> +		/* No old markers, silently ignore */
> +		return;
> +
> +	while ((line = get_next_line(&pos, file, size))) {
> +		char *marker, *modname, *fmt;
> +		struct module *mod;
> +
> +		marker = line;
> +		if (!(modname = strchr(marker, '\t')))
> +			goto fail;
> +		*modname++ = '\0';
> +		if (!(fmt = strchr(modname, '\t')))
> +			goto fail;
> +		*fmt++ = '\0';
> +		if (*marker == '\0' || *modname == '\0')
> +			goto fail;
> +
> +		if (!(mod = find_module(modname))) {
> +			if (is_vmlinux(modname)) {
> +				have_vmlinux = 1;
> +			}
> +			mod = new_module(NOFAIL(strdup(modname)));
> +			mod->skip = 1;
> +		}
> +
> +		add_marker(mod, marker, fmt);
> +	}
> +	return;
> +fail:
> +	fatal("parse error in markers list file\n");
> +}
> +
> +static int compare_strings(const void *a, const void *b)
> +{
> +	return strcmp(*(const char **) a, *(const char **) b);
> +}
> +
> +static void write_markers(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->markers != NULL) {
> +			/*
> +			 * Sort the strings so we can skip duplicates when
> +			 * we write them out.
> +			 */
> +			qsort(mod->markers, mod->nmarkers,
> +			      sizeof mod->markers[0], &compare_strings);
> +			for (i = 0; i < mod->nmarkers; ++i) {
> +				char *line = mod->markers[i];
> +				buf_write(&buf, line, strlen(line));
> +				while (i + 1 < mod->nmarkers &&
> +				       !strcmp(mod->markers[i],
> +					       mod->markers[i + 1]))
> +					free(mod->markers[i++]);
> +				free(mod->markers[i]);
> +			}
> +			free(mod->markers);
> +			mod->markers = NULL;
> +		}
> +
> +	write_if_changed(&buf, fname);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	struct module *mod;
> @@ -1656,10 +1824,12 @@ int main(int argc, char **argv)
>  	char fname[SZ];
>  	char *kernel_read = NULL, *module_read = NULL;
>  	char *dump_write = NULL;
> +	char *markers_read = NULL;
> +	char *markers_write = NULL;
>  	int opt;
>  	int err;
>  
> -	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
> +	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
>  		switch(opt) {
>  			case 'i':
>  				kernel_read = optarg;
> @@ -1683,6 +1853,12 @@ int main(int argc, char **argv)
>  			case 'w':
>  				warn_unresolved = 1;
>  				break;
> +			case 'M':
> +				markers_write = optarg;
> +				break;
> +			case 'K':
> +				markers_read = optarg;
> +				break;
>  			default:
>  				exit(1);
>  		}
> @@ -1724,5 +1900,11 @@ int main(int argc, char **argv)
>  	if (dump_write)
>  		write_dump(dump_write);
>  
> +	if (markers_read)
> +		read_markers(markers_read);
> +
> +	if (markers_write)
> +		write_markers(markers_write);
> +
>  	return err;
>  }
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index 0ffed17..175301a 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -110,6 +110,8 @@ struct module {
>  	int has_init;
>  	int has_cleanup;
>  	struct buffer dev_table_buf;
> +	char **markers;
> +	size_t nmarkers;
>  	char	     srcversion[25];
>  };
>  
> @@ -124,6 +126,7 @@ struct elf_info {
>  	Elf_Section  export_gpl_sec;
>  	Elf_Section  export_unused_gpl_sec;
>  	Elf_Section  export_gpl_future_sec;
> +	Elf_Section  markers_strings_sec;
>  	const char   *strtab;
>  	char	     *modinfo;
>  	unsigned int modinfo_len;
> 
> 
> 
> 
> 

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-08 19:36                                 ` Mathieu Desnoyers
@ 2007-11-08 19:45                                   ` David Smith
  2007-11-09 16:36                                   ` David Smith
  1 sibling, 0 replies; 18+ messages in thread
From: David Smith @ 2007-11-08 19:45 UTC (permalink / raw)
  To: Mathieu Desnoyers; +Cc: Roland McGrath, Andrew Morton, linux-kernel, systemtap

Mathieu Desnoyers wrote:
> * David Smith (dsmith@redhat.com) wrote:
>> Mathieu Desnoyers wrote:
>>> * Roland McGrath (roland@redhat.com) wrote:
>>>>> If we want to do it safely, I think we should iterate from
>>>>> __start___markers to __stop___markers symbols of vmlinux and get the
>>>>> pointers to the name/format string pairs.
>>>>>
>>>>> The same can then be done with modules using the __markers section.
>>>>>
>>>>> Or maybe is there some reason not to do that ?
>>>> It's just rather a pain in the ass, a whole lot more fiddly work.
>>>> cf "somewhat crude" and "foreseeable future" in my patch's log entry.
>>>> Knock yourself out if you're looking for more tedious hacking to do in
>>>> modpost.c, but I say fix it when it breaks.
>>>>
>>> Hmmmm, I have rarely seen code go into mainline without addressing valid
>>> technical criticism first. Please fix.
>>>
>>> I'll look into it if I find the time.
>>>
>>> Mathieu
>> Mathieu,
>>
>> Here's an updated patch, written by Roland (that I tested for him), that
>> looks for all marker symbols in the __markers_strings section.  It doesn't
>> get the pointers from the __markers section because that is very difficult
>> to do in modpost (having to handle the architecture-dependent relocations
>> applied to those pointers).
>>
> 
> Hrm, what would happen if a gcc optimization eventually decides to mix
> the memory layout of the strings ? Is there something that specifies
> that they won't ?

I don't believe there is anything in gcc that specifies that the strings
won't get mixed around.  But, I believe this code is good for the
foreseeable future.  We could fix this code if the future breakage does
happen.

-- 
David Smith
dsmith@redhat.com
Red Hat
http://www.redhat.com
256.217.0141 (direct)
256.837.0057 (fax)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-08 19:36                                 ` Mathieu Desnoyers
  2007-11-08 19:45                                   ` David Smith
@ 2007-11-09 16:36                                   ` David Smith
  2007-11-11 23:29                                     ` Mathieu Desnoyers
  1 sibling, 1 reply; 18+ messages in thread
From: David Smith @ 2007-11-09 16:36 UTC (permalink / raw)
  To: Mathieu Desnoyers; +Cc: Roland McGrath, Andrew Morton, linux-kernel, systemtap

Mathieu Desnoyers wrote:
> Hrm, what would happen if a gcc optimization eventually decides to mix
> the memory layout of the strings ? Is there something that specifies
> that they won't ?

Here's another patch that Roland wrote and I tested that
attempts to solve the potential problem of string ordering
by merging the name and format strings.

---
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.

Signed-off-by: Roland McGrath <roland@redhat.com>
---
 include/linux/marker.h   |    9 +--
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  163 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 4 files changed, 179 insertions(+), 7 deletions(-)

diff --git a/include/linux/marker.h b/include/linux/marker.h
index 5f36cf9..b978bbe 100644
--- a/include/linux/marker.h
+++ b/include/linux/marker.h
@@ -51,15 +51,12 @@ struct marker {
  */
 #define __trace_mark(generic, name, call_data, format, args...)		\
 	do {								\
-		static const char __mstrtab_name_##name[]		\
+		static const char __mstrtab_##name[]			\
 		__attribute__((section("__markers_strings")))		\
-		= #name;						\
-		static const char __mstrtab_format_##name[]		\
-		__attribute__((section("__markers_strings")))		\
-		= format;						\
+ 		= #name "\0" format;					\
 		static struct marker __mark_##name			\
 		__attribute__((section("__markers"), aligned(8))) =	\
-		{ __mstrtab_name_##name, __mstrtab_format_##name,	\
+		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
 		0, __mark_empty_function, NULL };			\
 		__mark_check_format(format, ## args);			\
 		if (!generic) {						\
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index d988f5d..6321870 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 93ac52a..53887e8 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,62 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_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->markers_strings_sec)
+		return;
+
+	/*
+	 * First count the strings.  We look for all the symbols defined
+	 * in the __markers_strings section named __mstrtab_*.  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->markers_strings_sec &&
+		    !strncmp(info->strtab + sym->st_name,
+			     "__mstrtab_", sizeof "__mstrtab_" - 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->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
+	mod->nmarkers = n;
+
+	n = 0;
+	for (sym = first_sym; sym <= last_sym; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec &&
+		    !strncmp(info->strtab + sym->st_name,
+			     "__mstrtab_", sizeof "__mstrtab_" - 1)) {
+			const char *name = strings + sym->st_value;
+			const char *fmt = strchr(name, '\0') + 1;
+			char *line = NULL;
+			asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+			NOFAIL(line);
+			mod->markers[n++] = line;
+		}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1361,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1711,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(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->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1803,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1832,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1879,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 0ffed17..175301a 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] markers: modpost
  2007-11-09 16:36                                   ` David Smith
@ 2007-11-11 23:29                                     ` Mathieu Desnoyers
  0 siblings, 0 replies; 18+ messages in thread
From: Mathieu Desnoyers @ 2007-11-11 23:29 UTC (permalink / raw)
  To: David Smith; +Cc: Roland McGrath, Andrew Morton, linux-kernel, systemtap

* David Smith (dsmith@redhat.com) wrote:
> Mathieu Desnoyers wrote:
> > Hrm, what would happen if a gcc optimization eventually decides to mix
> > the memory layout of the strings ? Is there something that specifies
> > that they won't ?
> 
> Here's another patch that Roland wrote and I tested that
> attempts to solve the potential problem of string ordering
> by merging the name and format strings.
> 

Yup, it looks good. I'll give it a try.

Thanks!

Mathieu

> ---
> 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.
> 
> Signed-off-by: Roland McGrath <roland@redhat.com>
> ---
>  include/linux/marker.h   |    9 +--
>  scripts/Makefile.modpost |   11 +++
>  scripts/mod/modpost.c    |  163 +++++++++++++++++++++++++++++++++++++++++++++-
>  scripts/mod/modpost.h    |    3 +
>  4 files changed, 179 insertions(+), 7 deletions(-)
> 
> diff --git a/include/linux/marker.h b/include/linux/marker.h
> index 5f36cf9..b978bbe 100644
> --- a/include/linux/marker.h
> +++ b/include/linux/marker.h
> @@ -51,15 +51,12 @@ struct marker {
>   */
>  #define __trace_mark(generic, name, call_data, format, args...)		\
>  	do {								\
> -		static const char __mstrtab_name_##name[]		\
> +		static const char __mstrtab_##name[]			\
>  		__attribute__((section("__markers_strings")))		\
> -		= #name;						\
> -		static const char __mstrtab_format_##name[]		\
> -		__attribute__((section("__markers_strings")))		\
> -		= format;						\
> + 		= #name "\0" format;					\
>  		static struct marker __mark_##name			\
>  		__attribute__((section("__markers"), aligned(8))) =	\
> -		{ __mstrtab_name_##name, __mstrtab_format_##name,	\
> +		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
>  		0, __mark_empty_function, NULL };			\
>  		__mark_check_format(format, ## args);			\
>  		if (!generic) {						\
> diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
> index d988f5d..6321870 100644
> --- a/scripts/Makefile.modpost
> +++ b/scripts/Makefile.modpost
> @@ -13,6 +13,7 @@
>  # 2) modpost is then used to
>  # 3)  create one <module>.mod.c file pr. module
>  # 4)  create one Module.symvers file with CRC for all exported symbols
> +# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
>  # 5) compile all <module>.mod.c files
>  # 6) final link of the module to a <module.ko> file
>  
> @@ -45,6 +46,10 @@ include scripts/Makefile.lib
>  
>  kernelsymfile := $(objtree)/Module.symvers
>  modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
> +kernelmarkersfile := $(objtree)/Module.markers
> +modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
> +
> +markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
>  
>  # Step 1), find all modules listed in $(MODVERDIR)/
>  __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
> @@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
>   $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
>   $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
>   $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
> + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
> + $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
>   $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
>  
>  quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
> @@ -81,6 +88,10 @@ vmlinux.o: FORCE
>  $(symverfile):         __modpost ;
>  $(modules:.ko=.mod.c): __modpost ;
>  
> +ifdef CONFIG_MARKERS
> +$(markersfile):	       __modpost ;
> +endif
> +
>  
>  # Step 5), compile all *.mod.c files
>  
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index 93ac52a..53887e8 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -11,6 +11,8 @@
>   * Usage: modpost vmlinux module1.o module2.o ...
>   */
>  
> +#define _GNU_SOURCE
> +#include <stdio.h>
>  #include <ctype.h>
>  #include "modpost.h"
>  #include "../../include/linux/license.h"
> @@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
>  			info->export_unused_gpl_sec = i;
>  		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
>  			info->export_gpl_future_sec = i;
> +		else if (strcmp(secname, "__markers_strings") == 0)
> +			info->markers_strings_sec = i;
>  
>  		if (sechdrs[i].sh_type != SHT_SYMTAB)
>  			continue;
> @@ -1249,6 +1253,62 @@ static int exit_section_ref_ok(const char *name)
>  	return 0;
>  }
>  
> +static void get_markers(struct elf_info *info, struct module *mod)
> +{
> +	const Elf_Shdr *sh = &info->sechdrs[info->markers_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->markers_strings_sec)
> +		return;
> +
> +	/*
> +	 * First count the strings.  We look for all the symbols defined
> +	 * in the __markers_strings section named __mstrtab_*.  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->markers_strings_sec &&
> +		    !strncmp(info->strtab + sym->st_name,
> +			     "__mstrtab_", sizeof "__mstrtab_" - 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->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
> +	mod->nmarkers = n;
> +
> +	n = 0;
> +	for (sym = first_sym; sym <= last_sym; sym++)
> +		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
> +		    sym->st_shndx == info->markers_strings_sec &&
> +		    !strncmp(info->strtab + sym->st_name,
> +			     "__mstrtab_", sizeof "__mstrtab_" - 1)) {
> +			const char *name = strings + sym->st_value;
> +			const char *fmt = strchr(name, '\0') + 1;
> +			char *line = NULL;
> +			asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
> +			NOFAIL(line);
> +			mod->markers[n++] = line;
> +		}
> +}
> +
>  static void read_symbols(char *modname)
>  {
>  	const char *symname;
> @@ -1301,6 +1361,8 @@ static void read_symbols(char *modname)
>  		get_src_version(modname, mod->srcversion,
>  				sizeof(mod->srcversion)-1);
>  
> +	get_markers(&info, mod);
> +
>  	parse_elf_finish(&info);
>  
>  	/* Our trick to get versioning for struct_module - it's
> @@ -1649,6 +1711,91 @@ static void write_dump(const char *fname)
>  	write_if_changed(&buf, fname);
>  }
>  
> +static void add_marker(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->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
> +						     sizeof mod->markers[0])));
> +	mod->markers[mod->nmarkers++] = line;
> +}
> +
> +static void read_markers(const char *fname)
> +{
> +	unsigned long size, pos = 0;
> +	void *file = grab_file(fname, &size);
> +	char *line;
> +
> +        if (!file)
> +		/* No old markers, silently ignore */
> +		return;
> +
> +	while ((line = get_next_line(&pos, file, size))) {
> +		char *marker, *modname, *fmt;
> +		struct module *mod;
> +
> +		marker = line;
> +		if (!(modname = strchr(marker, '\t')))
> +			goto fail;
> +		*modname++ = '\0';
> +		if (!(fmt = strchr(modname, '\t')))
> +			goto fail;
> +		*fmt++ = '\0';
> +		if (*marker == '\0' || *modname == '\0')
> +			goto fail;
> +
> +		if (!(mod = find_module(modname))) {
> +			if (is_vmlinux(modname)) {
> +				have_vmlinux = 1;
> +			}
> +			mod = new_module(NOFAIL(strdup(modname)));
> +			mod->skip = 1;
> +		}
> +
> +		add_marker(mod, marker, fmt);
> +	}
> +	return;
> +fail:
> +	fatal("parse error in markers list file\n");
> +}
> +
> +static int compare_strings(const void *a, const void *b)
> +{
> +	return strcmp(*(const char **) a, *(const char **) b);
> +}
> +
> +static void write_markers(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->markers != NULL) {
> +			/*
> +			 * Sort the strings so we can skip duplicates when
> +			 * we write them out.
> +			 */
> +			qsort(mod->markers, mod->nmarkers,
> +			      sizeof mod->markers[0], &compare_strings);
> +			for (i = 0; i < mod->nmarkers; ++i) {
> +				char *line = mod->markers[i];
> +				buf_write(&buf, line, strlen(line));
> +				while (i + 1 < mod->nmarkers &&
> +				       !strcmp(mod->markers[i],
> +					       mod->markers[i + 1]))
> +					free(mod->markers[i++]);
> +				free(mod->markers[i]);
> +			}
> +			free(mod->markers);
> +			mod->markers = NULL;
> +		}
> +
> +	write_if_changed(&buf, fname);
> +}
> +
>  int main(int argc, char **argv)
>  {
>  	struct module *mod;
> @@ -1656,10 +1803,12 @@ int main(int argc, char **argv)
>  	char fname[SZ];
>  	char *kernel_read = NULL, *module_read = NULL;
>  	char *dump_write = NULL;
> +	char *markers_read = NULL;
> +	char *markers_write = NULL;
>  	int opt;
>  	int err;
>  
> -	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
> +	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
>  		switch(opt) {
>  			case 'i':
>  				kernel_read = optarg;
> @@ -1683,6 +1832,12 @@ int main(int argc, char **argv)
>  			case 'w':
>  				warn_unresolved = 1;
>  				break;
> +			case 'M':
> +				markers_write = optarg;
> +				break;
> +			case 'K':
> +				markers_read = optarg;
> +				break;
>  			default:
>  				exit(1);
>  		}
> @@ -1724,5 +1879,11 @@ int main(int argc, char **argv)
>  	if (dump_write)
>  		write_dump(dump_write);
>  
> +	if (markers_read)
> +		read_markers(markers_read);
> +
> +	if (markers_write)
> +		write_markers(markers_write);
> +
>  	return err;
>  }
> diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
> index 0ffed17..175301a 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -110,6 +110,8 @@ struct module {
>  	int has_init;
>  	int has_cleanup;
>  	struct buffer dev_table_buf;
> +	char **markers;
> +	size_t nmarkers;
>  	char	     srcversion[25];
>  };
>  
> @@ -124,6 +126,7 @@ struct elf_info {
>  	Elf_Section  export_gpl_sec;
>  	Elf_Section  export_unused_gpl_sec;
>  	Elf_Section  export_gpl_future_sec;
> +	Elf_Section  markers_strings_sec;
>  	const char   *strtab;
>  	char	     *modinfo;
>  	unsigned int modinfo_len;
> 
> 

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2007-11-11 23:29 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20070918211324.161373216@polymtl.ca>
     [not found] ` <20070919113737.GA18177@Krystal>
     [not found]   ` <y0mtzpqvk1l.fsf@ton.toronto.redhat.com>
     [not found]     ` <200709192132.00873.vda.linux@googlemail.com>
     [not found]       ` <20070921125819.GA13129@Krystal>
     [not found]         ` <20070921130752.GB9431@infradead.org>
2007-09-21 16:11           ` [patch 1/4] Linux Kernel Markers - Architecture Independent Code Frank Ch. Eigler
2007-09-21 18:58             ` Christoph Hellwig
2007-09-21 20:00               ` Frank Ch. Eigler
     [not found]         ` <20070921133006.GF8964@redhat.com>
     [not found]           ` <20070921133820.GD13129@Krystal>
2007-10-15 20:11             ` Frank Ch. Eigler
2007-10-15 23:12               ` Mathieu Desnoyers
2007-10-15 23:50                 ` Roland McGrath
2007-10-25 19:17                   ` Mathieu Desnoyers
2007-10-26 14:30                     ` Frank Ch. Eigler
2007-11-01  1:07                       ` [PATCH] markers: modpost Roland McGrath
2007-11-01  1:12                         ` Roland McGrath
2007-11-01  2:46                         ` Mathieu Desnoyers
2007-11-01  9:38                           ` Roland McGrath
2007-11-01 11:24                             ` Mathieu Desnoyers
2007-11-08 19:31                               ` David Smith
2007-11-08 19:36                                 ` Mathieu Desnoyers
2007-11-08 19:45                                   ` David Smith
2007-11-09 16:36                                   ` David Smith
2007-11-11 23:29                                     ` Mathieu Desnoyers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).