[llvm] r223793 - Initial dsymutil tool commit.

Chandler Carruth chandlerc at google.com
Tue Dec 9 09:14:00 PST 2014


Please revert, see my comment on your review thread. The review had not
concluded.

On Tue, Dec 9, 2014 at 6:03 PM, Frederic Riss <friss at apple.com> wrote:

> Author: friss
> Date: Tue Dec  9 11:03:30 2014
> New Revision: 223793
>
> URL: http://llvm.org/viewvc/llvm-project?rev=223793&view=rev
> Log:
> Initial dsymutil tool commit.
>
> The goal of this tool is to replicate Darwin's dsymutil functionality
> based on LLVM. dsymutil is a DWARF linker. Darwin's linker (ld64) does
> not link the debug information, it leaves it in the object files in
> relocatable form, but embbeds a `debug map` into the executable that
> describes where to find the debug information and how to relocate it.
> When releasing/archiving a binary, dsymutil is called to link all the DWARF
> information into a `dsym bundle` that can distributed/stored along with
> the binary.
>
> With this commit, the LLVM based dsymutil is just able to parse the STABS
> debug maps embedded by ld64 in linked binaries (and not all of them, for
> example archives aren't supported yet).
>
> Note that the tool directory is called dsymutil, but the executable is
> currently called llvm-dsymutil. This discrepancy will disappear once the
> tool will be feature complete. At this point the executable will be renamed
> to dsymutil, but until then you do not want it to override the system one.
>
>     Differential Revision: http://reviews.llvm.org/D6242
>
> Added:
>     llvm/trunk/test/tools/dsymutil/
>     llvm/trunk/test/tools/dsymutil/Inputs/
>     llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64   (with
> props)
>     llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o
>     llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64   (with props)
>     llvm/trunk/test/tools/dsymutil/Inputs/basic1.c
>     llvm/trunk/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o
>     llvm/trunk/test/tools/dsymutil/Inputs/basic2.c
>     llvm/trunk/test/tools/dsymutil/Inputs/basic2.macho.x86_64.o
>     llvm/trunk/test/tools/dsymutil/Inputs/basic3.c
>     llvm/trunk/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o
>     llvm/trunk/test/tools/dsymutil/debug-map-parsing.test
>     llvm/trunk/tools/dsymutil/
>     llvm/trunk/tools/dsymutil/CMakeLists.txt
>     llvm/trunk/tools/dsymutil/DebugMap.cpp
>     llvm/trunk/tools/dsymutil/DebugMap.h
>     llvm/trunk/tools/dsymutil/DwarfLinker.cpp
>     llvm/trunk/tools/dsymutil/DwarfLinker.h
>     llvm/trunk/tools/dsymutil/LLVMBuild.txt
>       - copied, changed from r223790, llvm/trunk/tools/LLVMBuild.txt
>     llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp
>     llvm/trunk/tools/dsymutil/MachODebugMapParser.h
>     llvm/trunk/tools/dsymutil/Makefile
>     llvm/trunk/tools/dsymutil/dsymutil.cpp
> Modified:
>     llvm/trunk/tools/CMakeLists.txt
>     llvm/trunk/tools/LLVMBuild.txt
>     llvm/trunk/tools/Makefile
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64?rev=223793&view=auto
>
> ==============================================================================
> Binary files llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64
> (added) and llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64
> Tue Dec  9 11:03:30 2014 differ
>
> Propchange: llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o?rev=223793&view=auto
>
> ==============================================================================
> Binary files
> llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o (added) and
> llvm/trunk/test/tools/dsymutil/Inputs/basic-lto.macho.x86_64.o Tue Dec  9
> 11:03:30 2014 differ
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64?rev=223793&view=auto
>
> ==============================================================================
> Binary files llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64
> (added) and llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64 Tue
> Dec  9 11:03:30 2014 differ
>
> Propchange: llvm/trunk/test/tools/dsymutil/Inputs/basic.macho.x86_64
>
> ------------------------------------------------------------------------------
>     svn:executable = *
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic1.c
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic1.c?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/dsymutil/Inputs/basic1.c (added)
> +++ llvm/trunk/test/tools/dsymutil/Inputs/basic1.c Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,25 @@
> +/* This is the main file used to produce the basic* objects that are
> +   used for the dsymutil tests.
> +
> +   These are compiled in a couple of different ways (always on a
> +   Darwin system):
> +   Basic compilation:
> +      for FILE in basic1.c basic2.c basic3.c; do
> +         clang -g -c $FILE -o ${FILE%.c}.macho.x86_64.o
> +      done
> +      clang basic1.macho.x86_64.o basic2.macho.x86_64.o
> basic3.macho.x86_64.o -o basic.macho.x86_64 -Wl,-dead_strip
> +
> +   LTO compilation:
> +      for FILE in basic1.c basic2.c basic3.c; do
> +         clang -g -c -flto $FILE -o ${FILE%.c}-lto.o
> +      done
> +      clang basic1-lto.o basic2-lto.o basic3-lto.o -o
> basic-lto.macho.x86_64 -Wl,-object_path_lto,$PWD/basic-lto.macho.x86_64.o
> -Wl,-dead_strip
> +      rm basic1-lto.o basic2-lto.o basic3-lto.o
> +
> +*/
> +
> +int foo(int);
> +
> +int main(int argc, const char *argv[]) {
> +  return foo(argc);
> +}
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o?rev=223793&view=auto
>
> ==============================================================================
> Binary files llvm/trunk/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o
> (added) and llvm/trunk/test/tools/dsymutil/Inputs/basic1.macho.x86_64.o Tue
> Dec  9 11:03:30 2014 differ
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic2.c
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic2.c?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/dsymutil/Inputs/basic2.c (added)
> +++ llvm/trunk/test/tools/dsymutil/Inputs/basic2.c Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,22 @@
> +/* For compilation instructions see basic1.c. */
> +
> +static int baz = 42;
> +static int private_int;
> +extern volatile int val;
> +int unused_data = 1;
> +
> +int bar(int);
> +
> +void unused1() {
> +  bar(baz);
> +}
> +
> +static int inc() {
> +  return ++private_int;
> +}
> +
> +__attribute__((noinline))
> +int foo(int arg) {
> +  return bar(arg+val) + inc() + baz++;
> +}
> +
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic2.macho.x86_64.o
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic2.macho.x86_64.o?rev=223793&view=auto
>
> ==============================================================================
> Binary files llvm/trunk/test/tools/dsymutil/Inputs/basic2.macho.x86_64.o
> (added) and llvm/trunk/test/tools/dsymutil/Inputs/basic2.macho.x86_64.o Tue
> Dec  9 11:03:30 2014 differ
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic3.c
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic3.c?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/dsymutil/Inputs/basic3.c (added)
> +++ llvm/trunk/test/tools/dsymutil/Inputs/basic3.c Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,20 @@
> +/* For compilation instructions see basic1.c. */
> +
> +volatile int val;
> +
> +extern int foo(int);
> +
> +int unused2() {
> +  return foo(val);
> +}
> +
> +static int inc() {
> +  return ++val;
> +}
> +
> +__attribute__((noinline))
> +int bar(int arg) {
> +  if (arg > 42)
> +    return inc();
> +  return foo(val + arg);
> +}
>
> Added: llvm/trunk/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o?rev=223793&view=auto
>
> ==============================================================================
> Binary files llvm/trunk/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o
> (added) and llvm/trunk/test/tools/dsymutil/Inputs/basic3.macho.x86_64.o Tue
> Dec  9 11:03:30 2014 differ
>
> Added: llvm/trunk/test/tools/dsymutil/debug-map-parsing.test
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/debug-map-parsing.test?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/dsymutil/debug-map-parsing.test (added)
> +++ llvm/trunk/test/tools/dsymutil/debug-map-parsing.test Tue Dec  9
> 11:03:30 2014
> @@ -0,0 +1,48 @@
> +RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p
> %p/Inputs/basic.macho.x86_64 | FileCheck %s
> +RUN: llvm-dsymutil -v -parse-only -oso-prepend-path=%p
> %p/Inputs/basic-lto.macho.x86_64 | FileCheck %s --check-prefix=CHECK-LTO
> +RUN: llvm-dsymutil -v -parse-only %p/Inputs/basic.macho.x86_64 2>&1 |
> FileCheck %s --check-prefix=NOT-FOUND
> +RUN: not llvm-dsymutil -v -parse-only %p/Inputs/inexistant 2>&1 |
> FileCheck %s --check-prefix=NO-EXECUTABLE
> +Check that We can parse the debug map of the basic executable.
> +
> +CHECK-NOT: error
> +CHECK: DEBUG MAP:
> +CHECK: /Inputs/basic1.macho.x86_64.o:
> +CHECK:         0000000000000000 => 0000000100000ea0    _main
> +CHECK: /Inputs/basic2.macho.x86_64.o:
> +CHECK:         0000000000000310 => 0000000100001000    _baz
> +CHECK:         0000000000000020 => 0000000100000ed0    _foo
> +CHECK:         0000000000000070 => 0000000100000f20    _inc
> +CHECK:         0000000000000560 => 0000000100001008    _private_int
> +CHECK: /Inputs/basic3.macho.x86_64.o:
> +CHECK:         0000000000000020 => 0000000100000f40    _bar
> +CHECK:         0000000000000070 => 0000000100000f90    _inc
> +CHECK:         0000000000000004 => 0000000100001004    _val
> +CHECK: END DEBUG MAP
> +
> +
> +Check that we can parse the debug-map of the basic-lto executable
> +
> +CHECK-LTO-NOT: error
> +CHECK-LTO: DEBUG MAP:
> +CHECK-LTO: /Inputs/basic-lto.macho.x86_64.o:
> +CHECK-LTO:     0000000000000050 => 0000000100000f90    _bar
> +CHECK-LTO:     0000000000000658 => 0000000100001000    _baz
> +CHECK-LTO:     0000000000000010 => 0000000100000f50    _foo
> +CHECK-LTO:     0000000000000000 => 0000000100000f40    _main
> +CHECK-LTO:     00000000000008e8 => 0000000100001008    _private_int
> +CHECK-LTO:     00000000000008ec => 0000000100001004    _val
> +CHECK-LTO: END DEBUG MAP
> +
> +Check that we warn about missing object files (this presumes that the
> files aren't
> +present in the machine's /Inputs/ folder, which should be a pretty safe
> bet).
> +
> +NOT-FOUND: cannot open{{.*}}"/Inputs/basic1.macho.x86_64.o": No such file
> +NOT-FOUND: cannot open{{.*}}"/Inputs/basic2.macho.x86_64.o": No such file
> +NOT-FOUND: cannot open{{.*}}"/Inputs/basic3.macho.x86_64.o": No such file
> +NOT-FOUND: DEBUG MAP:
> +NOT-FOUND-NEXT: END DEBUG MAP
> +
> +Check that we correctly error out on invalid executatble.
> +
> +NO-EXECUTABLE: cannot parse{{.*}}/inexistant": No such file
> +NO-EXECUTABLE-NOT: DEBUG MAP
>
> Modified: llvm/trunk/tools/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/CMakeLists.txt?rev=223793&r1=223792&r2=223793&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/CMakeLists.txt (original)
> +++ llvm/trunk/tools/CMakeLists.txt Tue Dec  9 11:03:30 2014
> @@ -36,6 +36,7 @@ add_llvm_tool_subdirectory(llvm-objdump)
>  add_llvm_tool_subdirectory(llvm-readobj)
>  add_llvm_tool_subdirectory(llvm-rtdyld)
>  add_llvm_tool_subdirectory(llvm-dwarfdump)
> +add_llvm_tool_subdirectory(dsymutil)
>  add_llvm_tool_subdirectory(llvm-vtabledump)
>  if( LLVM_USE_INTEL_JITEVENTS )
>    add_llvm_tool_subdirectory(llvm-jitlistener)
>
> Modified: llvm/trunk/tools/LLVMBuild.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/LLVMBuild.txt?rev=223793&r1=223792&r2=223793&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/LLVMBuild.txt Tue Dec  9 11:03:30 2014
> @@ -16,7 +16,7 @@
>
>  ;===------------------------------------------------------------------------===;
>
>  [common]
> -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer
> llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener
> llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld
> llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder
> +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer
> llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener
> llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld
> llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
>
>  [component_0]
>  type = Group
>
> Modified: llvm/trunk/tools/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/Makefile?rev=223793&r1=223792&r2=223793&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/Makefile (original)
> +++ llvm/trunk/tools/Makefile Tue Dec  9 11:03:30 2014
> @@ -33,7 +33,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis ll
>                   macho-dump llvm-objdump llvm-readobj llvm-rtdyld \
>                   llvm-dwarfdump llvm-cov llvm-size llvm-stress
> llvm-mcmarkup \
>                   llvm-profdata llvm-symbolizer obj2yaml yaml2obj
> llvm-c-test \
> -                 llvm-vtabledump verify-uselistorder
> +                 llvm-vtabledump verify-uselistorder dsymutil
>
>  # If Intel JIT Events support is configured, build an extra tool to test
> it.
>  ifeq ($(USE_INTEL_JITEVENTS), 1)
>
> Added: llvm/trunk/tools/dsymutil/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/CMakeLists.txt?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/CMakeLists.txt (added)
> +++ llvm/trunk/tools/dsymutil/CMakeLists.txt Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,12 @@
> +set(LLVM_LINK_COMPONENTS
> +  Object
> +  Support
> +  )
> +
> +add_llvm_tool(llvm-dsymutil
> +  dsymutil.cpp
> +  DebugMap.cpp
> +  DwarfLinker.cpp
> +  MachODebugMapParser.cpp
> +  )
> +
>
> Added: llvm/trunk/tools/dsymutil/DebugMap.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DebugMap.cpp?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/DebugMap.cpp (added)
> +++ llvm/trunk/tools/dsymutil/DebugMap.cpp Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,84 @@
> +//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation
> -----===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +#include "DebugMap.h"
> +
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/Support/DataTypes.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include <algorithm>
> +
> +namespace llvm {
> +
> +using namespace llvm::object;
> +
> +DebugMapObject::DebugMapObject(StringRef ObjectFilename)
> +  : Filename(ObjectFilename) {}
> +
> +bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress,
> +                               uint64_t LinkedAddress) {
> +  auto InsertResult = Symbols.insert(std::make_pair(Name,
> +
> SymbolMapping{ObjectAddress,
> +
> LinkedAddress}));
> +  return InsertResult.second;
> +}
> +
> +void DebugMapObject::print(raw_ostream& OS) const {
> +  OS << getObjectFilename() << ":\n";
> +  // Sort the symbols in alphabetical order, like llvm-nm (and to get
> +  // deterministic output for testing).
> +  typedef StringMapEntry<SymbolMapping> MapEntryTy;
> +  std::vector<const MapEntryTy *> Entries;
> +  Entries.reserve(Symbols.getNumItems());
> +  for (auto SymIt = Symbols.begin(), End = Symbols.end(); SymIt != End;
> ++SymIt)
> +    Entries.push_back(&*SymIt);
> +  std::sort(Entries.begin(), Entries.end(),
> +            [] (const MapEntryTy *LHS, const MapEntryTy *RHS) {
> +              return LHS->getKey() < RHS->getKey();
> +            });
> +  for (const auto *Entry: Entries) {
> +    const auto &Sym = Entry->getValue();
> +    OS << format("\t%016" PRIx64 " => %016" PRIx64 "\t%s\n",
> +                     Sym.ObjectAddress, Sym.BinaryAddress,
> Entry->getKeyData());
> +  }
> +  OS << '\n';
> +}
> +
> +#ifndef NDEBUG
> +void DebugMapObject::dump() const {
> +  print(errs());
> +}
> +#endif
> +
> +DebugMapObject& DebugMap::addDebugMapObject(StringRef ObjectFilePath) {
> +  Objects.emplace_back(new DebugMapObject(ObjectFilePath));
> +  return *Objects.back();
> +}
> +
> +const DebugMapObject::SymbolMapping *
> +DebugMapObject::lookupSymbol(StringRef SymbolName) const {
> +  StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
> +  if (Sym == Symbols.end())
> +    return nullptr;
> +  return &Sym->getValue();
> +}
> +
> +void DebugMap::print(raw_ostream& OS) const {
> +  OS << "DEBUG MAP:   object addr =>  executable addr\tsymbol name\n";
> +  for (const auto &Obj: objects())
> +    Obj->print(OS);
> +  OS << "END DEBUG MAP\n";
> +}
> +
> +#ifndef NDEBUG
> +void DebugMap::dump() const {
> +  print(errs());
> +}
> +#endif
> +}
>
> Added: llvm/trunk/tools/dsymutil/DebugMap.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DebugMap.h?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/DebugMap.h (added)
> +++ llvm/trunk/tools/dsymutil/DebugMap.h Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,131 @@
> +//===- tools/dsymutil/DebugMap.h - Generic debug map representation
> -------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// This file contains the class declaration of the DebugMap
> +/// entity. A DebugMap lists all the object files linked together to
> +/// produce an executable along with the linked address of all the
> +/// atoms used in these object files.
> +/// The DebugMap is an input to the DwarfLinker class that will
> +/// extract the Dwarf debug information from the referenced object
> +/// files and link their usefull debug info together.
> +///
>
> +//===----------------------------------------------------------------------===//
> +#ifndef DSYMUTIL_DEBUGMAP_H
> +#define DSYMUTIL_DEBUGMAP_H
> +
> +#include "llvm/ADT/StringMap.h"
> +#include "llvm/Object/ObjectFile.h"
> +#include "llvm/Support/ErrorOr.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/ADT/iterator_range.h"
> +#include <vector>
> +
> +namespace llvm {
> +
> +class raw_ostream;
> +
> +class DebugMapObject;
> +
> +/// \brief The DebugMap object stores the list of object files to
> +/// query for debug information along with the mapping between the
> +/// symbols' addresses in the object file to their linked address in
> +/// the linked binary.
> +///
> +/// A DebugMap producer could look like this:
> +/// DebugMap *DM = new DebugMap();
> +/// for (const auto &Obj: LinkedObjects) {
> +///     DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath());
> +///     for (const auto &Sym: Obj.getLinkedSymbols())
> +///         DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(),
> +///                       Sym.getBinaryAddress());
> +/// }
> +///
> +/// A DebugMap consumer can then use the map to link the debug
> +/// information. For example something along the lines of:
> +/// for (const auto &DMO: DM->objects()) {
> +///     auto Obj = createBinary(DMO.getObjectFilename());
> +///     for (auto &DIE: Obj.getDwarfDIEs()) {
> +///         if (SymbolMapping *Sym = DMO.lookup(DIE.getName()))
> +///             DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress);
> +///         else
> +///             DIE.discardSubtree();
> +///     }
> +/// }
> +class DebugMap
> +{
> +  typedef std::vector<std::unique_ptr<DebugMapObject>> ObjectContainer;
> +  ObjectContainer Objects;
> +
> +public:
> +  typedef ObjectContainer::const_iterator const_iterator;
> +
> +  iterator_range<const_iterator> objects() const {
> +    return make_range(begin(), end());
> +  }
> +
> +  const_iterator begin() const {
> +    return Objects.begin();
> +  }
> +
> +  const_iterator end() const {
> +    return Objects.end();
> +  }
> +
> +  /// This function adds an DebugMapObject to the list owned by this
> +  /// debug map.
> +  DebugMapObject& addDebugMapObject(StringRef ObjectFilePath);
> +
> +  void print(raw_ostream& OS) const;
> +
> +#ifndef NDEBUG
> +  void dump() const;
> +#endif
> +};
> +
> +/// \brief The DebugMapObject represents one object file described by
> +/// the DebugMap. It contains a list of mappings between addresses in
> +/// the object file and in the linked binary for all the linked atoms
> +/// in this object file.
> +class DebugMapObject {
> +public:
> +  struct SymbolMapping {
> +    uint64_t ObjectAddress;
> +    uint64_t BinaryAddress;
> +  };
> +
> +  /// \brief Adds a symbol mapping to this DebugMapObject.
> +  /// \returns false if the symbol was already registered. The request
> +  /// is discarded in this case.
> +  bool addSymbol(llvm::StringRef SymName, uint64_t ObjectAddress,
> +                 uint64_t LinkedAddress);
> +
> +  /// \bried Lookup a symbol mapping.
> +  /// \returns null if the symbol isn't found.
> +  const SymbolMapping *lookupSymbol(StringRef SymbolName) const;
> +
> +  llvm::StringRef getObjectFilename() const { return Filename; }
> +
> +  void print(raw_ostream& OS) const;
> +#ifndef NDEBUG
> +  void dump() const;
> +#endif
> +private:
> +  friend class DebugMap;
> +  /// DebugMapObjects can only be constructed by the owning DebugMap.
> +  DebugMapObject(StringRef ObjectFilename);
> +
> +  std::string Filename;
> +  StringMap<SymbolMapping> Symbols;
> +};
> +
> +}
> +
> +#endif // DSYMUTIL_DEBUGMAP_H
>
> Added: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (added)
> +++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,22 @@
> +//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker
> -----------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +#include "DwarfLinker.h"
> +#include "DebugMap.h"
> +
> +namespace llvm {
> +
> +DwarfLinker::DwarfLinker(StringRef OutputFilename)
> +  : OutputFilename(OutputFilename)
> +{}
> +
> +bool DwarfLinker::link(const DebugMap &Map) {
> +  return true;
> +}
> +
> +}
>
> Added: llvm/trunk/tools/dsymutil/DwarfLinker.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.h?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/DwarfLinker.h (added)
> +++ llvm/trunk/tools/dsymutil/DwarfLinker.h Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,40 @@
> +//===- tools/dsymutil/DwarfLinker.h - Dwarf debug info linker
> -------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// This file contains the class declaration of the DwarfLinker
> +/// object. A DwarfLinker takes a DebugMap as input and links the
> +/// debug information of all the referenced object files together. It
> +/// may drop and rewrite some parts of the debug info tree in the
> +/// process.
> +///
>
> +//===----------------------------------------------------------------------===//
> +#ifndef DSYMUTIL_DWARFLINKER_H
> +#define DSYMUTIL_DWARFLINKER_H
> +
> +#include "llvm/ADT/StringRef.h"
> +
> +namespace llvm {
> +
> +class DebugMap;
> +
> +class DwarfLinker {
> +  std::string OutputFilename;
> +public:
> +  DwarfLinker(StringRef OutputFilename);
> +
> +  /// \brief Link the passed debug map into the ouptut file.
> +  /// \returns false if the link encountered a fatal error.
> +  bool link(const DebugMap&);
> +};
> +
> +}
> +
> +#endif
>
> Copied: llvm/trunk/tools/dsymutil/LLVMBuild.txt (from r223790,
> llvm/trunk/tools/LLVMBuild.txt)
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/LLVMBuild.txt?p2=llvm/trunk/tools/dsymutil/LLVMBuild.txt&p1=llvm/trunk/tools/LLVMBuild.txt&r1=223790&r2=223793&rev=223793&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/dsymutil/LLVMBuild.txt Tue Dec  9 11:03:30 2014
> @@ -1,4 +1,4 @@
> -;===- ./tools/LLVMBuild.txt ------------------------------------*- Conf
> -*--===;
> +;===- ./tools/dsymutil/LLVMBuild.txt ---------------------*- Conf -*--===;
>  ;
>  ;                     The LLVM Compiler Infrastructure
>  ;
> @@ -15,10 +15,8 @@
>  ;
>
>  ;===------------------------------------------------------------------------===;
>
> -[common]
> -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer
> llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener
> llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld
> llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder
> -
>  [component_0]
> -type = Group
> -name = Tools
> -parent = $ROOT
> +type = Tool
> +name = dsymutil
> +parent = Tools
> +required_libraries = Object Support
>
> Added: llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp (added)
> +++ llvm/trunk/tools/dsymutil/MachODebugMapParser.cpp Tue Dec  9 11:03:30
> 2014
> @@ -0,0 +1,194 @@
> +//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps
> ----===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "MachODebugMapParser.h"
> +#include "llvm/Support/Path.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +using namespace llvm::object;
> +
> +namespace llvm {
> +
> +static void Warning(const Twine &Msg) { errs() << "warning: " + Msg +
> "\n"; }
> +
> +static ErrorOr<OwningBinary<MachOObjectFile>> createMachOBinary(StringRef
> file) {
> +  ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
> +  if (BinaryOrErr.getError())
> +    return BinaryOrErr.getError();
> +
> +  std::unique_ptr<Binary> Bin;
> +  std::unique_ptr<MemoryBuffer> Buf;
> +  std::tie(Bin, Buf) = BinaryOrErr->takeBinary();
> +  if (!isa<MachOObjectFile>(Bin.get()))
> +    return make_error_code(object_error::invalid_file_type);
> +
> +  std::unique_ptr<MachOObjectFile>
> MachOFile(cast<MachOObjectFile>(Bin.release()));
> +  return OwningBinary<MachOObjectFile>(std::move(MachOFile),
> std::move(Buf));
> +}
> +
> +/// Reset the parser state coresponding to the current object
> +/// file. This is to be called after an object file is finished
> +/// processing.
> +void MachODebugMapParser::resetParserState() {
> +  CurrentObjectFile = OwningBinary<object::MachOObjectFile>();
> +  CurrentObjectAddresses.clear();
> +  CurrentDebugMapObject = nullptr;
> +}
> +
> +/// Create a new DebugMapObject. This function resets the state of the
> +/// parser that was referring to the last object file and sets
> +/// everything up to add symbols to the new one.
> +void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) {
> +  resetParserState();
> +
> +  std::string Path = Filename;
> +  if (!PathPrefix.empty())
> +    Path = PathPrefix + sys::path::get_separator().data() + Path;
> +
> +  auto MachOOrError = createMachOBinary(Path);
> +  if (auto Error = MachOOrError.getError()) {
> +    Warning(Twine("cannot open debug object \"") + Path + "\": "
> +            + Error.message() + "\n");
> +    return;
> +  }
> +
> +  CurrentObjectFile = std::move(*MachOOrError);
> +  loadCurrentObjectFileSymbols();
> +  CurrentDebugMapObject = &Result->addDebugMapObject(Path);
> +}
> +
> +/// This main parsing routine tries to open the main binary and if
> +/// successful iterates over the STAB entries. The real parsing is
> +/// done in handleStabSymbolTableEntry.
> +ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
> +  auto MainBinaryOrError = createMachOBinary(BinaryPath);
> +  if (MainBinaryOrError.getError())
> +    return MainBinaryOrError.getError();
> +
> +  MainOwningBinary = std::move(*MainBinaryOrError);
> +  Result = make_unique<DebugMap>();
> +  const auto &MainBinary = *MainOwningBinary.getBinary();
> +  for (const SymbolRef &Symbol : MainBinary.symbols()) {
> +    const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
> +    if (MainBinary.is64Bit())
> +      handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI));
> +    else
> +      handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI));
> +  }
> +
> +  resetParserState();
> +  return std::move(Result);
> +}
> +
> +/// Interpret the STAB entries to fill the DebugMap.
> +void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
> +                                                     uint8_t Type,
> +                                                     uint8_t SectionIndex,
> +                                                     uint16_t Flags,
> +                                                     uint64_t Value) {
> +  if (!(Type & MachO::N_STAB))
> +    return;
> +
> +  const MachOObjectFile &MachOBinary = *MainOwningBinary.getBinary();
> +  const char *Name =
> &MachOBinary.getStringTableData().data()[StringIndex];
> +
> +  // An N_OSO entry represents the start of a new object file description.
> +  if (Type == MachO::N_OSO)
> +    return switchToNewDebugMapObject(Name);
> +
> +  // If the last N_OSO object file wasn't found,
> +  // CurrentDebugMapObject will be null. Do not update anything
> +  // until we find the next valid N_OSO entry.
> +  if (!CurrentDebugMapObject)
> +    return;
> +
> +  switch (Type) {
> +  case MachO::N_GSYM:
> +    // This is a global variable. We need to query the main binary
> +    // symbol table to find its address as it might not be in the
> +    // debug map (for common symbols).
> +    Value = getMainBinarySymbolAddress(Name);
> +    if (Value == UnknownAddressOrSize)
> +      return;
> +    break;
> +  case MachO::N_FUN:
> +    // Functions are scopes in STABS. They have an end marker that we
> +    // need to ignore.
> +    if (Name[0] == '\0')
> +      return;
> +    break;
> +  case MachO::N_STSYM:
> +    break;
> +  default:
> +    return;
> +  }
> +
> +  auto ObjectSymIt = CurrentObjectAddresses.find(Name);
> +  if (ObjectSymIt == CurrentObjectAddresses.end())
> +    return Warning("could not find object file symbol for symbol " +
> +                   Twine(Name));
> +  if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(),
> Value))
> +    return Warning(Twine("failed to insert symbol '") + Name + "' in the
> debug map.");
> +}
> +
> +/// Load the current object file symbols into CurrentObjectAddresses.
> +void MachODebugMapParser::loadCurrentObjectFileSymbols() {
> +  CurrentObjectAddresses.clear();
> +  const auto &Binary = *CurrentObjectFile.getBinary();
> +
> +  for (auto Sym : Binary.symbols()) {
> +    StringRef Name;
> +    uint64_t Addr;
> +    if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
> +        Sym.getName(Name))
> +      continue;
> +    CurrentObjectAddresses[Name] = Addr;
> +  }
> +}
> +
> +/// Lookup a symbol address in the main binary symbol table. The
> +/// parser only needs to query common symbols, thus not every symbol's
> +/// address is available through this function.
> +uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) {
> +  if (MainBinarySymbolAddresses.empty())
> +    loadMainBinarySymbols();
> +
> +  auto Sym = MainBinarySymbolAddresses.find(Name);
> +  if (Sym == MainBinarySymbolAddresses.end())
> +    return UnknownAddressOrSize;
> +  return Sym->second;
> +}
> +
> +/// Load the interesting main binary symbols' addresses into
> +/// MainBinarySymbolAddresses.
> +void MachODebugMapParser::loadMainBinarySymbols() {
> +  const MachOObjectFile &Binary = *MainOwningBinary.getBinary();
> +  section_iterator Section = Binary.section_end();
> +  for (const auto &Sym : Binary.symbols()) {
> +    SymbolRef::Type Type;
> +    // Skip undefined and STAB entries.
> +    if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) ||
> +        (Type & SymbolRef::ST_Unknown))
> +      continue;
> +    StringRef Name;
> +    uint64_t Addr;
> +    // The only symbols of interest are the global variables. These
> +    // are the only ones that need to be queried because the address
> +    // of common data won't be described in the debug map. All other
> +    // addresses should be fetched for the debug map.
> +    if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize ||
> +        !(Sym.getFlags() & SymbolRef::SF_Global) ||
> +        Sym.getSection(Section) || Section->isText() || Sym.getName(Name)
> ||
> +        Name.size() == 0 || Name[0] == '\0')
> +      continue;
> +    MainBinarySymbolAddresses[Name] = Addr;
> +  }
> +}
> +
> +}
>
> Added: llvm/trunk/tools/dsymutil/MachODebugMapParser.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/MachODebugMapParser.h?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/MachODebugMapParser.h (added)
> +++ llvm/trunk/tools/dsymutil/MachODebugMapParser.h Tue Dec  9 11:03:30
> 2014
> @@ -0,0 +1,76 @@
> +//===- tools/dsymutil/MachODebugMapParser.h - Parse STABS debug maps
> ------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// This file contains the class declaration for the code that parses
> STABS
> +/// debug maps that are embedded in the binaries symbol tables.
> +///
>
> +//===----------------------------------------------------------------------===//
> +#ifndef DSYMUTIL_MACHODEBUGMAPPARSER_H
> +#define DSYMUTIL_MACHODEBUGMAPPARSER_H
> +
> +#include "DebugMap.h"
> +
> +#include "llvm/ADT/StringMap.h"
> +#include "llvm/Object/MachO.h"
> +#include "llvm/Object/Error.h"
> +
> +namespace llvm {
> +
> +class MachODebugMapParser {
> +public:
> + MachODebugMapParser(StringRef BinaryPath)
> +   : BinaryPath(BinaryPath) {}
> +
> +  /// \brief Add a prefix to every object file path before trying to
> +  /// open it.
> +  void setPreprendPath(StringRef Prefix) { PathPrefix = Prefix; }
> +
> +  /// \brief Parses and returns the DebugMap of the input binary.
> +  /// \returns an error in case the provided BinaryPath doesn't exist
> +  /// or isn't of a supported type.
> +  ErrorOr<std::unique_ptr<DebugMap>> parse();
> +
> +private:
> +  std::string BinaryPath;
> +  std::string PathPrefix;
> +
> +  /// OwningBinary constructed from the BinaryPath.
> +  object::OwningBinary<object::MachOObjectFile> MainOwningBinary;
> +  /// Map of the binary symbol addresses.
> +  StringMap<uint64_t> MainBinarySymbolAddresses;
> +  /// The constructed DebugMap.
> +  std::unique_ptr<DebugMap> Result;
> +
> +  /// Handle to the currently processed object file.
> +  object::OwningBinary<object::MachOObjectFile> CurrentObjectFile;
> +  /// Map of the currently processed object file symbol addresses.
> +  StringMap<uint64_t> CurrentObjectAddresses;
> +  /// Element of the debug map corresponfing to the current object file.
> +  DebugMapObject *CurrentDebugMapObject;
> +
> +  void switchToNewDebugMapObject(StringRef Filename);
> +  void resetParserState();
> +  uint64_t getMainBinarySymbolAddress(StringRef Name);
> +  void loadMainBinarySymbols();
> +  void loadCurrentObjectFileSymbols();
> +  void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type,
> +                                  uint8_t SectionIndex, uint16_t Flags,
> +                                  uint64_t Value);
> +
> +  template <typename STEType> void handleStabDebugMapEntry(const STEType
> &STE) {
> +    handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect,
> STE.n_desc,
> +                               STE.n_value);
> +  }
> +};
> +
> +}
> +
> +#endif // DSYMUTIL_MACHODEBUGMAPPARSER_H
>
> Added: llvm/trunk/tools/dsymutil/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/Makefile?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/Makefile (added)
> +++ llvm/trunk/tools/dsymutil/Makefile Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,17 @@
> +##===- tools/dsymutil/Makefile -----------------------------*- Makefile
> -*-===##
> +#
> +#                     The LLVM Compiler Infrastructure
> +#
> +# This file is distributed under the University of Illinois Open Source
> +# License. See LICENSE.TXT for details.
> +#
>
> +##===----------------------------------------------------------------------===##
> +
> +LEVEL := ../..
> +TOOLNAME := llvm-dsymutil
> +LINK_COMPONENTS := Object Support
> +
> +# This tool has no plugins, optimize startup time.
> +TOOL_NO_EXPORTS := 1
> +
> +include $(LEVEL)/Makefile.common
>
> Added: llvm/trunk/tools/dsymutil/dsymutil.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.cpp?rev=223793&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/dsymutil/dsymutil.cpp (added)
> +++ llvm/trunk/tools/dsymutil/dsymutil.cpp Tue Dec  9 11:03:30 2014
> @@ -0,0 +1,67 @@
> +//===-- dsymutil.cpp - Debug info dumping utility for llvm
> ----------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This program is a utility that aims to be a dropin replacement for
> +// Darwin's dsymutil.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "DebugMap.h"
> +#include "DwarfLinker.h"
> +#include "MachODebugMapParser.h"
> +
> +#include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include "llvm/Support/Options.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Support/Signals.h"
> +
> +#include <string>
> +
> +static llvm::cl::opt<std::string> InputFile(llvm::cl::Positional,
> +                                            llvm::cl::desc("<input
> file>"),
> +                                            llvm::cl::init("-"));
> +
> +static llvm::cl::opt<std::string> OsoPrependPath("oso-prepend-path",
> +
>  llvm::cl::desc("<path>"));
> +
> +static llvm::cl::opt<bool> Verbose("v", llvm::cl::desc("Verbosity level"),
> +                                   llvm::cl::init(false));
> +
> +static llvm::cl::opt<bool> ParseOnly("parse-only",
> +                                     llvm::cl::desc("Only parse the debug
> map, do "
> +                                                    "not actaully link
> the DWARF."),
> +                                     llvm::cl::init(false));
> +
> +int main(int argc, char **argv) {
> +  llvm::sys::PrintStackTraceOnErrorSignal();
> +  llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
> +  llvm::llvm_shutdown_obj Shutdown;
> +
> +  llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
> +
> +  llvm::MachODebugMapParser Parser(InputFile);
> +  Parser.setPreprendPath(OsoPrependPath);
> +  llvm::ErrorOr<std::unique_ptr<llvm::DebugMap>> DebugMap =
> Parser.parse();
> +
> +  if (auto EC = DebugMap.getError()) {
> +    llvm::errs() << "error: cannot parse the debug map for \"" <<
> InputFile <<
> +      "\": " << EC.message() << '\n';
> +    return 1;
> +  }
> +
> +  if (Verbose)
> +    (*DebugMap)->print(llvm::outs());
> +
> +  if (ParseOnly)
> +    return 0;
> +
> +  llvm::DwarfLinker Linker(InputFile + ".dwarf");
> +  return !Linker.link(*DebugMap.get());
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20141209/b172ffac/attachment.html>


More information about the llvm-commits mailing list