diff --git a/llvm/docs/CommandGuide/llvm-ar.rst b/llvm/docs/CommandGuide/llvm-ar.rst --- a/llvm/docs/CommandGuide/llvm-ar.rst +++ b/llvm/docs/CommandGuide/llvm-ar.rst @@ -100,15 +100,15 @@ *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 @@ 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 diff --git a/llvm/include/llvm/Object/Archive.h b/llvm/include/llvm/Object/Archive.h --- a/llvm/include/llvm/Object/Archive.h +++ b/llvm/include/llvm/Object/Archive.h @@ -135,6 +135,7 @@ Expected getBuffer() const; uint64_t getChildOffset() const; + uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; } Expected getMemoryBufferRef() const; diff --git a/llvm/test/Object/archive-thin-create.test b/llvm/test/Object/archive-thin-create.test --- a/llvm/test/Object/archive-thin-create.test +++ b/llvm/test/Object/archive-thin-create.test @@ -9,6 +9,9 @@ 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 diff --git a/llvm/test/Object/archive-toc.test b/llvm/test/Object/archive-toc.test --- a/llvm/test/Object/archive-toc.test +++ b/llvm/test/Object/archive-toc.test @@ -46,3 +46,17 @@ 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 diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp --- a/llvm/tools/llvm-ar/llvm-ar.cpp +++ b/llvm/tools/llvm-ar/llvm-ar.cpp @@ -106,6 +106,7 @@ [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 @@ }; // 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 @@ case 'o': OriginalDates = true; break; + case 'O': + DisplayMemberOffsets = true; + break; case 'P': CompareFullPath = true; break; @@ -486,8 +491,13 @@ 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) {