From 09a7f6016ae87e97275e18ea662ff32a120c04a4 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 3 Jul 2013 15:57:14 +0000 Subject: [PATCH] Add support for gnu archives with a string table and no symtab. While there, use early returns to reduce nesting. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185547 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Object/Archive.cpp | 79 ++++++++++++------- .../Inputs/archive-test.a-gnu-no-symtab | 5 ++ test/Object/nm-archive.test | 3 + 3 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 test/Object/Inputs/archive-test.a-gnu-no-symtab diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 6bd087d01d0..8206b0a18bc 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -114,13 +114,19 @@ Archive::Archive(MemoryBuffer *source, error_code &ec) child_iterator i = begin_children(false); child_iterator e = end_children(); + if (i == e) { + ec = object_error::parse_failed; + return; + } + + // FIXME: this function should be able to use raw names. StringRef name; if ((ec = i->getName(name))) return; // Below is the pattern that is used to figure out the archive format // GNU archive format - // First member : / (points to the symbol table ) + // First member : / (may exist, if it exists, points to the symbol table ) // Second member : // (may exist, if it exists, points to the string table) // Note : The string table is used if the filename exceeds 15 characters // BSD archive format @@ -136,40 +142,59 @@ Archive::Archive(MemoryBuffer *source, error_code &ec) // even if the string table is empty. However, lib.exe does not in fact // seem to create the third member if there's no member whose filename // exceeds 15 characters. So the third member is optional. + + if (name == "__.SYMDEF") { + Format = K_BSD; + SymbolTable = i; + ec = object_error::success; + return; + } + if (name == "/") { SymbolTable = i; - StringTable = e; - if (i != e) ++i; + + ++i; if (i == e) { ec = object_error::parse_failed; return; } if ((ec = i->getName(name))) return; - if (name[0] != '/') { - Format = K_GNU; - } else if ((name.size() > 1) && (name == "//")) { - Format = K_GNU; - StringTable = i; - ++i; - } else { - Format = K_COFF; - if (i != e) { - SymbolTable = i; - ++i; - } - if (i != e) { - if ((ec = i->getName(name))) - return; - if (name == "//") - StringTable = i; - } - } - } else if (name == "__.SYMDEF") { - Format = K_BSD; - SymbolTable = i; - StringTable = e; - } + } + + if (name == "//") { + Format = K_GNU; + StringTable = i; + ec = object_error::success; + return; + } + + if (name[0] != '/') { + Format = K_GNU; + ec = object_error::success; + return; + } + + if (name != "/") { + ec = object_error::parse_failed; + return; + } + + Format = K_COFF; + SymbolTable = i; + + ++i; + if (i == e) { + ec = object_error::success; + return; + } + + if ((ec = i->getName(name))) + return; + + if (name == "//") + StringTable = i; + ec = object_error::success; } diff --git a/test/Object/Inputs/archive-test.a-gnu-no-symtab b/test/Object/Inputs/archive-test.a-gnu-no-symtab new file mode 100644 index 00000000000..0a5b237a291 --- /dev/null +++ b/test/Object/Inputs/archive-test.a-gnu-no-symtab @@ -0,0 +1,5 @@ +! +// 24 ` +a-very-long-file-name/ + +/0 1372864788 1000 1000 100664 0 ` diff --git a/test/Object/nm-archive.test b/test/Object/nm-archive.test index e35b4d431e6..869bea849c4 100644 --- a/test/Object/nm-archive.test +++ b/test/Object/nm-archive.test @@ -1,10 +1,13 @@ RUN: llvm-nm %p/Inputs/archive-test.a-coff-i386 \ RUN: | FileCheck %s -check-prefix COFF + RUN: llvm-as %p/Inputs/trivial.ll -o=%t1 RUN: rm -f %t2 RUN: llvm-ar rcs %t2 %t1 RUN: llvm-nm %t2 | FileCheck %s -check-prefix BITCODE +Test we don't error with an archive with no symtab. +RUN: llvm-nm %p/Inputs/archive-test.a-gnu-no-symtab COFF: trivial-object-test.coff-i386: COFF-NEXT: 00000000 d .data