[llvm-ar] Implement the O modifier: display member offsets inside the archive

Since GNU ar 2.31, the 't' operation prints member offsets beside file
names if the 'O' modifier is specified. 'O' is ignored for thin
archives.

Reviewed By: gbreynoo, ruiu

Differential Revision: https://reviews.llvm.org/D69087

llvm-svn: 375106
This commit is contained in:
Fangrui Song 2019-10-17 11:34:29 +00:00
parent 807a019065
commit c1f3443f19
5 changed files with 48 additions and 16 deletions

View File

@ -100,15 +100,15 @@ r[abu]
*files* or insert them at the end of the archive if they do not exist. If no
*files* are specified, the archive is not modified.
t[v]
t[vO]
Print the table of contents. Without any modifiers, this operation just prints
the names of the members to the standard output. With the *v* modifier,
**llvm-ar** also prints out the file type (B=bitcode, S=symbol
table, blank=regular file), the permission mode, the owner and group, the
size, and the date. If any *files* are specified, the listing is only for
those files. If no *files* are specified, the table of contents for the
whole archive is printed.
size, and the date. With the :option:`O` modifier, display member offsets.
If any *files* are specified, the listing is only for those files. If no
*files* are specified, the table of contents for the whole archive is printed.
x[oP]
@ -145,6 +145,10 @@ section (above) to determine which modifiers are applicable to which operations.
When extracting files, this option will cause **llvm-ar** to preserve the
original modification times of the files it writes.
[O]
Display member offsets inside the archive.
[u]
When replacing existing files in the archive, only replace those files that have

View File

@ -135,6 +135,7 @@ public:
Expected<StringRef> getBuffer() const;
uint64_t getChildOffset() const;
uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; }
Expected<MemoryBufferRef> getMemoryBufferRef() const;

View File

@ -9,6 +9,9 @@ RUN: llvm-ar qcT foo/libtest.a foo/test1.o
RUN: llvm-ar qcT foo/libtest.a foo/test2.o
RUN: llvm-ar t foo/libtest.a | FileCheck --match-full-lines %s
O (displaying member offsets) is ignored for thin archives.
RUN: llvm-ar tO foo/libtest.a | FileCheck --match-full-lines %s
CHECK: foo/test1.o
CHECK: foo/test1.o
CHECK: foo/test2.o

View File

@ -46,3 +46,17 @@ RUN: env TZ=GMT llvm-ar tv Inputs/thin-path.a | FileCheck %s --check-prefix=THIN
THINPATH: rw-r--r-- 0/0 1224 Jan 1 00:00 1970 Inputs/test.o
THINPATH-NEXT: rw-r--r-- 0/0 1224 Jan 1 00:00 1970 Inputs/t/test2.o
RUN: llvm-ar tO Inputs/GNU.a | FileCheck %s --check-prefix=GNU-O --strict-whitespace
GNU-O: {{^}}evenlen 0x10c
GNU-O-NEXT: {{^}}oddlen 0x150
GNU-O-NEXT: {{^}}very_long_bytecode_file_name.bc 0x194
GNU-O-NEXT: {{^}}IsNAN.o 0x78a
RUN: env TZ=GMT llvm-ar tvO Inputs/GNU.a | FileCheck %s --check-prefix=GNU-VO --strict-whitespace
GNU-VO: rw-r--r-- 500/500 8 Nov 19 02:57 2004 evenlen 0x10c
GNU-VO-NEXT: rw-r--r-- 500/500 7 Nov 19 02:57 2004 oddlen 0x150
GNU-VO-NEXT: rwxr-xr-x 500/500 1465 Nov 19 03:01 2004 very_long_bytecode_file_name.bc 0x194
GNU-VO-NEXT: rw-r--r-- 500/500 2280 Nov 19 03:04 2004 IsNAN.o 0x78a

View File

@ -106,6 +106,7 @@ MODIFIERS:
[L] - add archive's contents
[N] - use instance [count] of name
[o] - preserve original dates
[O] - display member offsets
[P] - use full names when matching (implied for thin archives)
[s] - create an archive index (cf. ranlib)
[S] - do not build a symbol table
@ -187,17 +188,18 @@ enum ArchiveOperation {
};
// Modifiers to follow operation to vary behavior
static bool AddAfter = false; ///< 'a' modifier
static bool AddBefore = false; ///< 'b' modifier
static bool Create = false; ///< 'c' modifier
static bool OriginalDates = false; ///< 'o' modifier
static bool CompareFullPath = false; ///< 'P' modifier
static bool OnlyUpdate = false; ///< 'u' modifier
static bool Verbose = false; ///< 'v' modifier
static bool Symtab = true; ///< 's' modifier
static bool Deterministic = true; ///< 'D' and 'U' modifiers
static bool Thin = false; ///< 'T' modifier
static bool AddLibrary = false; ///< 'L' modifier
static bool AddAfter = false; ///< 'a' modifier
static bool AddBefore = false; ///< 'b' modifier
static bool Create = false; ///< 'c' modifier
static bool OriginalDates = false; ///< 'o' modifier
static bool DisplayMemberOffsets = false; ///< 'O' modifier
static bool CompareFullPath = false; ///< 'P' modifier
static bool OnlyUpdate = false; ///< 'u' modifier
static bool Verbose = false; ///< 'v' modifier
static bool Symtab = true; ///< 's' modifier
static bool Deterministic = true; ///< 'D' and 'U' modifiers
static bool Thin = false; ///< 'T' modifier
static bool AddLibrary = false; ///< 'L' modifier
// Relative Positional Argument (for insert/move). This variable holds
// the name of the archive member to which the 'a', 'b' or 'i' modifier
@ -329,6 +331,9 @@ static ArchiveOperation parseCommandLine() {
case 'o':
OriginalDates = true;
break;
case 'O':
DisplayMemberOffsets = true;
break;
case 'P':
CompareFullPath = true;
break;
@ -486,8 +491,13 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) {
if (!ParentDir.empty())
outs() << sys::path::convert_to_slash(ParentDir) << '/';
}
outs() << Name;
} else {
outs() << Name;
if (DisplayMemberOffsets)
outs() << " 0x" << utohexstr(C.getDataOffset(), true);
}
outs() << Name << "\n";
outs() << '\n';
}
static std::string normalizePath(StringRef Path) {