On 26 May 2015 at 21:07, Michael Hudson-Doyle
<michael.hud...@canonical.com> wrote:
>> It would be nice if the unit test would cover versions longer than
>> the normal space padding, and the visibility attributes.
>
> I'll try to do that tomorrow.

So it took a week longer than I hoped, but I'm attaching a patch with,
I think, pretty comprehensive tests.  The implementation is the same
as my previous patch (and the tests fail without the new
implementation). I'm not much of a perl programmer, so my perl is
probably as unidiomatic as it gets, but if you can make my test cases
pass I don't really care if you change everything else completely :-)

Cheers,
mwh
From e5a3fcb914a03ea0e448371ea3a271e33dc41c34 Mon Sep 17 00:00:00 2001
From: Michael Hudson-Doyle <michael.hud...@canonical.com>
Date: Thu, 4 Jun 2015 13:13:23 +1200
Subject: [PATCH] Support for spaces in symbols in Dpkg::Shlibs::Objdump.

---
 scripts/Dpkg/Shlibs/Objdump.pm          |  63 ++++++++++------
 scripts/Makefile.am                     |  18 ++++-
 scripts/t/Dpkg_Shlibs.t                 |  35 ++++++++-
 scripts/t/Dpkg_Shlibs/makespacesymc.pl  |  32 ++++++++
 scripts/t/Dpkg_Shlibs/objdump.spacesyms | 127 ++++++++++++++++++++++++++++++++
 scripts/t/Dpkg_Shlibs/spacesym.pl       |  19 +++++
 scripts/t/Dpkg_Shlibs/spacesyms.map     |   7 ++
 7 files changed, 276 insertions(+), 25 deletions(-)
 create mode 100755 scripts/t/Dpkg_Shlibs/makespacesymc.pl
 create mode 100644 scripts/t/Dpkg_Shlibs/objdump.spacesyms
 create mode 100755 scripts/t/Dpkg_Shlibs/spacesym.pl
 create mode 100644 scripts/t/Dpkg_Shlibs/spacesyms.map

