[llvm] r305733 - Change llvm-nm for Mach-O files to use dyld info in some cases when printing symbols.

Kevin Enderby via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 19 17:26:38 PDT 2017


Hi Vitaly,

Thanks for point this out.  I didn’t seem to get an email for the sanitizer-x86_64-linux-fast bot.  I think it is because of the fields I added to the struct NMSymbol that are not set on the main path.  I’ve got a diff I’m building now to memset the structs to 0.  Should fix this.

Kev

> On Jun 19, 2017, at 5:02 PM, Vitaly Buka <vitalybuka at google.com> wrote:
> 
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/5758/steps/check-llvm%20msan/logs/stdio <http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/5758/steps/check-llvm%20msan/logs/stdio>
> 
> Command Output (stderr):
> --
> ==28618==WARNING: MemorySanitizer: use-of-uninitialized-value
>     #0 0x51239a in sortAndPrintSymbolList(llvm::object::SymbolicFile&, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-nm/llvm-nm.cpp:733:21
>     #1 0x5043d7 in dumpSymbolNamesFromObject(llvm::object::SymbolicFile&, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-nm/llvm-nm.cpp:1534:3
>     #2 0x4ef45c in dumpSymbolNamesFromFile(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-nm/llvm-nm.cpp:1633:11
>     #3 0x4e34f2 in for_each<std::__1::__wrap_iter<std::__1::basic_string<char> *>, void (*)(std::__1::basic_string<char> &)> /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/libcxx_build_msan/include/c++/v1/algorithm:965:9
>     #4 0x4e34f2 in main /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-nm/llvm-nm.cpp:1925
>     #5 0x7f4274b8482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
>     #6 0x476fd8 in _start (/mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm_build_msan/bin/llvm-nm+0x476fd8)
> 
> SUMMARY: MemorySanitizer: use-of-uninitialized-value /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/tools/llvm-nm/llvm-nm.cpp:733:21 in sortAndPrintSymbolList(llvm::object::SymbolicFile&, bool, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
> Exiting
> FileCheck error: '-' is empty.
> FileCheck command line:  /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm_build_msan/./bin/FileCheck --check-prefix=COFF-SHORT-IMPORT /mnt/b/sanitizer-buildbot3/sanitizer-x86_64-linux-fast/build/llvm/test/Object/archive-symtab.test
> 
> --
> 
> 
> On Mon, Jun 19, 2017 at 12:38 PM, Kevin Enderby via llvm-commits <llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>> wrote:
> Author: enderby
> Date: Mon Jun 19 14:38:22 2017
> New Revision: 305733
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=305733&view=rev <http://llvm.org/viewvc/llvm-project?rev=305733&view=rev>
> Log:
> Change llvm-nm for Mach-O files to use dyld info in some cases when printing symbols.
> 
> In order to reduce swift binary sizes, Apple is now stripping swift symbols
> from the nlist symbol table.  llvm-nm currently only looks at the nlist symbol
> table and misses symbols that are present in dyld info.   This makes it hard to
> know the set of symbols for a binary using just llvm-nm.  Unless you know to
> run llvm-objdump -exports-trie that can output the exported symbols in the dyld
> info from the export trie, which does so but in a different format.
> 
> Also moving forward the time may come a when a fully linked Mach-O file that
> uses dyld will no longer have an nlist symbol table to avoid duplicating the
> symbol information.
> 
> This change adds three flags to llvm-nm, -add-dyldinfo, -no-dyldinfo, and
> -dyldinfo-only.
> 
> The first, -add-dyldinfo, has the same effect as when the new bit in the Mach-O
> header, MH_NLIST_OUTOFSYNC_WITH_DYLDINFO, appears in a binary.  In that it
> looks through the dyld info from the export trie and adds symbols to be printed
> that are not already in its internal SymbolList variable.  The -no-dyldinfo
> option turns this behavior off.
> 
> The -dyldinfo-only option only looks at the dyld information and recreates the
> symbol table from the dyld info from the export trie and binding information.
> As if it the Mach-O file had no nlist symbol table.
> 
> Also fixed a few bugs with Mach-O N_INDR symbols not correctly printing the
> indirect name, or in the same format as the old nm-classic program.
> 
> rdar://32021551
> 
> Added:
>     llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64   (with props)
>     llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test
> Modified:
>     llvm/trunk/include/llvm/BinaryFormat/MachO.h
>     llvm/trunk/tools/llvm-nm/llvm-nm.cpp
>     llvm/trunk/tools/llvm-objdump/MachODump.cpp
> 
> Modified: llvm/trunk/include/llvm/BinaryFormat/MachO.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MachO.h?rev=305733&r1=305732&r2=305733&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/BinaryFormat/MachO.h?rev=305733&r1=305732&r2=305733&view=diff>
> ==============================================================================
> --- llvm/trunk/include/llvm/BinaryFormat/MachO.h (original)
> +++ llvm/trunk/include/llvm/BinaryFormat/MachO.h Mon Jun 19 14:38:22 2017
> @@ -78,7 +78,8 @@ enum {
>    MH_DEAD_STRIPPABLE_DYLIB = 0x00400000u,
>    MH_HAS_TLV_DESCRIPTORS = 0x00800000u,
>    MH_NO_HEAP_EXECUTION = 0x01000000u,
> -  MH_APP_EXTENSION_SAFE = 0x02000000u
> +  MH_APP_EXTENSION_SAFE = 0x02000000u,
> +  MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000u
>  };
> 
>  enum : uint32_t {
> 
> Added: llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64?rev=305733&view=auto <http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64?rev=305733&view=auto>
> ==============================================================================
> Binary file - no diff available.
> 
> Propchange: llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64
> ------------------------------------------------------------------------------
>     svn:executable = *
> 
> Propchange: llvm/trunk/test/tools/llvm-nm/X86/Inputs/Strip-ST.dylib.macho-x86_64
> ------------------------------------------------------------------------------
>     svn:mime-type = application/octet-stream
> 
> Added: llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test?rev=305733&view=auto <http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test?rev=305733&view=auto>
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test (added)
> +++ llvm/trunk/test/tools/llvm-nm/X86/dyldinfo.test Mon Jun 19 14:38:22 2017
> @@ -0,0 +1,18 @@
> +# RUN: llvm-nm %p/Inputs/Strip-ST.dylib.macho-x86_64 | FileCheck --check-prefix=DEFAULT %s
> +# RUN: llvm-nm -no-dyldinfo %p/Inputs/Strip-ST.dylib.macho-x86_64 | FileCheck --check-prefix=NO-DYLDINFO %s
> +# RUN: llvm-nm -dyldinfo-only %p/Inputs/Strip-ST.dylib.macho-x86_64 | FileCheck --check-prefix=DYLDINFO-ONLY %s
> +
> +# DEFAULT: 0000000000000f90 T __Bob_is_slow
> +# DEFAULT: 0000000000001008 D __T0ims_data
> +# DEFAULT: 0000000000000f80 T __T0om_is_not_swift
> +# DEFAULT: U dyld_stub_binder
> +
> +# NO-DYLDINFO: 0000000000000f90 T __Bob_is_slow
> +# NO-DYLDINFO-NOT: __T0ims_data
> +# NO-DYLDINFO-NOT: __T0om_is_not_swift
> +# NO-DYLDINFO: U dyld_stub_binder
> +
> +# DYLDINFO-ONLY: 0000000000000f90 T __Bob_is_slow
> +# DYLDINFO-ONLY: 0000000000001008 D __T0ims_data
> +# DYLDINFO-ONLY: 0000000000000f80 T __T0om_is_not_swift
> +# DYLDINFO-ONLY-NOT: U dyld_stub_binder
> 
> Modified: llvm/trunk/tools/llvm-nm/llvm-nm.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-nm/llvm-nm.cpp?rev=305733&r1=305732&r2=305733&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-nm/llvm-nm.cpp?rev=305733&r1=305732&r2=305733&view=diff>
> ==============================================================================
> --- llvm/trunk/tools/llvm-nm/llvm-nm.cpp (original)
> +++ llvm/trunk/tools/llvm-nm/llvm-nm.cpp Mon Jun 19 14:38:22 2017
> @@ -167,6 +167,15 @@ cl::list<std::string> SegSect("s", cl::P
> 
>  cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, "
>                                               "Mach-O only"), cl::Grouping);
> +cl::opt<bool> AddDyldInfo("add-dyldinfo",
> +                          cl::desc("Add symbols from the dyldinfo not already "
> +                                   "in the symbol table, Mach-O only"));
> +cl::opt<bool> NoDyldInfo("no-dyldinfo",
> +                         cl::desc("Don't add any symbols from the dyldinfo, "
> +                                  "Mach-O only"));
> +cl::opt<bool> DyldInfoOnly("dyldinfo-only",
> +                           cl::desc("Show only symbols from the dyldinfo, "
> +                                    "Mach-O only"));
> 
>  cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
>                              cl::desc("Disable LLVM bitcode reader"));
> @@ -247,6 +256,17 @@ struct NMSymbol {
>    char TypeChar;
>    StringRef Name;
>    BasicSymbolRef Sym;
> +  // The Sym field above points to the native symbol in the object file,
> +  // for Mach-O when we are creating symbols from the dyld info the above
> +  // pointer is null as there is no native symbol.  In these cases the fields
> +  // below are filled in to represent what would have been a Mach-O nlist
> +  // native symbol.
> +  uint32_t SymFlags;
> +  SectionRef Section;
> +  uint8_t NType;
> +  uint8_t NSect;
> +  uint16_t NDesc;
> +  StringRef IndirectName;
>  };
>  } // anonymous namespace
> 
> @@ -331,22 +351,38 @@ static void darwinPrintSymbol(SymbolicFi
>        H_64 = MachO->MachOObjectFile::getHeader64();
>        Filetype = H_64.filetype;
>        Flags = H_64.flags;
> -      MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
> -      NType = STE_64.n_type;
> -      NSect = STE_64.n_sect;
> -      NDesc = STE_64.n_desc;
> -      NStrx = STE_64.n_strx;
> -      NValue = STE_64.n_value;
> +      if (SymDRI.p){
> +        MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
> +        NType = STE_64.n_type;
> +        NSect = STE_64.n_sect;
> +        NDesc = STE_64.n_desc;
> +        NStrx = STE_64.n_strx;
> +        NValue = STE_64.n_value;
> +      } else {
> +        NType = I->NType;
> +        NSect = I->NSect;
> +        NDesc = I->NDesc;
> +        NStrx = 0;
> +        NValue = I->Address;
> +      }
>      } else {
>        H = MachO->MachOObjectFile::getHeader();
>        Filetype = H.filetype;
>        Flags = H.flags;
> -      MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
> -      NType = STE.n_type;
> -      NSect = STE.n_sect;
> -      NDesc = STE.n_desc;
> -      NStrx = STE.n_strx;
> -      NValue = STE.n_value;
> +      if (SymDRI.p){
> +        MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
> +        NType = STE.n_type;
> +        NSect = STE.n_sect;
> +        NDesc = STE.n_desc;
> +        NStrx = STE.n_strx;
> +        NValue = STE.n_value;
> +      } else {
> +        NType = I->NType;
> +        NSect = I->NSect;
> +        NDesc = I->NDesc;
> +        NStrx = 0;
> +        NValue = I->Address;
> +      }
>      }
>    }
> 
> @@ -363,7 +399,22 @@ static void darwinPrintSymbol(SymbolicFi
>      outs() << Str << ' ';
>      format("%08x", NStrx).print(Str, sizeof(Str));
>      outs() << Str << ' ';
> -    outs() << I->Name << "\n";
> +    outs() << I->Name;
> +    if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
> +      outs() << " (indirect for ";
> +      format(printFormat, NValue).print(Str, sizeof(Str));
> +      outs() << Str << ' ';
> +      StringRef IndirectName;
> +      if (I->Sym.getRawDataRefImpl().p) {
> +        if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
> +          outs() << "?)";
> +        else
> +          outs() << IndirectName << ")";
> +      }
> +      else
> +        outs() << I->IndirectName << ")";
> +    }
> +    outs() << "\n";
>      return;
>    }
> 
> @@ -419,14 +470,19 @@ static void darwinPrintSymbol(SymbolicFi
>          outs() << "(?,?) ";
>        break;
>      }
> -    Expected<section_iterator> SecOrErr =
> -      MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
> -    if (!SecOrErr) {
> -      consumeError(SecOrErr.takeError());
> -      outs() << "(?,?) ";
> -      break;
> +    section_iterator Sec = SectionRef();
> +    if (I->Sym.getRawDataRefImpl().p) {
> +      Expected<section_iterator> SecOrErr =
> +        MachO->getSymbolSection(I->Sym.getRawDataRefImpl());
> +      if (!SecOrErr) {
> +        consumeError(SecOrErr.takeError());
> +        outs() << "(?,?) ";
> +        break;
> +      }
> +      Sec = *SecOrErr;
> +    } else {
> +      Sec = I->Section;
>      }
> -    section_iterator Sec = *SecOrErr;
>      DataRefImpl Ref = Sec->getRawDataRefImpl();
>      StringRef SectionName;
>      MachO->getSectionName(Ref, SectionName);
> @@ -485,11 +541,17 @@ static void darwinPrintSymbol(SymbolicFi
>    if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
>      outs() << I->Name << " (for ";
>      StringRef IndirectName;
> -    if (!MachO ||
> -        MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
> +    if (MachO) {
> +      if (I->Sym.getRawDataRefImpl().p) {
> +        if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
> +          outs() << "?)";
> +        else
> +          outs() << IndirectName << ")";
> +      }
> +      else
> +        outs() << I->IndirectName << ")";
> +    } else
>        outs() << "?)";
> -    else
> -      outs() << IndirectName << ")";
>    } else
>      outs() << I->Name;
> 
> @@ -660,7 +722,12 @@ static void sortAndPrintSymbolList(Symbo
> 
>    for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end();
>         I != E; ++I) {
> -    uint32_t SymFlags = I->Sym.getFlags();
> +    uint32_t SymFlags;
> +    if (I->Sym.getRawDataRefImpl().p)
> +      SymFlags = I->Sym.getFlags();
> +    else
> +      SymFlags = I->SymFlags;
> +
>      bool Undefined = SymFlags & SymbolRef::SF_Undefined;
>      bool Global = SymFlags & SymbolRef::SF_Global;
>      if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
> @@ -699,10 +766,13 @@ static void sortAndPrintSymbolList(Symbo
>        }
>      }
> 
> +    MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
>      // Otherwise, print the symbol address and size.
>      if (symbolIsDefined(*I)) {
>        if (Obj.isIR())
>          strcpy(SymbolAddrStr, printDashes);
> +      else if(MachO && I->TypeChar == 'I')
> +        strcpy(SymbolAddrStr, printBlanks);
>        else
>          format(printFormat, I->Address)
>            .print(SymbolAddrStr, sizeof(SymbolAddrStr));
> @@ -714,7 +784,6 @@ static void sortAndPrintSymbolList(Symbo
>      // nm(1) -m output or hex, else if OutputFormat is darwin or we are
>      // printing Mach-O symbols in hex and not a Mach-O object fall back to
>      // OutputFormat bsd (see below).
> -    MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
>      if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
>        darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes,
>                          printFormat);
> @@ -734,7 +803,19 @@ static void sortAndPrintSymbolList(Symbo
>        outs() << I->TypeChar;
>        if (I->TypeChar == '-' && MachO)
>          darwinPrintStab(MachO, I);
> -      outs() << " " << I->Name << "\n";
> +      outs() << " " << I->Name;
> +      if (I->TypeChar == 'I' && MachO) {
> +        outs() << " (indirect for ";
> +        if (I->Sym.getRawDataRefImpl().p) {
> +          StringRef IndirectName;
> +          if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName))
> +            outs() << "?)";
> +          else
> +            outs() << IndirectName << ")";
> +        } else
> +          outs() << I->IndirectName << ")";
> +      }
> +      outs() << "\n";
>      } else if (OutputFormat == sysv) {
>        std::string PaddedName(I->Name);
>        while (PaddedName.length() < 20)
> @@ -1022,51 +1103,433 @@ dumpSymbolNamesFromObject(SymbolicFile &
>      if (Nsect == 0)
>        return;
>    }
> -  for (BasicSymbolRef Sym : Symbols) {
> -    uint32_t SymFlags = Sym.getFlags();
> -    if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
> -      continue;
> -    if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
> -      continue;
> -    // If a "-s segname sectname" option was specified and this is a Mach-O
> -    // file and this section appears in this file, Nsect will be non-zero then
> -    // see if this symbol is a symbol from that section and if not skip it.
> -    if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
> -      continue;
> -    NMSymbol S;
> -    S.Size = 0;
> -    S.Address = 0;
> -    if (PrintSize) {
> -      if (isa<ELFObjectFileBase>(&Obj))
> -        S.Size = ELFSymbolRef(Sym).getSize();
> -    }
> -    if (PrintAddress && isa<ObjectFile>(Obj)) {
> -      SymbolRef SymRef(Sym);
> -      Expected<uint64_t> AddressOrErr = SymRef.getAddress();
> -      if (!AddressOrErr) {
> -        consumeError(AddressOrErr.takeError());
> -        break;
> +  if (!MachO || !DyldInfoOnly) {
> +    for (BasicSymbolRef Sym : Symbols) {
> +      uint32_t SymFlags = Sym.getFlags();
> +      if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
> +        continue;
> +      if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
> +        continue;
> +      // If a "-s segname sectname" option was specified and this is a Mach-O
> +      // file and this section appears in this file, Nsect will be non-zero then
> +      // see if this symbol is a symbol from that section and if not skip it.
> +      if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
> +        continue;
> +      NMSymbol S;
> +      S.Size = 0;
> +      S.Address = 0;
> +      if (PrintSize) {
> +        if (isa<ELFObjectFileBase>(&Obj))
> +          S.Size = ELFSymbolRef(Sym).getSize();
> +      }
> +      if (PrintAddress && isa<ObjectFile>(Obj)) {
> +        SymbolRef SymRef(Sym);
> +        Expected<uint64_t> AddressOrErr = SymRef.getAddress();
> +        if (!AddressOrErr) {
> +          consumeError(AddressOrErr.takeError());
> +          break;
> +        }
> +        S.Address = *AddressOrErr;
>        }
> -      S.Address = *AddressOrErr;
> +      S.TypeChar = getNMTypeChar(Obj, Sym);
> +      std::error_code EC = Sym.printName(OS);
> +      if (EC && MachO)
> +        OS << "bad string index";
> +      else
> +        error(EC);
> +      OS << '\0';
> +      S.Sym = Sym;
> +      SymbolList.push_back(S);
>      }
> -    S.TypeChar = getNMTypeChar(Obj, Sym);
> -    std::error_code EC = Sym.printName(OS);
> -    if (EC && MachO)
> -      OS << "bad string index";
> -    else
> -      error(EC);
> -    OS << '\0';
> -    S.Sym = Sym;
> -    SymbolList.push_back(S);
>    }
> 
>    OS.flush();
>    const char *P = NameBuffer.c_str();
> -  for (unsigned I = 0; I < SymbolList.size(); ++I) {
> +  unsigned I;
> +  for (I = 0; I < SymbolList.size(); ++I) {
>      SymbolList[I].Name = P;
>      P += strlen(P) + 1;
>    }
> 
> +  // If this is a Mach-O file where the nlist symbol table is out of sync
> +  // with the dyld export trie then look through exports and fake up symbols
> +  // for the ones that are missing (also done with the -add-dyldinfo flag).
> +  // This is needed if strip(1) -T is run on a binary containing swift
> +  // language symbols for example.  The option -only-dyldinfo will fake up
> +  // all symbols from the dyld export trie as well as the bind info.
> +  std::string ExportsNameBuffer;
> +  raw_string_ostream EOS(ExportsNameBuffer);
> +  std::string BindsNameBuffer;
> +  raw_string_ostream BOS(BindsNameBuffer);
> +  std::string LazysNameBuffer;
> +  raw_string_ostream LOS(LazysNameBuffer);
> +  std::string WeaksNameBuffer;
> +  raw_string_ostream WOS(WeaksNameBuffer);
> +  if (MachO && !NoDyldInfo) {
> +    MachO::mach_header H;
> +    MachO::mach_header_64 H_64;
> +    uint32_t HFlags = 0;
> +    if (MachO->is64Bit()) {
> +      H_64 = MachO->MachOObjectFile::getHeader64();
> +      HFlags = H_64.flags;
> +    } else {
> +      H = MachO->MachOObjectFile::getHeader();
> +      HFlags = H.flags;
> +    }
> +    uint64_t BaseSegmentAddress = 0;
> +    for (const auto &Command : MachO->load_commands()) {
> +      if (Command.C.cmd == MachO::LC_SEGMENT) {
> +        MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
> +        if (Seg.fileoff == 0 && Seg.filesize != 0) {
> +          BaseSegmentAddress = Seg.vmaddr;
> +          break;
> +        }
> +      } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
> +        MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
> +        if (Seg.fileoff == 0 && Seg.filesize != 0) {
> +          BaseSegmentAddress = Seg.vmaddr;
> +          break;
> +        }
> +      }
> +    }
> +    if (DyldInfoOnly || AddDyldInfo ||
> +        HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
> +      unsigned ExportsAdded = 0;
> +      for (const llvm::object::ExportEntry &Entry : MachO->exports()) {
> +        bool found = false;
> +        bool ReExport = false;
> +        if (!DyldInfoOnly) {
> +          for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
> +            if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress &&
> +                SymbolList[J].Name == Entry.name())
> +              found = true;
> +          }
> +        }
> +        if (!found) {
> +          NMSymbol S;
> +          S.Address = Entry.address() + BaseSegmentAddress;
> +          S.Size = 0;
> +          S.TypeChar = '\0';
> +          S.Name = Entry.name();
> +          // There is no symbol in the nlist symbol table for this so we set
> +          // Sym effectivly to null and the rest of code in here must test for
> +          // it and not do things like Sym.getFlags() for it.
> +          S.Sym = BasicSymbolRef();
> +          S.SymFlags = SymbolRef::SF_Global;
> +          S.Section = SectionRef();
> +          S.NType = 0;
> +          S.NSect = 0;
> +          S.NDesc = 0;
> +          S.IndirectName = StringRef();
> +
> +          uint64_t EFlags = Entry.flags();
> +          bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
> +                      MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
> +          bool Resolver = (EFlags &
> +                           MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
> +          ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
> +          bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
> +          if (WeakDef)
> +            S.NDesc |= MachO::N_WEAK_DEF;
> +          if (Abs) {
> +            S.NType = MachO::N_EXT | MachO::N_ABS;
> +            S.TypeChar = 'A';
> +          } else if (ReExport) {
> +            S.NType = MachO::N_EXT | MachO::N_INDR;
> +            S.TypeChar = 'I';
> +          } else {
> +            S.NType = MachO::N_EXT | MachO::N_SECT;
> +            if (Resolver) {
> +              S.Address = Entry.other() + BaseSegmentAddress;
> +              if ((S.Address & 1) != 0 &&
> +                  !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
> +                S.Address &= ~1LL;
> +                S.NDesc |= MachO::N_ARM_THUMB_DEF;
> +              }
> +            } else {
> +              S.Address = Entry.address() + BaseSegmentAddress;
> +            }
> +            StringRef SegmentName = StringRef();
> +            StringRef SectionName = StringRef();
> +            for (const SectionRef &Section : MachO->sections()) {
> +              S.NSect++;
> +              Section.getName(SectionName);
> +              SegmentName = MachO->getSectionFinalSegmentName(
> +                                                  Section.getRawDataRefImpl());
> +              if (S.Address >= Section.getAddress() &&
> +                  S.Address < Section.getAddress() + Section.getSize()) {
> +                S.Section = Section;
> +                break;
> +              } else if (Entry.name() == "__mh_execute_header" &&
> +                         SegmentName == "__TEXT" && SectionName == "__text") {
> +                S.Section = Section;
> +                S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
> +                break;
> +              }
> +            }
> +            if (SegmentName == "__TEXT" && SectionName == "__text")
> +              S.TypeChar = 'T';
> +            else if (SegmentName == "__DATA" && SectionName == "__data")
> +              S.TypeChar = 'D';
> +            else if (SegmentName == "__DATA" && SectionName == "__bss")
> +              S.TypeChar = 'B';
> +            else
> +              S.TypeChar = 'S';
> +          }
> +          SymbolList.push_back(S);
> +
> +          EOS << Entry.name();
> +          EOS << '\0';
> +          ExportsAdded++;
> +
> +          // For ReExports there are a two more things to do, first add the
> +          // indirect name and second create the undefined symbol using the
> +          // referened dynamic library.
> +          if (ReExport) {
> +
> +            // Add the indirect name.
> +            if (Entry.otherName().empty())
> +              EOS << Entry.name();
> +            else
> +              EOS << Entry.otherName();
> +            EOS << '\0';
> +
> +            // Now create the undefined symbol using the referened dynamic
> +            // library.
> +            NMSymbol U;
> +            U.Address = 0;
> +            U.Size = 0;
> +            U.TypeChar = 'U';
> +            if (Entry.otherName().empty())
> +              U.Name = Entry.name();
> +            else
> +              U.Name = Entry.otherName();
> +            // Again there is no symbol in the nlist symbol table for this so
> +            // we set Sym effectivly to null and the rest of code in here must
> +            // test for it and not do things like Sym.getFlags() for it.
> +            U.Sym = BasicSymbolRef();
> +            U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
> +            U.Section = SectionRef();
> +            U.NType = MachO::N_EXT | MachO::N_UNDF;
> +            U.NSect = 0;
> +            U.NDesc = 0;
> +            // The library ordinal for this undefined symbol is in the export
> +            // trie Entry.other().
> +            MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
> +            U.IndirectName = StringRef();
> +            SymbolList.push_back(U);
> +
> +            // Finally add the undefined symbol's name.
> +            if (Entry.otherName().empty())
> +              EOS << Entry.name();
> +            else
> +              EOS << Entry.otherName();
> +            EOS << '\0';
> +            ExportsAdded++;
> +          }
> +        }
> +      }
> +      // Set the symbol names and indirect names for the added symbols.
> +      if (ExportsAdded) {
> +        EOS.flush();
> +        const char *Q = ExportsNameBuffer.c_str();
> +        for (unsigned K = 0; K < ExportsAdded; K++) {
> +          SymbolList[I].Name = Q;
> +          Q += strlen(Q) + 1;
> +          if (SymbolList[I].TypeChar == 'I') {
> +            SymbolList[I].IndirectName = Q;
> +            Q += strlen(Q) + 1;
> +          }
> +          I++;
> +        }
> +      }
> +
> +      // Add the undefined symbols from the bind entries.
> +      unsigned BindsAdded = 0;
> +      Error BErr = Error::success();
> +      StringRef LastSymbolName = StringRef();
> +      for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
> +        bool found = false;
> +        if (LastSymbolName == Entry.symbolName())
> +          found = true;
> +        else if(!DyldInfoOnly) {
> +          for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
> +            if (SymbolList[J].Name == Entry.symbolName())
> +              found = true;
> +          }
> +        }
> +        if (!found) {
> +          LastSymbolName = Entry.symbolName();
> +          NMSymbol B;
> +          B.Address = 0;
> +          B.Size = 0;
> +          B.TypeChar = 'U';
> +          // There is no symbol in the nlist symbol table for this so we set
> +          // Sym effectivly to null and the rest of code in here must test for
> +          // it and not do things like Sym.getFlags() for it.
> +          B.Sym = BasicSymbolRef();
> +          B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
> +          B.NType = MachO::N_EXT | MachO::N_UNDF;
> +          B.NSect = 0;
> +          B.NDesc = 0;
> +          B.NDesc = 0;
> +          MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
> +          B.IndirectName = StringRef();
> +          B.Name = Entry.symbolName();
> +          SymbolList.push_back(B);
> +          BOS << Entry.symbolName();
> +          BOS << '\0';
> +          BindsAdded++;
> +        }
> +      }
> +      if (BErr)
> +        error(std::move(BErr), MachO->getFileName());
> +      // Set the symbol names and indirect names for the added symbols.
> +      if (BindsAdded) {
> +        BOS.flush();
> +        const char *Q = BindsNameBuffer.c_str();
> +        for (unsigned K = 0; K < BindsAdded; K++) {
> +          SymbolList[I].Name = Q;
> +          Q += strlen(Q) + 1;
> +          if (SymbolList[I].TypeChar == 'I') {
> +            SymbolList[I].IndirectName = Q;
> +            Q += strlen(Q) + 1;
> +          }
> +          I++;
> +        }
> +      }
> +
> +      // Add the undefined symbols from the lazy bind entries.
> +      unsigned LazysAdded = 0;
> +      Error LErr = Error::success();
> +      LastSymbolName = StringRef();
> +      for (const llvm::object::MachOBindEntry &Entry :
> +           MachO->lazyBindTable(LErr)) {
> +        bool found = false;
> +        if (LastSymbolName == Entry.symbolName())
> +          found = true;
> +        else {
> +          // Here we must check to see it this symbol is already in the
> +          // SymbolList as it might have already have been added above via a
> +          // non-lazy (bind) entry.
> +          for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
> +            if (SymbolList[J].Name == Entry.symbolName())
> +              found = true;
> +          }
> +        }
> +        if (!found) {
> +          LastSymbolName = Entry.symbolName();
> +          NMSymbol L;
> +          L.Name = Entry.symbolName();
> +          L.Address = 0;
> +          L.Size = 0;
> +          L.TypeChar = 'U';
> +          // There is no symbol in the nlist symbol table for this so we set
> +          // Sym effectivly to null and the rest of code in here must test for
> +          // it and not do things like Sym.getFlags() for it.
> +          L.Sym = BasicSymbolRef();
> +          L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
> +          L.NType = MachO::N_EXT | MachO::N_UNDF;
> +          L.NSect = 0;
> +          // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
> +          // makes sence since we are creating this from a lazy bind entry.
> +          L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
> +          MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
> +          L.IndirectName = StringRef();
> +          SymbolList.push_back(L);
> +          LOS << Entry.symbolName();
> +          LOS << '\0';
> +          LazysAdded++;
> +        }
> +      }
> +      if (LErr)
> +        error(std::move(LErr), MachO->getFileName());
> +      // Set the symbol names and indirect names for the added symbols.
> +      if (LazysAdded) {
> +        LOS.flush();
> +        const char *Q = LazysNameBuffer.c_str();
> +        for (unsigned K = 0; K < LazysAdded; K++) {
> +          SymbolList[I].Name = Q;
> +          Q += strlen(Q) + 1;
> +          if (SymbolList[I].TypeChar == 'I') {
> +            SymbolList[I].IndirectName = Q;
> +            Q += strlen(Q) + 1;
> +          }
> +          I++;
> +        }
> +      }
> +
> +      // Add the undefineds symbol from the weak bind entries which are not
> +      // strong symbols.
> +      unsigned WeaksAdded = 0;
> +      Error WErr = Error::success();
> +      LastSymbolName = StringRef();
> +      for (const llvm::object::MachOBindEntry &Entry :
> +           MachO->weakBindTable(WErr)) {
> +        bool found = false;
> +        unsigned J = 0;
> +        if (LastSymbolName == Entry.symbolName() ||
> +            Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
> +          found = true;
> +        } else {
> +          for (J = 0; J < SymbolList.size() && !found; ++J) {
> +            if (SymbolList[J].Name == Entry.symbolName()) {
> +               found = true;
> +               break;
> +            }
> +          }
> +        }
> +        if (!found) {
> +          LastSymbolName = Entry.symbolName();
> +          NMSymbol W;
> +          W.Name = Entry.symbolName();
> +          W.Address = 0;
> +          W.Size = 0;
> +          W.TypeChar = 'U';
> +          // There is no symbol in the nlist symbol table for this so we set
> +          // Sym effectivly to null and the rest of code in here must test for
> +          // it and not do things like Sym.getFlags() for it.
> +          W.Sym = BasicSymbolRef();
> +          W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
> +          W.NType = MachO::N_EXT | MachO::N_UNDF;
> +          W.NSect = 0;
> +          // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
> +          // what is created in this case by the linker when there are real
> +          // symbols in the nlist structs.
> +          W.NDesc = MachO::N_WEAK_DEF;
> +          W.IndirectName = StringRef();
> +          SymbolList.push_back(W);
> +          WOS << Entry.symbolName();
> +          WOS << '\0';
> +          WeaksAdded++;
> +        } else {
> +          // This is the case the symbol was previously been found and it could
> +          // have been added from a bind or lazy bind symbol.  If so and not
> +          // a definition also mark it as weak.
> +          if (SymbolList[J].TypeChar == 'U')
> +            // See comment above about N_WEAK_DEF.
> +            SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
> +        }
> +      }
> +      if (WErr)
> +        error(std::move(WErr), MachO->getFileName());
> +      // Set the symbol names and indirect names for the added symbols.
> +      if (WeaksAdded) {
> +        WOS.flush();
> +        const char *Q = WeaksNameBuffer.c_str();
> +        for (unsigned K = 0; K < WeaksAdded; K++) {
> +          SymbolList[I].Name = Q;
> +          Q += strlen(Q) + 1;
> +          if (SymbolList[I].TypeChar == 'I') {
> +            SymbolList[I].IndirectName = Q;
> +            Q += strlen(Q) + 1;
> +          }
> +          I++;
> +        }
> +      }
> +    }
> +  }
> +
>    CurrentFilename = Obj.getFileName();
>    sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
>  }
> @@ -1456,6 +1919,9 @@ int main(int argc, char **argv) {
>      error("bad number of arguments (must be two arguments)",
>            "for the -s option");
> 
> +  if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
> +    error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only");
> +
>    std::for_each(InputFilenames.begin(), InputFilenames.end(),
>                  dumpSymbolNamesFromFile);
> 
> 
> Modified: llvm/trunk/tools/llvm-objdump/MachODump.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=305733&r1=305732&r2=305733&view=diff <http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objdump/MachODump.cpp?rev=305733&r1=305732&r2=305733&view=diff>
> ==============================================================================
> --- llvm/trunk/tools/llvm-objdump/MachODump.cpp (original)
> +++ llvm/trunk/tools/llvm-objdump/MachODump.cpp Mon Jun 19 14:38:22 2017
> @@ -7634,6 +7634,10 @@ static void PrintMachHeader(uint32_t mag
>        outs() << " APP_EXTENSION_SAFE";
>        f &= ~MachO::MH_APP_EXTENSION_SAFE;
>      }
> +    if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
> +      outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO";
> +      f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO;
> +    }
>      if (f != 0 || flags == 0)
>        outs() << format(" 0x%08" PRIx32, f);
>    } else {
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits <http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits>
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170619/fdb15671/attachment.html>


More information about the llvm-commits mailing list