diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -172,6 +172,12 @@ When disassembling with the :option:`--source` option, prepend ``prefix`` to absolute paths. +.. option:: --prefix-strip= + + When disassembling with the :option:`--source` option, strip out ``level`` + initial directories from absolute paths. This option has no effect without + :option:`--prefix`. + .. option:: --print-imm-hex Use hex format when printing immediate values in disassembly output. diff --git a/llvm/docs/llvm-objdump.1 b/llvm/docs/llvm-objdump.1 --- a/llvm/docs/llvm-objdump.1 +++ b/llvm/docs/llvm-objdump.1 @@ -109,6 +109,11 @@ When disassembling, add .Ar PREFIX to absolute paths. +.It Fl -prefix-strip Ns = Ns Ar LEVEL +When disassembling, strip out +.Ar LEVEL +initial directories from absolute paths. This option has no effect without +.Fl -prefix Ns = Ns PREFIX . .It Fl -print-imm-hex Use hex format for immediate values. .It Fl -private-header diff --git a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test --- a/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test +++ b/llvm/test/tools/llvm-objdump/X86/source-interleave-prefix.test @@ -12,8 +12,8 @@ ; RUN: sed -e "s,SRC_COMPDIR,./Inputs,g" %p/Inputs/source-interleave.ll > %t-relative-path.ll ; RUN: llc -o %t-relative-path.o -filetype=obj -mtriple=x86_64-pc-linux %t-relative-path.ll ; RUN: llvm-objdump --prefix myprefix --source %t-relative-path.o 2>&1 | \ -; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-relative-path.o -DPREFIX=. -; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]]/Inputs{{[/\\]}}source-interleave-x86_64.c +; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-relative-path.o -DPREFIX=. -DCOMPDIR=/Inputs +; CHECK-BROKEN-PREFIX: warning: '[[FILE]]': failed to find source [[PREFIX]][[COMPDIR]]{{[/\\]}}source-interleave-x86_64.c ;; Test invalid source interleave fixed by adding the correct prefix. @@ -28,16 +28,64 @@ ; RUN: sed -e "s,SRC_COMPDIR,%/p/Inputs,g" %p/Inputs/source-interleave.ll > %t-correct-prefix.ll ; RUN: llc -o %t-correct-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-correct-prefix.ll ; RUN: llvm-objdump --prefix myprefix --source %t-correct-prefix.o 2>&1 | \ -; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-correct-prefix.o -DPREFIX=myprefix%/p +; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-correct-prefix.o -DPREFIX=myprefix%/p -DCOMPDIR=/Inputs ;; Using only a prefix separator is the same as not using the `--prefix` option. ; RUN: llvm-objdump --prefix / --source %t-missing-prefix.o 2>&1 | \ -; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX='' +; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX='' -DCOMPDIR=/Inputs ;; All trailing separators on the prefix are discarded. ;; The prefix 'myprefix//' is converted to 'myprefix'. ; RUN: llvm-objdump --prefix myprefix// --source %t-missing-prefix.o 2>&1 | \ -; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix +; RUN: FileCheck %s --check-prefix=CHECK-BROKEN-PREFIX -DFILE=%t-missing-prefix.o -DPREFIX=myprefix -DCOMPDIR=/Inputs +;; Test invalid source interleave fixed by adding the correct prefix and +;; stripping out an extra directory from the path. + +; RUN: sed -e "s,SRC_COMPDIR,/extra/Inputs,g" %p/Inputs/source-interleave.ll > %t-extra-path-prefix.ll +; RUN: llc -o %t-extra-path-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-extra-path-prefix.ll +; RUN: llvm-objdump --prefix %p --prefix-strip 1 --source %t-extra-path-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-MISSING-PREFIX-FIX + +;; Test do not skip extra separators. The --prefix-strip should take into +;; account each separator individually. Hence, to fix '/extra/Inputs' +;; --prefix-strip needs to be 1. To fix '//extra/Inputs' --prefix-strip +;; needs to be 2. + +; RUN: sed -e "s,SRC_COMPDIR,//extra/Inputs,g" %p/Inputs/source-interleave.ll > %t-extra-sep-path-prefix.ll +; RUN: llc -o %t-extra-sep-path-prefix.o -filetype=obj -mtriple=x86_64-pc-linux %t-extra-sep-path-prefix.ll +; RUN: llvm-objdump --prefix %p --prefix-strip 2 --source %t-extra-sep-path-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-MISSING-PREFIX-FIX + +;; Test --prefix-strip value of 0. No effect. +;; SRC_COMPDIR is set to '/Inputs' before and after --prefix-strip 0. + +; RUN: llvm-objdump --prefix %p --prefix-strip 0 --source %t-missing-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-MISSING-PREFIX-FIX + +;; Test --prefix-strip value equal to the number of directory components. +;; SRC_COMPDIR is set to '/Inputs' before --prefix-strip 1. +;; SRC_COMPDIR becomes '' after --prefix-strip 1. + +; RUN: llvm-objdump --prefix %p/Inputs --prefix-strip 1 --source %t-missing-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-MISSING-PREFIX-FIX + +;; Test --prefix-strip value greater than the number of components. +;; SRC_COMPDIR is set to '/Inputs' before --prefix-strip 2. +;; SRC_COMPDIR becomes '' after --prefix-strip 2. + +; RUN: llvm-objdump --prefix %p/Inputs --prefix-strip 2 --source %t-missing-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-MISSING-PREFIX-FIX + +;; Test negative value --prefix-strip. Reports an error. + +; RUN: not llvm-objdump --prefix %p --prefix-strip '-1' --source %t-missing-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-INVALID-PREFIX-STRIP -DOPTION='-1' +; CHECK-INVALID-PREFIX-STRIP: llvm-objdump{{.*}}: for the --prefix-strip option: '[[OPTION]]' value invalid for uint argument! + +;; Test text value --prefix-strip. Reports an error. + +; RUN: not llvm-objdump --prefix %p --prefix-strip foo --source %t-missing-prefix.o 2>&1 | \ +; RUN: FileCheck %s --check-prefix=CHECK-INVALID-PREFIX-STRIP -DOPTION='foo' diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -42,6 +42,7 @@ extern cl::opt NoShowRawInsn; extern cl::opt NoLeadingAddr; extern cl::opt Prefix; +extern cl::opt PrefixStrip; extern cl::opt PrintImmHex; extern cl::opt PrivateHeaders; extern cl::opt Relocations; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -358,6 +358,12 @@ cl::desc("Add prefix to absolute paths"), cl::cat(ObjdumpCat)); +cl::opt + objdump::PrefixStrip("prefix-strip", + cl::desc("Strip out initial directories from absolute " + "paths. No effect without --prefix"), + cl::init(0), cl::cat(ObjdumpCat)); + enum DebugVarsFormat { DVDisabled, DVUnicode, @@ -1031,6 +1037,27 @@ } if (!Prefix.empty() && sys::path::is_absolute_gnu(LineInfo.FileName)) { + // FileName has at least one character since is_absolute_gnu is false for + // an empty string. + assert(!LineInfo.FileName.empty()); + if (PrefixStrip > 0) { + uint32_t Level = 0; + auto StrippedNameStart = LineInfo.FileName.begin(); + + // Path.h iterator skips extra separators. Therefore it cannot be used + // here to keep compatibility with GNU Objdump. + for (auto Pos = StrippedNameStart + 1, End = LineInfo.FileName.end(); + Pos != End && Level < PrefixStrip; ++Pos) { + if (sys::path::is_separator(*Pos)) { + StrippedNameStart = Pos; + ++Level; + } + } + + LineInfo.FileName = + std::string(StrippedNameStart, LineInfo.FileName.end()); + } + SmallString<128> FilePath; sys::path::append(FilePath, Prefix, LineInfo.FileName);