diff --git a/scripts/Dpkg/Shlibs/Objdump.pm b/scripts/Dpkg/Shlibs/Objdump.pm
index c19c3fb..dd53a24 100644
--- a/scripts/Dpkg/Shlibs/Objdump.pm
+++ b/scripts/Dpkg/Shlibs/Objdump.pm
@@ -221,7 +221,7 @@ sub parse_objdump_output {
 	if ($section eq 'dynsym') {
 	    $self->parse_dynamic_symbol($_);
 	} elsif ($section eq 'dynreloc') {
-	    if (/^\S+\s+(\S+)\s+(\S+)\s*$/) {
+	    if (/^\S+\s+(\S+)\s+(.+)$/) {
 		$self->{dynrelocs}{$2} = $1;
 	    } else {
 		warning(g_("couldn't parse dynamic relocation record: %s"), $_);
@@ -299,21 +299,36 @@ sub parse_objdump_output {
 sub parse_dynamic_symbol {
     my ($self, $line) = @_;
     my $vis_re = '(\.protected|\.hidden|\.internal|0x\S+)';
-    if ($line =~ /^[0-9a-f]+ (.{7})\s+(\S+)\s+[0-9a-f]+(?:\s+(\S+))?(?:\s+$vis_re)?\s+(\S+)/) {
-
-	my ($flags, $sect, $ver, $vis, $name) = ($1, $2, $3, $4, $5);
-
-	# Special case if version is missing but extra visibility
-	# attribute replaces it in the match
-	if (defined($ver) and $ver =~ /^$vis_re$/) {
-	    $vis = $ver;
-	    $ver = '';
-	}
+    if ($line =~ /^[0-9a-f]+ (.{7})\s+(\S+)\s+[0-9a-f]+(.+)$/) {
+
+	my ($flags, $sect, $rest) = ($1, $2, $3);
+        my ($ver, $vis, $name);
+
+        if ($rest =~ /^ {11}/) {
+            # No version
+            $rest =~ s/^\s+|\s+$//g;
+            if ($rest =~ /^$vis_re\s+(\S.+)/) {
+                $vis = $1;
+                $name = $2;
+            } else {
+                $name = $rest;
+            }
+        } elsif ($rest =~ /(?:\s+(\S+))?(?:\s+$vis_re)?\s+(.+)/) {
+            ($ver, $vis, $name) = ($1, $2, $3);
+            # Special case if version is missing but extra visibility
+            # attribute replaces it in the match
+            if (defined($ver) and $ver =~ /^$vis_re$/) {
+                $vis = $ver;
+                $ver = '';
+            }
+        }
 
-	# Cleanup visibility field
-	$vis =~ s/^\.// if defined($vis);
+        if (defined($name)) {
+            # Cleanup visibility field
+            $vis =~ s/^\.// if defined($vis);
 
-	my $symbol = {
+            # Register symbol
+            my $symbol = {
 		name => $name,
 		version => $ver // '',
 		section => $sect,
@@ -328,16 +343,18 @@ sub parse_dynamic_symbol {
 		defined => $sect ne '*UND*'
 	    };
 
-	# Handle hidden symbols
-	if (defined($ver) and $ver =~ /^\((.*)\)$/) {
-	    $ver = $1;
-	    $symbol->{version} = $1;
-	    $symbol->{hidden} = 1;
-	}
+            # Handle hidden symbols
+            if (defined($ver) and $ver =~ /^\((.*)\)$/) {
+                $ver = $1;
+                $symbol->{version} = $1;
+                $symbol->{hidden} = 1;
+            }
+            $self->add_dynamic_symbol($symbol);
+            return;
+        }
+    }
 
-	# Register symbol
-	$self->add_dynamic_symbol($symbol);
-    } elsif ($line =~ /^[0-9a-f]+ (.{7})\s+(\S+)\s+[0-9a-f]+/) {
+    if ($line =~ /^[0-9a-f]+ (.{7})\s+(\S+)\s+[0-9a-f]+/) {
 	# Same start but no version and no symbol ... just ignore
     } elsif ($line =~ /^REG_G\d+\s+/) {
 	# Ignore some s390-specific output like
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index be164b7..ad3e0b9 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -313,7 +313,8 @@ test_data_objects = \
 	t/Dpkg_Shlibs/libobjdump.basictags-amd64.so \
 	t/Dpkg_Shlibs/libobjdump.basictags-i386.so \
 	t/Dpkg_Shlibs/libobjdump.basictags-mips.so \
-	t/Dpkg_Shlibs/libobjdump.patterns.so
+	t/Dpkg_Shlibs/libobjdump.patterns.so \
+	t/Dpkg_Shlibs/libobjdump.spacesyms.so
 
 $(srcdir)/t/Dpkg_Shlibs/libobjdump.basictags-amd64.so: $(srcdir)/t/Dpkg_Shlibs/basictags.c
 	$(CC) $(CFLAGS) -shared -fPIC -Wl,-soname -Wl,libbasictags.so.1 $< \
@@ -332,6 +333,19 @@ $(srcdir)/t/Dpkg_Shlibs/libobjdump.patterns.so: $(srcdir)/t/Dpkg_Shlibs/patterns
 	    -Wl,--version-script=$(srcdir)/t/Dpkg_Shlibs/patterns.map $< \
 	    -o $@
 
+spacesyms.c: $(srcdir)/t/Dpkg_Shlibs/makespacesymc.pl
+	$(srcdir)/t/Dpkg_Shlibs/makespacesymc.pl > spacesyms.c
+
+spacesyms.o: spacesyms.c
+	$(CC) $(CFLAGS) -c -fPIC -o $@.tmp $<
+	$(srcdir)/t/Dpkg_Shlibs/spacesym.pl $@.tmp $@
+	rm $@.tmp
+
+$(srcdir)/t/Dpkg_Shlibs/libobjdump.spacesyms.so: spacesyms.o $(srcdir)/t/Dpkg_Shlibs/spacesyms.map
+	$(CC) -shared -Wl,-soname -Wl,libspacesyms.so.1 \
+	    -Wl,--version-script=$(srcdir)/t/Dpkg_Shlibs/spacesyms.map $< \
+	    -o $@
+
 .PHONY: refresh-test-data
 
 OBJDUMP = objdump -w -f -p -T -R
@@ -345,6 +359,8 @@ refresh-test-data: $(test_data_objects)
 	  >$(srcdir)/t/Dpkg_Shlibs/objdump.basictags-mips
 	$(OBJDUMP) $(srcdir)/t/Dpkg_Shlibs/libobjdump.patterns.so \
 	  >$(srcdir)/t/Dpkg_Shlibs/objdump.patterns
+	$(OBJDUMP) $(srcdir)/t/Dpkg_Shlibs/libobjdump.spacesyms.so \
+	  >$(srcdir)/t/Dpkg_Shlibs/objdump.spacesyms
 	$(OBJDUMP) `which ls` >$(srcdir)/t/Dpkg_Shlibs/objdump.ls
 
 include $(top_srcdir)/check.am
diff --git a/scripts/t/Dpkg_Shlibs.t b/scripts/t/Dpkg_Shlibs.t
index 4bcd848..813b49a 100644
--- a/scripts/t/Dpkg_Shlibs.t
+++ b/scripts/t/Dpkg_Shlibs.t
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 124;
+use Test::More tests => 148;
 
 use Cwd;
 use IO::String;
@@ -351,6 +351,39 @@ is_deeply( $sym, { name => 'IA__g_free', version => '',
 		   hidden => '', defined => 1 },
 		   'symbol with visibility without version' );
 
+# Check parsing of objdump output when symbol names contain spaces
+$obj = Dpkg::Shlibs::Objdump::Object->new;
+
+open $objdump, '<', "$datadir/objdump.spacesyms"
+  or die "$datadir/objdump.spacesyms: $!";
+$obj->parse_objdump_output($objdump);
+close $objdump;
+
+sub check_spacesym {
+    my ($name, $visibility, $version) = @_;
+    $sym = $obj->get_symbol("$name@" . "$version");
+    is_deeply( $sym, { name => $name, version => $version,
+                       soname => 'libspacesyms.so.1', objid => 'libspacesyms.so.1',
+                       section => '.text', dynamic => 1,
+                       debug => '', type => 'F', weak => '',
+                       local => '', global => 1, visibility => $visibility,
+                       hidden => '', defined => 1 }, $name );
+    ok(defined($obj->{dynrelocs}{$name}), "dynreloc found for $name");
+}
+
+check_spacesym('symdefaultvernospacedefault', '', 'Base');
+check_spacesym('symdefaultvernospaceprotected', 'protected', 'Base');
+check_spacesym('symlongvernospacedefault', '', 'VERY_LONG_VERSION_1');
+check_spacesym('symlongvernospaceprotected', 'protected', 'VERY_LONG_VERSION_1');
+check_spacesym('symshortvernospacedefault', '', 'V1');
+check_spacesym('symshortvernospaceprotected', 'protected', 'V1');
+check_spacesym('symdefaultverSPA CEdefault', '', 'Base');
+check_spacesym('symdefaultverSPA CEprotected', 'protected', 'Base');
+check_spacesym('symlongverSPA CEdefault', '', 'VERY_LONG_VERSION_1');
+check_spacesym('symlongverSPA CEprotected', 'protected', 'VERY_LONG_VERSION_1');
+check_spacesym('symshortverSPA CEdefault', '', 'V1');
+check_spacesym('symshortverSPA CEprotected', 'protected', 'V1');
+
 ####### Test symbol tagging support  ######
 
 # Parsing/dumping
diff --git a/scripts/t/Dpkg_Shlibs/makespacesymc.pl b/scripts/t/Dpkg_Shlibs/makespacesymc.pl
new file mode 100755
index 0000000..cea94d2
--- /dev/null
+++ b/scripts/t/Dpkg_Shlibs/makespacesymc.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/perl -w
+#
+# makespacesymc.pl outputs a C file that contains symbols matching
+# sym{defaultver,longver,shortver}{nospace,SPACE}{default,hidden,protected,internal}
+# with symbol visibility matching the final element and at least one
+# relocation against each symbol. When used together with spacesym.pl
+# and spacesyms.map, makes a shared object that contains symbols that
+# covers all cases of:
+# 1) has a short, long or Base version
+# 2) has or does not have a space in the symbol name
+# 3) default, hidden, protected or internal visibility.
+
+use strict;
+
+my @symbols;
+
+foreach my $version ("defaultver", "longver", "shortver") {
+    foreach my $space ("nospace", "SPACE") {
+        foreach my $visibility ("default", "hidden", "protected", "internal") {
+            my $symbol = "sym$version$space$visibility";
+            push @symbols, $symbol;
+            print "void $symbol(void) __attribute__((visibility(\"$visibility\")));\n";
+            print "void $symbol(void) {}\n";
+        }
+    }
+}
+
+print "void (*funcs[])(void) = {\n";
+foreach my $symbol (@symbols) {
+    print "$symbol,\n";
+}
+print "};\n";
diff --git a/scripts/t/Dpkg_Shlibs/objdump.spacesyms b/scripts/t/Dpkg_Shlibs/objdump.spacesyms
new file mode 100644
index 0000000..a32600d
--- /dev/null
+++ b/scripts/t/Dpkg_Shlibs/objdump.spacesyms
@@ -0,0 +1,127 @@
+
+../../scripts/t/Dpkg_Shlibs/libobjdump.spacesyms.so:     file format elf64-x86-64
+architecture: i386:x86-64, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x0000000000000b80
+
+Program Header:
+    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**21
+         filesz 0x000000000000115c memsz 0x000000000000115c flags r-x
+    LOAD off    0x0000000000001dd0 vaddr 0x0000000000201dd0 paddr 0x0000000000201dd0 align 2**21
+         filesz 0x0000000000000370 memsz 0x0000000000000378 flags rw-
+ DYNAMIC off    0x0000000000001de8 vaddr 0x0000000000201de8 paddr 0x0000000000201de8 align 2**3
+         filesz 0x00000000000001f0 memsz 0x00000000000001f0 flags rw-
+    NOTE off    0x00000000000001c8 vaddr 0x00000000000001c8 paddr 0x00000000000001c8 align 2**2
+         filesz 0x0000000000000024 memsz 0x0000000000000024 flags r--
+EH_FRAME off    0x0000000000000e00 vaddr 0x0000000000000e00 paddr 0x0000000000000e00 align 2**2
+         filesz 0x00000000000000d4 memsz 0x00000000000000d4 flags r--
+   STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
+         filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-
+   RELRO off    0x0000000000001dd0 vaddr 0x0000000000201dd0 paddr 0x0000000000201dd0 align 2**0
+         filesz 0x0000000000000230 memsz 0x0000000000000230 flags r--
+
+Dynamic Section:
+  NEEDED               libc.so.6
+  SONAME               libspacesyms.so.1
+  INIT                 0x0000000000000b30
+  FINI                 0x0000000000000df4
+  INIT_ARRAY           0x0000000000201dd0
+  INIT_ARRAYSZ         0x0000000000000008
+  FINI_ARRAY           0x0000000000201dd8
+  FINI_ARRAYSZ         0x0000000000000008
+  GNU_HASH             0x00000000000001f0
+  STRTAB               0x0000000000000530
+  SYMTAB               0x00000000000002a8
+  STRSZ                0x0000000000000214
+  SYMENT               0x0000000000000018
+  PLTGOT               0x0000000000202000
+  PLTRELSZ             0x0000000000000030
+  PLTREL               0x0000000000000007
+  JMPREL               0x0000000000000b00
+  RELA                 0x0000000000000800
+  RELASZ               0x0000000000000300
+  RELAENT              0x0000000000000018
+  VERDEF               0x0000000000000780
+  VERDEFNUM            0x0000000000000003
+  VERNEED              0x00000000000007e0
+  VERNEEDNUM           0x0000000000000001
+  VERSYM               0x0000000000000744
+  RELACOUNT            0x000000000000000f
+
+Version definitions:
+1 0x01 0x026eb371 libspacesyms.so.1
+2 0x00 0x00000591 V1
+3 0x00 0x0df29ee1 VERY_LONG_VERSION_1
+	V1 
+
+Version References:
+  required from libc.so.6:
+    0x09691a75 0x00 04 GLIBC_2.2.5
+
+DYNAMIC SYMBOL TABLE:
+0000000000000b30 l    d  .init	0000000000000000              .init
+0000000000000000  w   D  *UND*	0000000000000000              _ITM_deregisterTMCloneTable
+0000000000000000  w   D  *UND*	0000000000000000              __gmon_start__
+0000000000000000  w   D  *UND*	0000000000000000              _Jv_RegisterClasses
+0000000000000000  w   D  *UND*	0000000000000000              _ITM_registerTMCloneTable
+0000000000000000  w   DF *UND*	0000000000000000  GLIBC_2.2.5 __cxa_finalize
+0000000000000cc0 g    DF .text	0000000000000002  Base        symdefaultverSPA CEdefault
+0000000000000df4 g    DF .fini	0000000000000000  Base        _fini
+0000000000202080 g    DO .data	00000000000000c0  Base        funcs
+0000000000000b30 g    DF .init	0000000000000000  Base        _init
+0000000000000d80 g    DF .text	0000000000000002  V1          symshortvernospacedefault
+0000000000202140 g    D  .bss	0000000000000000  Base        __bss_start
+0000000000000ca0 g    DF .text	0000000000000002  Base        .protected symdefaultvernospaceprotected
+0000000000202148 g    D  .bss	0000000000000000  Base        _end
+0000000000000dc0 g    DF .text	0000000000000002  V1          symshortverSPA CEdefault
+0000000000000000 g    DO *ABS*	0000000000000000  V1          V1
+0000000000000da0 g    DF .text	0000000000000002  V1          .protected symshortvernospaceprotected
+0000000000000d00 g    DF .text	0000000000000002  VERY_LONG_VERSION_1 symlongvernospacedefault
+0000000000000000 g    DO *ABS*	0000000000000000  VERY_LONG_VERSION_1 VERY_LONG_VERSION_1
+0000000000202140 g    D  .data	0000000000000000  Base        _edata
+0000000000000c80 g    DF .text	0000000000000002  Base        symdefaultvernospacedefault
+0000000000000d60 g    DF .text	0000000000000002  VERY_LONG_VERSION_1 .protected symlongverSPA CEprotected
+0000000000000ce0 g    DF .text	0000000000000002  Base        .protected symdefaultverSPA CEprotected
+0000000000000d40 g    DF .text	0000000000000002  VERY_LONG_VERSION_1 symlongverSPA CEdefault
+0000000000000de0 g    DF .text	0000000000000002  V1          .protected symshortverSPA CEprotected
+0000000000000d20 g    DF .text	0000000000000002  VERY_LONG_VERSION_1 .protected symlongvernospaceprotected
+
+
+DYNAMIC RELOCATION RECORDS
+OFFSET           TYPE              VALUE 
+0000000000201dd0 R_X86_64_RELATIVE  *ABS*+0x0000000000000c50
+0000000000201dd8 R_X86_64_RELATIVE  *ABS*+0x0000000000000c10
+0000000000202040 R_X86_64_RELATIVE  *ABS*+0x0000000000202040
+0000000000202088 R_X86_64_RELATIVE  *ABS*+0x0000000000000c90
+0000000000202098 R_X86_64_RELATIVE  *ABS*+0x0000000000000cb0
+00000000002020a8 R_X86_64_RELATIVE  *ABS*+0x0000000000000cd0
+00000000002020b8 R_X86_64_RELATIVE  *ABS*+0x0000000000000cf0
+00000000002020c8 R_X86_64_RELATIVE  *ABS*+0x0000000000000d10
+00000000002020d8 R_X86_64_RELATIVE  *ABS*+0x0000000000000d30
+00000000002020e8 R_X86_64_RELATIVE  *ABS*+0x0000000000000d50
+00000000002020f8 R_X86_64_RELATIVE  *ABS*+0x0000000000000d70
+0000000000202108 R_X86_64_RELATIVE  *ABS*+0x0000000000000d90
+0000000000202118 R_X86_64_RELATIVE  *ABS*+0x0000000000000db0
+0000000000202128 R_X86_64_RELATIVE  *ABS*+0x0000000000000dd0
+0000000000202138 R_X86_64_RELATIVE  *ABS*+0x0000000000000df0
+0000000000201fd8 R_X86_64_GLOB_DAT  _ITM_deregisterTMCloneTable
+0000000000201fe0 R_X86_64_GLOB_DAT  __gmon_start__
+0000000000201fe8 R_X86_64_GLOB_DAT  _Jv_RegisterClasses
+0000000000201ff0 R_X86_64_GLOB_DAT  _ITM_registerTMCloneTable
+0000000000201ff8 R_X86_64_GLOB_DAT  __cxa_finalize
+0000000000202080 R_X86_64_64       symdefaultvernospacedefault
+0000000000202090 R_X86_64_64       symdefaultvernospaceprotected
+00000000002020a0 R_X86_64_64       symdefaultverSPA CEdefault
+00000000002020b0 R_X86_64_64       symdefaultverSPA CEprotected
+00000000002020c0 R_X86_64_64       symlongvernospacedefault
+00000000002020d0 R_X86_64_64       symlongvernospaceprotected
+00000000002020e0 R_X86_64_64       symlongverSPA CEdefault
+00000000002020f0 R_X86_64_64       symlongverSPA CEprotected
+0000000000202100 R_X86_64_64       symshortvernospacedefault
+0000000000202110 R_X86_64_64       symshortvernospaceprotected
+0000000000202120 R_X86_64_64       symshortverSPA CEdefault
+0000000000202130 R_X86_64_64       symshortverSPA CEprotected
+0000000000202018 R_X86_64_JUMP_SLOT  __gmon_start__
+0000000000202020 R_X86_64_JUMP_SLOT  __cxa_finalize
+
+
diff --git a/scripts/t/Dpkg_Shlibs/spacesym.pl b/scripts/t/Dpkg_Shlibs/spacesym.pl
new file mode 100755
index 0000000..69986ea
--- /dev/null
+++ b/scripts/t/Dpkg_Shlibs/spacesym.pl
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+#
+# spacesym.pl INPUT OUTPUT copies the object file INPUT to OUTPUT,
+# redefining any symbol in INPUT that contains "SPACE" in its name to
+# contain "SPA CE" instead.
+
+use strict;
+
+my ($input, $output) = @ARGV;
+my @cmds = ("objcopy");
+open(NM, "nm $input | grep SPACE |");
+while (<NM>) {
+    chomp;
+    my $x = (split " ",$_,3)[2];
+    my $y = $x =~ s/SPACE/SPA CE/r;
+    push @cmds, "--redefine-sym=$x=$y";
+}
+push @cmds, $input, $output;
+exec @cmds;
diff --git a/scripts/t/Dpkg_Shlibs/spacesyms.map b/scripts/t/Dpkg_Shlibs/spacesyms.map
new file mode 100644
index 0000000..b40f71d
--- /dev/null
+++ b/scripts/t/Dpkg_Shlibs/spacesyms.map
@@ -0,0 +1,7 @@
+V1 {
+global: symshortver*;
+};
+
+VERY_LONG_VERSION_1 {
+global: symlongver*;
+} V1;
\ No newline at end of file
-- 
2.1.4

Reply via email to