Browse Source

Dpkg::Shlibs::Objdump: Support spaces in symbol names

The ELF spec does not disallow symbols with embedded spaces, so we
should really be supporting those. This is required by Go shared
libraries.

Closes: #785344
Based-on-patch-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Signed-off-by: Guillem Jover <guillem@debian.org>
Guillem Jover 8 years ago
parent
commit
8bc91e0955

+ 3 - 0
debian/changelog

@@ -65,6 +65,9 @@ dpkg (1.18.2) UNRELEASED; urgency=low
     - Make the dependency comparison deep by comparing not only the first
       dependency alternative, to get them sorted in a reproducible way.
       Based on a patch by Chris Lamb <lamby@debian.org>. Closes: #792491
+    - Support spaces in symbol names in Dpkg::Shlibs::Objdump. This is
+      required by Go shared libraries. Closes: #785344
+      Based on a patch by Michael Hudson-Doyle <michael.hudson@canonical.com>.
   * Test suite:
     - Set SIGINT, SIGTERM and SIGPIPE to their default actions to get
       deterministic behavior.

+ 6 - 6
scripts/Dpkg/Shlibs/Objdump.pm

@@ -194,8 +194,8 @@ sub parse_objdump_output {
 
     my $section = 'none';
     while (<$fh>) {
-	chomp;
-	next if /^\s*$/;
+	s/\s*$//;
+	next if length == 0;
 
 	if (/^DYNAMIC SYMBOL TABLE:/) {
 	    $section = 'dynsym';
@@ -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"), $_);
@@ -248,9 +248,9 @@ sub parse_objdump_output {
                 }
 	    }
 	} elsif ($section eq 'none') {
-	    if (/^\s*.+:\s*file\s+format\s+(\S+)\s*$/) {
+	    if (/^\s*.+:\s*file\s+format\s+(\S+)$/) {
 		$self->{format} = $1;
-	    } elsif (/^architecture:\s*\S+,\s*flags\s*\S+:\s*$/) {
+	    } elsif (/^architecture:\s*\S+,\s*flags\s*\S+:$/) {
 		# Parse 2 lines of "-f"
 		# architecture: i386, flags 0x00000112:
 		# EXEC_P, HAS_SYMS, D_PAGED
@@ -299,7 +299,7 @@ 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+)/) {
+    if ($line =~ /^[0-9a-f]+ (.{7})\s+(\S+)\s+[0-9a-f]+(?:\s+(\S+))?(?:\s+$vis_re)?\s+(.+)/) {
 
 	my ($flags, $sect, $ver, $vis, $name) = ($1, $2, $3, $4, $5);
 

+ 22 - 1
scripts/Makefile.am

@@ -255,6 +255,7 @@ test_data = \
 	t/Dpkg_Shlibs/ld.so.conf.d/inf_recurse.conf \
 	t/Dpkg_Shlibs/ld.so.conf.d/recursive.conf \
 	t/Dpkg_Shlibs/objdump.space \
+	t/Dpkg_Shlibs/objdump.spacesyms \
 	t/Dpkg_Shlibs/objdump.basictags-amd64 \
 	t/Dpkg_Shlibs/objdump.basictags-i386 \
 	t/Dpkg_Shlibs/objdump.basictags-mips \
@@ -265,6 +266,9 @@ test_data = \
 	t/Dpkg_Shlibs/objdump.libc6-2.6 \
 	t/Dpkg_Shlibs/objdump.dbd-pg \
 	t/Dpkg_Shlibs/objdump.ls \
+	t/Dpkg_Shlibs/spacesyms.map \
+	t/Dpkg_Shlibs/spacesyms-c-gen.pl \
+	t/Dpkg_Shlibs/spacesyms-o-map.pl \
 	t/Dpkg_Source_Patch/c-style.patch \
 	t/Dpkg_Source_Patch/ghost-hunk.patch \
 	t/Dpkg_Source_Patch/index-+++.patch \
@@ -314,7 +318,9 @@ 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 \
+	$(nil)
 
 $(srcdir)/t/Dpkg_Shlibs/libobjdump.basictags-amd64.so: $(srcdir)/t/Dpkg_Shlibs/basictags.c
 	$(CC) $(CFLAGS) -shared -fPIC -Wl,-soname -Wl,libbasictags.so.1 $< \
@@ -333,6 +339,19 @@ $(srcdir)/t/Dpkg_Shlibs/libobjdump.patterns.so: $(srcdir)/t/Dpkg_Shlibs/patterns
 	    -Wl,--version-script=$(srcdir)/t/Dpkg_Shlibs/patterns.map $< \
 	    -o $@
 
+$(srcdir)/t/Dpkg_Shlibs/spacesyms.c: $(srcdir)/t/Dpkg_Shlibs/spacesyms-c-gen.pl
+	$(srcdir)/t/Dpkg_Shlibs/spacesyms-c-gen.pl > $@
+
+$(srcdir)/t/Dpkg_Shlibs/spacesyms.o: $(srcdir)/t/Dpkg_Shlibs/spacesyms.c $(srcdir)/t/Dpkg_Shlibs/spacesyms-o-map.pl
+	$(CC) $(CFLAGS) -c -fPIC -o $@.tmp $<
+	$(srcdir)/t/Dpkg_Shlibs/spacesyms-o-map.pl $@.tmp $@
+	rm -f $@.tmp
+
+$(srcdir)/t/Dpkg_Shlibs/libobjdump.spacesyms.so: $(srcdir)/t/Dpkg_Shlibs/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
@@ -346,6 +365,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

+ 37 - 1
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,42 @@ 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, $version, $visibility) = @_;
+
+    $visibility //= '';
+    $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', 'Base', 'protected');
+check_spacesym('symlongvernospacedefault', 'VERY_LONG_VERSION_1');
+check_spacesym('symlongvernospaceprotected', 'VERY_LONG_VERSION_1', 'protected');
+check_spacesym('symshortvernospacedefault', 'V1');
+check_spacesym('symshortvernospaceprotected', 'V1', 'protected');
+check_spacesym('symdefaultverSPA CEdefault', 'Base');
+check_spacesym('symdefaultverSPA CEprotected', 'Base', 'protected');
+check_spacesym('symlongverSPA CEdefault', 'VERY_LONG_VERSION_1');
+check_spacesym('symlongverSPA CEprotected', 'VERY_LONG_VERSION_1', 'protected');
+check_spacesym('symshortverSPA CEdefault', 'V1');
+check_spacesym('symshortverSPA CEprotected', 'V1', 'protected');
+
 ####### Test symbol tagging support  ######
 
 # Parsing/dumping

+ 1 - 0
scripts/t/Dpkg_Shlibs/.gitignore

@@ -0,0 +1 @@
+spacesyms.c

+ 124 - 0
scripts/t/Dpkg_Shlibs/objdump.spacesyms

@@ -0,0 +1,124 @@
+
+./t/Dpkg_Shlibs/libobjdump.spacesyms.so:     file format elf32-i386
+architecture: i386, flags 0x00000150:
+HAS_SYMS, DYNAMIC, D_PAGED
+start address 0x000007a0
+
+Program Header:
+    LOAD off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**12
+         filesz 0x00000d5c memsz 0x00000d5c flags r-x
+    LOAD off    0x00000d5c vaddr 0x00001d5c paddr 0x00001d5c align 2**12
+         filesz 0x00000204 memsz 0x00000208 flags rw-
+ DYNAMIC off    0x00000d68 vaddr 0x00001d68 paddr 0x00001d68 align 2**2
+         filesz 0x000000f8 memsz 0x000000f8 flags rw-
+    NOTE off    0x000000f4 vaddr 0x000000f4 paddr 0x000000f4 align 2**2
+         filesz 0x00000024 memsz 0x00000024 flags r--
+EH_FRAME off    0x00000a68 vaddr 0x00000a68 paddr 0x00000a68 align 2**2
+         filesz 0x000000d4 memsz 0x000000d4 flags r--
+   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4
+         filesz 0x00000000 memsz 0x00000000 flags rw-
+
+Dynamic Section:
+  NEEDED               libc.so.6
+  SONAME               libspacesyms.so.1
+  INIT                 0x00000740
+  FINI                 0x00000a54
+  INIT_ARRAY           0x00001d5c
+  INIT_ARRAYSZ         0x00000004
+  FINI_ARRAY           0x00001d60
+  FINI_ARRAYSZ         0x00000004
+  GNU_HASH             0x00000118
+  STRTAB               0x0000036c
+  SYMTAB               0x000001cc
+  STRSZ                0x00000214
+  SYMENT               0x00000010
+  PLTGOT               0x00001e74
+  PLTRELSZ             0x00000010
+  PLTREL               0x00000011
+  JMPREL               0x00000730
+  REL                  0x00000630
+  RELSZ                0x00000100
+  RELENT               0x00000008
+  VERDEF               0x000005b4
+  VERDEFNUM            0x00000003
+  VERNEED              0x00000610
+  VERNEEDNUM           0x00000001
+  VERSYM               0x00000580
+  RELCOUNT             0x0000000f
+
+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:
+    0x09691f73 0x00 04 GLIBC_2.1.3
+
+DYNAMIC SYMBOL TABLE:
+00000000  w   D  *UND*	00000000              _ITM_deregisterTMCloneTable
+00000000  w   DF *UND*	00000000  GLIBC_2.1.3 __cxa_finalize
+00000000  w   D  *UND*	00000000              __gmon_start__
+00000000  w   D  *UND*	00000000              _Jv_RegisterClasses
+00000000  w   D  *UND*	00000000              _ITM_registerTMCloneTable
+00000920 g    DF .text	00000002  Base        symdefaultverSPA CEdefault
+00000a54 g    DF .fini	00000000  Base        _fini
+00001f00 g    DO .data	00000060  Base        funcs
+00000740 g    DF .init	00000000  Base        _init
+000009e0 g    DF .text	00000002  V1          symshortvernospacedefault
+00001f60 g    D  .bss	00000000  Base        __bss_start
+00000900 g    DF .text	00000002  Base        .protected symdefaultvernospaceprotected
+00001f64 g    D  .bss	00000000  Base        _end
+00000a20 g    DF .text	00000002  V1          symshortverSPA CEdefault
+00000000 g    DO *ABS*	00000000  V1          V1
+00000a00 g    DF .text	00000002  V1          .protected symshortvernospaceprotected
+00000960 g    DF .text	00000002  VERY_LONG_VERSION_1 symlongvernospacedefault
+00000000 g    DO *ABS*	00000000  VERY_LONG_VERSION_1 VERY_LONG_VERSION_1
+00001f60 g    D  .data	00000000  Base        _edata
+000008e0 g    DF .text	00000002  Base        symdefaultvernospacedefault
+000009c0 g    DF .text	00000002  VERY_LONG_VERSION_1 .protected symlongverSPA CEprotected
+00000940 g    DF .text	00000002  Base        .protected symdefaultverSPA CEprotected
+000009a0 g    DF .text	00000002  VERY_LONG_VERSION_1 symlongverSPA CEdefault
+00000a40 g    DF .text	00000002  V1          .protected symshortverSPA CEprotected
+00000980 g    DF .text	00000002  VERY_LONG_VERSION_1 .protected symlongvernospaceprotected
+
+
+DYNAMIC RELOCATION RECORDS
+OFFSET   TYPE              VALUE 
+00001d5c R_386_RELATIVE    *ABS*
+00001d60 R_386_RELATIVE    *ABS*
+00001ec0 R_386_RELATIVE    *ABS*
+00001f04 R_386_RELATIVE    *ABS*
+00001f0c R_386_RELATIVE    *ABS*
+00001f14 R_386_RELATIVE    *ABS*
+00001f1c R_386_RELATIVE    *ABS*
+00001f24 R_386_RELATIVE    *ABS*
+00001f2c R_386_RELATIVE    *ABS*
+00001f34 R_386_RELATIVE    *ABS*
+00001f3c R_386_RELATIVE    *ABS*
+00001f44 R_386_RELATIVE    *ABS*
+00001f4c R_386_RELATIVE    *ABS*
+00001f54 R_386_RELATIVE    *ABS*
+00001f5c R_386_RELATIVE    *ABS*
+00001e60 R_386_GLOB_DAT    _ITM_deregisterTMCloneTable
+00001e64 R_386_GLOB_DAT    __cxa_finalize
+00001e68 R_386_GLOB_DAT    __gmon_start__
+00001e6c R_386_GLOB_DAT    _Jv_RegisterClasses
+00001e70 R_386_GLOB_DAT    _ITM_registerTMCloneTable
+00001f00 R_386_32          symdefaultvernospacedefault
+00001f08 R_386_32          symdefaultvernospaceprotected
+00001f10 R_386_32          symdefaultverSPA CEdefault
+00001f18 R_386_32          symdefaultverSPA CEprotected
+00001f20 R_386_32          symlongvernospacedefault
+00001f28 R_386_32          symlongvernospaceprotected
+00001f30 R_386_32          symlongverSPA CEdefault
+00001f38 R_386_32          symlongverSPA CEprotected
+00001f40 R_386_32          symshortvernospacedefault
+00001f48 R_386_32          symshortvernospaceprotected
+00001f50 R_386_32          symshortverSPA CEdefault
+00001f58 R_386_32          symshortverSPA CEprotected
+00001e80 R_386_JUMP_SLOT   __cxa_finalize
+00001e84 R_386_JUMP_SLOT   __gmon_start__
+
+

+ 37 - 0
scripts/t/Dpkg_Shlibs/spacesyms-c-gen.pl

@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+#
+# spacesyms-c-gen.pl
+#
+# Output a C file that contains symbols matching the shell glob
+# 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 spacesyms-o-map.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;
+use warnings;
+
+my @symbols;
+
+foreach my $version (qw(defaultver longver shortver)) {
+    foreach my $space (qw(nospace SPACE)) {
+        foreach my $visibility (qw(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";

+ 25 - 0
scripts/t/Dpkg_Shlibs/spacesyms-o-map.pl

@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+#
+# spacesyms-o-map.pl INPUT OUTPUT
+#
+# Copy the object file INPUT to OUTPUT, redefining any symbol in INPUT that
+# contains "SPACE" in its name to contain "SPA CE" instead.
+
+use strict;
+use warnings;
+
+my ($input, $output) = @ARGV;
+my @cmds = ('objcopy');
+
+open my $nm, '-|', 'nm', $input or die "cannot run nm: $!";
+while (<$nm>) {
+    next if not m/SPACE/;
+    chomp;
+    my $x = (split / /, $_, 3)[2];
+    my $y = $x =~ s/SPACE/SPA CE/r;
+    push @cmds, "--redefine-sym=$x=$y";
+}
+close $nm;
+
+push @cmds, $input, $output;
+exec @cmds;

+ 7 - 0
scripts/t/Dpkg_Shlibs/spacesyms.map

@@ -0,0 +1,7 @@
+V1 {
+	global: symshortver*;
+};
+
+VERY_LONG_VERSION_1 {
+	global: symlongver*;
+} V1;