Skip to content
Snippets Groups Projects
Commit cc3a2ba7 authored by Ximin Luo's avatar Ximin Luo
Browse files

Add support for reading the symbol table to ArFile

parent 3ba4298d
No related branches found
No related tags found
No related merge requests found
......@@ -131,6 +131,10 @@ class RequiredToolNotFound(Exception):
'arch': 'gettext',
'FreeBSD': 'gettext-tools',
},
'nm': {
'debian': 'binutils-multiarch',
'arch': 'binutils',
},
'objdump': {
'debian': 'binutils-multiarch',
'arch': 'binutils',
......
......@@ -18,13 +18,15 @@
# You should have received a copy of the GNU General Public License
# along with diffoscope. If not, see <http://www.gnu.org/licenses/>.
import os.path
import re
from diffoscope import tool_required
from diffoscope.difference import Difference
from diffoscope.comparators.binary import File
from diffoscope.comparators.libarchive import LibarchiveContainer, list_libarchive
from diffoscope.comparators.utils import Command
from diffoscope import logger
# TODO: this would also be useful for Go archives. Currently those are handled
# by StaticLibFile, but then readelf complains with "Error: Not an ELF file".
# ArFile gives slightly more reasonable output, e.g. a readable plain diff of
......@@ -34,16 +36,20 @@ class ArContainer(LibarchiveContainer):
def get_members(self):
members = LibarchiveContainer.get_members(self)
cls = members.__class__
# for some reason libarchive outputs ["/", "//"] as member names for
# some archives. for now, let's just filter these out, otherwise they
# cause exceptions later. eventually, we should investigate this in
# more detail and handle it properly.
filtered_out = cls([p for p in members.items() if not os.path.basename(p[0])])
known_ignores = {
"/" : "this is the symbol table, already accounted for in other output",
"//" : "this is the table for GNU long names, already accounted for in the archive filelist",
}
filtered_out = cls([p for p in members.items() if p[0] in known_ignores])
if filtered_out:
logger.debug("ignored directory ar members %s in %s, don't yet know how to handle these",
list(filtered_out.keys()), self.source.path)
return cls([p for p in members.items() if os.path.basename(p[0])])
for k, v in filtered_out.items():
logger.debug("ignored ar member '%s' because %s", k, known_ignores[k])
return cls([p for p in members.items() if p[0] not in known_ignores])
class ArSymbolTableDumper(Command):
@tool_required('nm')
def cmdline(self):
return ['nm', '-s', self.path]
class ArFile(File):
CONTAINER_CLASS = ArContainer
......@@ -54,6 +60,7 @@ class ArFile(File):
return ArFile.RE_FILE_TYPE.search(file.magic_file_type)
def compare_details(self, other, source=None):
return [Difference.from_text_readers(list_libarchive(self.path),
list_libarchive(other.path),
self.path, other.path, source="file list")]
return [Difference.from_command(ArSymbolTableDumper, self.path, other.path),
Difference.from_text_readers(list_libarchive(self.path),
list_libarchive(other.path),
self.path, other.path, source="file list")]
......@@ -52,22 +52,31 @@ def test_no_differences(rlib1):
def differences(rlib1, rlib2):
return rlib1.compare(rlib2).details
def test_item0_elf(differences):
assert differences[0].source1 == 'alloc_system-d16b8f0e.0.o'
assert differences[0].source2 == 'alloc_system-d16b8f0e.0.o'
def test_num_items(differences):
assert len(differences) == 4
def test_item0_armap(differences):
assert differences[0].source1 == 'nm -s {}'
assert differences[0].source2 == 'nm -s {}'
expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/rlib_armap_expected_diff')).read()
assert differences[0].unified_diff == expected_diff
def test_item1_elf(differences):
assert differences[1].source1 == 'alloc_system-d16b8f0e.0.o'
assert differences[1].source2 == 'alloc_system-d16b8f0e.0.o'
expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/rlib_elf_expected_diff')).read()
assert differences[0].details[0].unified_diff == expected_diff
assert differences[1].details[0].unified_diff == expected_diff
def test_item1_rust_metadata_bin(differences):
assert differences[1].source1 == 'rust.metadata.bin'
assert differences[1].source2 == 'rust.metadata.bin'
def test_item2_rust_metadata_bin(differences):
assert differences[2].source1 == 'rust.metadata.bin'
assert differences[2].source2 == 'rust.metadata.bin'
@pytest.mark.skipif(tool_missing('llvm-dis'), reason='missing llvm-dis')
def test_item2_deflate_llvm_bitcode(differences):
assert differences[2].source1 == 'alloc_system-d16b8f0e.0.bytecode.deflate'
assert differences[2].source2 == 'alloc_system-d16b8f0e.0.bytecode.deflate'
def test_item3_deflate_llvm_bitcode(differences):
assert differences[3].source1 == 'alloc_system-d16b8f0e.0.bytecode.deflate'
assert differences[3].source2 == 'alloc_system-d16b8f0e.0.bytecode.deflate'
expected_diff = open(os.path.join(os.path.dirname(__file__), '../data/rlib_llvm_dis_expected_diff')).read()
actual_diff = differences[2].details[0].details[1].unified_diff
actual_diff = differences[3].details[0].details[1].unified_diff
assert diff_ignore_line_numbers(actual_diff) == diff_ignore_line_numbers(expected_diff)
def test_compare_non_existing(monkeypatch, rlib1):
......
@@ -1,10 +1,10 @@
Archive index:
-__rust_allocate in alloc_system-d16b8f0e.0.o
+__rust_all0cate in alloc_system-d16b8f0e.0.o
__rust_deallocate in alloc_system-d16b8f0e.0.o
__rust_reallocate in alloc_system-d16b8f0e.0.o
__rust_reallocate_inplace in alloc_system-d16b8f0e.0.o
__rust_usable_size in alloc_system-d16b8f0e.0.o
alloc_system-d16b8f0e.0.o:
0000000000000000 T __rust_allocate
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment