[llvm] r240860 - [StackMaps] Add a lightweight parser for stackmap version 1 sections.

Lang Hames lhames at gmail.com
Fri Jun 26 16:56:54 PDT 2015


Author: lhames
Date: Fri Jun 26 18:56:53 2015
New Revision: 240860

URL: http://llvm.org/viewvc/llvm-project?rev=240860&view=rev
Log:
[StackMaps] Add a lightweight parser for stackmap version 1 sections.

The parser provides a convenient interface for reading llvm stackmap v1 sections
in object files.

This patch also includes a new option for llvm-readobj, '-stackmap', which uses
the parser to pretty-print stackmap sections for debugging/testing purposes.


Added:
    llvm/trunk/include/llvm/Object/StackMapParser.h
    llvm/trunk/test/Object/Inputs/stackmap.s
    llvm/trunk/test/Object/stackmap-dump.test
    llvm/trunk/tools/llvm-readobj/StackMapPrinter.h
Modified:
    llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
    llvm/trunk/tools/llvm-readobj/MachODumper.cpp
    llvm/trunk/tools/llvm-readobj/ObjDumper.h
    llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp

Added: llvm/trunk/include/llvm/Object/StackMapParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Object/StackMapParser.h?rev=240860&view=auto
==============================================================================
--- llvm/trunk/include/llvm/Object/StackMapParser.h (added)
+++ llvm/trunk/include/llvm/Object/StackMapParser.h Fri Jun 26 18:56:53 2015
@@ -0,0 +1,442 @@
+//===-------- StackMapParser.h - StackMap Parsing Support -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_STACKMAPPARSER_H
+#define LLVM_CODEGEN_STACKMAPPARSER_H
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+template <support::endianness Endianness>
+class StackMapV1Parser {
+public:
+
+  template <typename AccessorT>
+  class AccessorIterator {
+  public:
+
+    AccessorIterator(AccessorT A) : A(A) {}
+    AccessorIterator& operator++() { A = A.next(); return *this; }
+    AccessorIterator operator++(int) {
+      auto tmp = *this;
+      ++*this;
+      return tmp;
+    }
+
+    bool operator==(const AccessorIterator &Other) {
+      return A.P == Other.A.P;
+    }
+
+    bool operator!=(const AccessorIterator &Other) { return !(*this == Other); }
+
+    AccessorT& operator*() { return A; }
+    AccessorT* operator->() { return &A; }
+
+  private:
+    AccessorT A;
+  };
+
+  /// Accessor for function records.
+  class FunctionAccessor {
+    friend class StackMapV1Parser;
+  public:
+
+    /// Get the function address.
+    uint64_t getFunctionAddress() const {
+      return read<uint64_t>(P);
+    }
+
+    /// Get the function's stack size.
+    uint32_t getStackSize() const {
+      return read<uint64_t>(P + sizeof(uint64_t));
+    }
+
+  private:
+    FunctionAccessor(const uint8_t *P) : P(P) {}
+
+    const static int FunctionAccessorSize = 2 * sizeof(uint64_t);
+
+    FunctionAccessor next() const {
+      return FunctionAccessor(P + FunctionAccessorSize);
+    }
+
+    const uint8_t *P;
+  };
+
+  /// Accessor for constants.
+  class ConstantAccessor {
+    friend class StackMapV1Parser;
+  public:
+
+    /// Return the value of this constant.
+    uint64_t getValue() const { return read<uint64_t>(P); }
+
+  private:
+
+    ConstantAccessor(const uint8_t *P) : P(P) {}
+
+    const static int ConstantAccessorSize = sizeof(uint64_t);
+
+    ConstantAccessor next() const {
+      return ConstantAccessor(P + ConstantAccessorSize);
+    }
+
+    const uint8_t *P;
+  };
+
+  // Forward-declare RecordAccessor so we can friend it below.
+  class RecordAccessor;
+
+  enum class LocationKind : uint8_t {
+    Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5
+  };
+
+
+  /// Accessor for location records.
+  class LocationAccessor {
+    friend class StackMapV1Parser;
+    friend class RecordAccessor;
+  public:
+
+    /// Get the Kind for this location.
+    LocationKind getKind() const {
+      return LocationKind(P[KindOffset]);
+    }
+
+    /// Get the Dwarf register number for this location.
+    uint16_t getDwarfRegNum() const {
+      return read<uint16_t>(P + DwarfRegNumOffset);
+    }
+
+    /// Get the small-constant for this location. (Kind must be Constant).
+    uint32_t getSmallConstant() const {
+      assert(getKind() == LocationKind::Constant && "Not a small constant.");
+      return read<uint32_t>(P + SmallConstantOffset);
+    }
+
+    /// Get the constant-index for this location. (Kind must be ConstantIndex).
+    uint32_t getConstantIndex() const {
+      assert(getKind() == LocationKind::ConstantIndex &&
+             "Not a constant-index.");
+      return read<uint32_t>(P + SmallConstantOffset);
+    }
+
+    /// Get the offset for this location. (Kind must be Direct or Indirect).
+    int32_t getOffset() const {
+      assert((getKind() == LocationKind::Direct ||
+              getKind() == LocationKind::Indirect) &&
+             "Not direct or indirect.");
+      return read<int32_t>(P + SmallConstantOffset);
+    }
+
+  private:
+
+    LocationAccessor(const uint8_t *P) : P(P) {}
+
+    LocationAccessor next() const {
+      return LocationAccessor(P + LocationAccessorSize);
+    }
+
+    static const int KindOffset = 0;
+    static const int DwarfRegNumOffset = KindOffset + sizeof(uint16_t);
+    static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint16_t);
+    static const int LocationAccessorSize = sizeof(uint64_t);
+
+    const uint8_t *P;
+  };
+
+  /// Accessor for stackmap live-out fields.
+  class LiveOutAccessor {
+    friend class StackMapV1Parser;
+    friend class RecordAccessor;
+  public:
+
+    /// Get the Dwarf register number for this live-out.
+    uint16_t getDwarfRegNum() const {
+      return read<uint16_t>(P + DwarfRegNumOffset);
+    }
+
+    /// Get the size in bytes of live [sub]register.
+    unsigned getSizeInBytes() const {
+      return read<uint8_t>(P + SizeOffset);
+    }
+
+  private:
+
+    LiveOutAccessor(const uint8_t *P) : P(P) {}
+
+    LiveOutAccessor next() const {
+      return LiveOutAccessor(P + LiveOutAccessorSize);
+    }
+
+    static const int DwarfRegNumOffset = 0;
+    static const int SizeOffset =
+      DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t);
+    static const int LiveOutAccessorSize = sizeof(uint32_t);
+
+    const uint8_t *P;
+  };
+
+  /// Accessor for stackmap records.
+  class RecordAccessor {
+    friend class StackMapV1Parser;
+  public:
+
+    typedef AccessorIterator<LocationAccessor> location_iterator;
+    typedef AccessorIterator<LiveOutAccessor> liveout_iterator;
+
+    /// Get the patchpoint/stackmap ID for this record.
+    uint64_t getID() const {
+      return read<uint64_t>(P + PatchpointIDOffset);
+    }
+
+    /// Get the instruction offset (from the start of the containing function)
+    /// for this record.
+    uint32_t getInstructionOffset() const {
+      return read<uint32_t>(P + InstructionOffsetOffset);
+    }
+
+    /// Get the number of locations contained in this record.
+    uint16_t getNumLocations() const {
+      return read<uint16_t>(P + NumLocationsOffset);
+    }
+
+    /// Get the location with the given index.
+    LocationAccessor getLocation(unsigned LocationIndex) const {
+      unsigned LocationOffset =
+        LocationListOffset + LocationIndex * LocationSize;
+      return LocationAccessor(P + LocationOffset);
+    }
+
+    /// Begin iterator for locations.
+    location_iterator location_begin() const {
+      return location_iterator(getLocation(0));
+    }
+
+    /// End iterator for locations.
+    location_iterator location_end() const {
+      return location_iterator(getLocation(getNumLocations()));
+    }
+
+    /// Iterator range for locations.
+    iterator_range<location_iterator> locations() const {
+      return make_range(location_begin(), location_end());
+    }
+
+    /// Get the number of liveouts contained in this record.
+    uint16_t getNumLiveOuts() const {
+      return read<uint16_t>(P + getNumLiveOutsOffset());
+    }
+
+    /// Get the live-out with the given index.
+    LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const {
+      unsigned LiveOutOffset =
+        getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize;
+      return LiveOutAccessor(P + LiveOutOffset);
+    }
+
+    /// Begin iterator for live-outs.
+    liveout_iterator liveouts_begin() const {
+      return liveout_iterator(getLiveOut(0));
+    }
+
+
+    /// End iterator for live-outs.
+    liveout_iterator liveouts_end() const {
+      return liveout_iterator(getLiveOut(getNumLiveOuts()));
+    }
+
+    /// Iterator range for live-outs.
+    iterator_range<liveout_iterator> liveouts() const {
+      return make_range(liveouts_begin(), liveouts_end());
+    }
+
+  private:
+
+    RecordAccessor(const uint8_t *P) : P(P) {}
+
+    unsigned getNumLiveOutsOffset() const {
+      return LocationListOffset + LocationSize * getNumLocations() +
+             sizeof(uint16_t);
+    }
+
+    unsigned getSizeInBytes() const {
+      unsigned RecordSize =
+        getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize;
+      return (RecordSize + 7) & ~0x7;
+    }
+
+    RecordAccessor next() const {
+      return RecordAccessor(P + getSizeInBytes());
+    }
+
+    static const unsigned PatchpointIDOffset = 0;
+    static const unsigned InstructionOffsetOffset =
+      PatchpointIDOffset + sizeof(uint64_t);
+    static const unsigned NumLocationsOffset =
+      InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t);
+    static const unsigned LocationListOffset =
+      NumLocationsOffset + sizeof(uint16_t);
+    static const unsigned LocationSize = sizeof(uint64_t);
+    static const unsigned LiveOutSize = sizeof(uint32_t);
+
+    const uint8_t *P;
+  };
+
+  /// Construct a parser for a version-1 stackmap. StackMap data will be read
+  /// from the given array.
+  StackMapV1Parser(ArrayRef<uint8_t> StackMapSection)
+      : StackMapSection(StackMapSection) {
+    ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize;
+
+    assert(StackMapSection[0] == 1 &&
+           "StackMapV1Parser can only parse version 1 stackmaps");
+
+    unsigned CurrentRecordOffset =
+      ConstantsListOffset + getNumConstants() * ConstantSize;
+
+    for (unsigned I = 0, E = getNumRecords(); I != E; ++I) {
+      StackMapRecordOffsets.push_back(CurrentRecordOffset);
+      CurrentRecordOffset +=
+        RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes();
+    }
+  }
+
+  typedef AccessorIterator<FunctionAccessor> function_iterator;
+  typedef AccessorIterator<ConstantAccessor> constant_iterator;
+  typedef AccessorIterator<RecordAccessor> record_iterator;
+
+  /// Get the version number of this stackmap. (Always returns 1).
+  unsigned getVersion() const { return 1; }
+
+  /// Get the number of functions in the stack map.
+  uint32_t getNumFunctions() const {
+    return read<uint32_t>(&StackMapSection[NumFunctionsOffset]);
+  }
+
+  /// Get the number of large constants in the stack map.
+  uint32_t getNumConstants() const {
+    return read<uint32_t>(&StackMapSection[NumConstantsOffset]);
+  }
+
+  /// Get the number of stackmap records in the stackmap.
+  uint32_t getNumRecords() const {
+    return read<uint32_t>(&StackMapSection[NumRecordsOffset]);
+  }
+
+  /// Return an FunctionAccessor for the given function index.
+  FunctionAccessor getFunction(unsigned FunctionIndex) const {
+    return FunctionAccessor(StackMapSection.data() +
+                            getFunctionOffset(FunctionIndex));
+  }
+
+  /// Begin iterator for functions.
+  function_iterator functions_begin() const {
+    return function_iterator(getFunction(0));
+  }
+
+  /// End iterator for functions.
+  function_iterator functions_end() const {
+    return function_iterator(
+             FunctionAccessor(StackMapSection.data() +
+                              getFunctionOffset(getNumFunctions())));
+  }
+
+  /// Iterator range for functions.
+  iterator_range<function_iterator> functions() const {
+    return make_range(functions_begin(), functions_end());
+  }
+
+  /// Return the large constant at the given index.
+  ConstantAccessor getConstant(unsigned ConstantIndex) const {
+    return ConstantAccessor(StackMapSection.data() +
+                            getConstantOffset(ConstantIndex));
+  }
+
+  /// Begin iterator for constants.
+  constant_iterator constants_begin() const {
+    return constant_iterator(getConstant(0));
+  }
+
+  /// End iterator for constants.
+  constant_iterator constants_end() const {
+    return constant_iterator(
+             ConstantAccessor(StackMapSection.data() +
+                              getConstantOffset(getNumConstants())));
+  }
+
+  /// Iterator range for constants.
+  iterator_range<constant_iterator> constants() const {
+    return make_range(constants_begin(), constants_end());
+  }
+
+  /// Return a RecordAccessor for the given record index.
+  RecordAccessor getRecord(unsigned RecordIndex) const {
+    std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex];
+    return RecordAccessor(StackMapSection.data() + RecordOffset);
+  }
+
+  /// Begin iterator for records.
+  record_iterator records_begin() const {
+    if (getNumRecords() == 0)
+      return record_iterator(RecordAccessor(nullptr));
+    return record_iterator(getRecord(0));
+  }
+
+  /// End iterator for records.
+  record_iterator records_end() const {
+    // Records need to be handled specially, since we cache the start addresses
+    // for them: We can't just compute the 1-past-the-end address, we have to
+    // look at the last record and use the 'next' method.
+    if (getNumRecords() == 0)
+      return record_iterator(RecordAccessor(nullptr));
+    return record_iterator(getRecord(getNumRecords() - 1).next());
+  }
+
+  /// Iterator range for records.
+  iterator_range<record_iterator> records() const {
+    return make_range(records_begin(), records_end());
+  }
+
+private:
+
+  template <typename T>
+  static T read(const uint8_t *P) {
+    return support::endian::read<T, Endianness, 1>(P);
+  }
+
+  static const unsigned HeaderOffset = 0;
+  static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t);
+  static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t);
+  static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t);
+  static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t);
+
+  static const unsigned FunctionSize = 2 * sizeof(uint64_t);
+  static const unsigned ConstantSize = sizeof(uint64_t);
+
+  std::size_t getFunctionOffset(unsigned FunctionIndex) const {
+    return FunctionListOffset + FunctionIndex * FunctionSize;
+  }
+
+  std::size_t getConstantOffset(unsigned ConstantIndex) const {
+    return ConstantsListOffset + ConstantIndex * ConstantSize;
+  }
+
+  ArrayRef<uint8_t> StackMapSection;
+  unsigned ConstantsListOffset;
+  std::vector<unsigned> StackMapRecordOffsets;
+};
+
+}
+
+#endif

Added: llvm/trunk/test/Object/Inputs/stackmap.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/stackmap.s?rev=240860&view=auto
==============================================================================
--- llvm/trunk/test/Object/Inputs/stackmap.s (added)
+++ llvm/trunk/test/Object/Inputs/stackmap.s Fri Jun 26 18:56:53 2015
@@ -0,0 +1,50 @@
+	.section	__TEXT,__text,regular,pure_instructions
+	.globl	_trivial_patchpoint_codegen
+	.align	4, 0x90
+_trivial_patchpoint_codegen:            ## @trivial_patchpoint_codegen
+	.fill	1
+Ltmp3:
+
+	.section	__LLVM_STACKMAPS,__llvm_stackmaps
+__LLVM_StackMaps:
+	.byte	1
+	.byte	0
+	.short	0
+	.long	1
+	.long	1
+	.long	1
+	.quad	_trivial_patchpoint_codegen
+	.quad	16
+	.quad	10000000000
+	.quad	2
+	.long	Ltmp3-_trivial_patchpoint_codegen
+	.short	0
+	.short	5
+	.byte	1
+	.byte	8
+	.short	5
+	.long	0
+	.byte	4
+	.byte	8
+	.short	0
+	.long	10
+	.byte	5
+	.byte	8
+	.short	0
+	.long	0
+	.byte	2
+	.byte	8
+	.short	4
+	.long	-8
+	.byte	3
+	.byte	8
+	.short	6
+	.long	-16
+	.short	0
+	.short	1
+	.short	7
+	.byte	0
+	.byte	8
+	.align	3
+
+.subsections_via_symbols

Added: llvm/trunk/test/Object/stackmap-dump.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/stackmap-dump.test?rev=240860&view=auto
==============================================================================
--- llvm/trunk/test/Object/stackmap-dump.test (added)
+++ llvm/trunk/test/Object/stackmap-dump.test Fri Jun 26 18:56:53 2015
@@ -0,0 +1,17 @@
+RUN: llvm-mc -triple x86_64-apple-darwin -filetype=obj -o %t %p/Inputs/stackmap.s && \
+RUN:   llvm-readobj -stackmap %t | FileCheck %s
+
+CHECK:      LLVM StackMap Version: 1
+CHECK-NEXT: Num Functions: 1
+CHECK-NEXT:   Function address: 0, stack size: 16
+CHECK-NEXT: Num Constants: 1
+CHECK-NEXT:   #1: 10000000000
+CHECK-NEXT: Num Records: 1
+CHECK-NEXT:   Record ID: 2, instruction offset: 1
+CHECK-NEXT:     5 locations:
+CHECK-NEXT:       #1: Register R#5
+CHECK-NEXT:       #2: Constant 10
+CHECK-NEXT:       #3: ConstantIndex #0 (10000000000)
+CHECK-NEXT:       #4: Direct R#4 + -8
+CHECK-NEXT:       #5: Indirect [R#6 + -16]
+CHECK-NEXT:     1 live-outs: [ R#7 (8-bytes) ]

Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=240860&r1=240859&r2=240860&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Fri Jun 26 18:56:53 2015
@@ -16,6 +16,7 @@
 #include "ARMWinEHPrinter.h"
 #include "Error.h"
 #include "ObjDumper.h"
+#include "StackMapPrinter.h"
 #include "StreamWriter.h"
 #include "Win64EHDumper.h"
 #include "llvm/ADT/DenseMap.h"
@@ -60,7 +61,7 @@ public:
   void printCOFFExports() override;
   void printCOFFDirectives() override;
   void printCOFFBaseReloc() override;
-
+  void printStackMap() const override;
 private:
   void printSymbol(const SymbolRef &Sym);
   void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
@@ -1140,3 +1141,32 @@ void COFFDumper::printCOFFBaseReloc() {
     W.printHex("Address", RVA);
   }
 }
+
+void COFFDumper::printStackMap() const {
+  object::SectionRef StackMapSection;
+  for (auto Sec : Obj->sections()) {
+    StringRef Name;
+    Sec.getName(Name);
+    if (Name == ".llvm_stackmaps") {
+      StackMapSection = Sec;
+      break;
+    }
+  }
+
+  if (StackMapSection == object::SectionRef())
+    return;
+
+  StringRef StackMapContents;
+  StackMapSection.getContents(StackMapContents);
+  ArrayRef<uint8_t> StackMapContentsArray(
+      reinterpret_cast<const uint8_t*>(StackMapContents.data()),
+      StackMapContents.size());
+
+  if (Obj->isLittleEndian())
+    prettyPrintStackMap(
+                      llvm::outs(),
+                      StackMapV1Parser<support::little>(StackMapContentsArray));
+  else
+    prettyPrintStackMap(llvm::outs(),
+                        StackMapV1Parser<support::big>(StackMapContentsArray));
+}

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=240860&r1=240859&r2=240860&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Fri Jun 26 18:56:53 2015
@@ -17,6 +17,7 @@
 #include "ARMEHABIPrinter.h"
 #include "Error.h"
 #include "ObjDumper.h"
+#include "StackMapPrinter.h"
 #include "StreamWriter.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallString.h"
@@ -61,6 +62,8 @@ public:
   void printMipsABIFlags() override;
   void printMipsReginfo() override;
 
+  void printStackMap() const override;
+
 private:
   typedef ELFFile<ELFT> ELFO;
   typedef typename ELFO::Elf_Shdr Elf_Shdr;
@@ -1494,3 +1497,25 @@ template <class ELFT> void ELFDumper<ELF
   W.printHex("Co-Proc Mask2", Reginfo->ri_cprmask[2]);
   W.printHex("Co-Proc Mask3", Reginfo->ri_cprmask[3]);
 }
+
+template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
+  const typename ELFFile<ELFT>::Elf_Shdr *StackMapSection = nullptr;
+  for (const auto &Sec : Obj->sections()) {
+    ErrorOr<StringRef> Name = Obj->getSectionName(&Sec);
+    if (*Name == ".llvm_stackmaps") {
+      StackMapSection = &Sec;
+      break;
+    }
+  }
+
+  if (!StackMapSection)
+    return;
+
+  StringRef StackMapContents;
+  ErrorOr<ArrayRef<uint8_t>> StackMapContentsArray =
+    Obj->getSectionContents(StackMapSection);
+
+  prettyPrintStackMap(
+              llvm::outs(),
+              StackMapV1Parser<ELFT::TargetEndianness>(*StackMapContentsArray));
+}

Modified: llvm/trunk/tools/llvm-readobj/MachODumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/MachODumper.cpp?rev=240860&r1=240859&r2=240860&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/MachODumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/MachODumper.cpp Fri Jun 26 18:56:53 2015
@@ -14,6 +14,7 @@
 #include "llvm-readobj.h"
 #include "Error.h"
 #include "ObjDumper.h"
+#include "StackMapPrinter.h"
 #include "StreamWriter.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
@@ -37,6 +38,7 @@ public:
   void printSymbols() override;
   void printDynamicSymbols() override;
   void printUnwindInfo() override;
+  void printStackMap() const override;
 
 private:
   template<class MachHeader>
@@ -573,3 +575,32 @@ void MachODumper::printSymbol(const Symb
 void MachODumper::printUnwindInfo() {
   W.startLine() << "UnwindInfo not implemented.\n";
 }
+
+void MachODumper::printStackMap() const {
+  object::SectionRef StackMapSection;
+  for (auto Sec : Obj->sections()) {
+    StringRef Name;
+    Sec.getName(Name);
+    if (Name == "__llvm_stackmaps") {
+      StackMapSection = Sec;
+      break;
+    }
+  }
+
+  if (StackMapSection == object::SectionRef())
+    return;
+
+  StringRef StackMapContents;
+  StackMapSection.getContents(StackMapContents);
+  ArrayRef<uint8_t> StackMapContentsArray(
+      reinterpret_cast<const uint8_t*>(StackMapContents.data()),
+      StackMapContents.size());
+
+  if (Obj->isLittleEndian())
+     prettyPrintStackMap(
+                      llvm::outs(),
+                      StackMapV1Parser<support::little>(StackMapContentsArray));
+  else
+     prettyPrintStackMap(llvm::outs(),
+                         StackMapV1Parser<support::big>(StackMapContentsArray));
+}

Modified: llvm/trunk/tools/llvm-readobj/ObjDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ObjDumper.h?rev=240860&r1=240859&r2=240860&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ObjDumper.h (original)
+++ llvm/trunk/tools/llvm-readobj/ObjDumper.h Fri Jun 26 18:56:53 2015
@@ -52,6 +52,8 @@ public:
   virtual void printCOFFDirectives() { }
   virtual void printCOFFBaseReloc() { }
 
+  virtual void printStackMap() const = 0;
+
 protected:
   StreamWriter& W;
 };

Added: llvm/trunk/tools/llvm-readobj/StackMapPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/StackMapPrinter.h?rev=240860&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-readobj/StackMapPrinter.h (added)
+++ llvm/trunk/tools/llvm-readobj/StackMapPrinter.h Fri Jun 26 18:56:53 2015
@@ -0,0 +1,80 @@
+//===-------- StackMapPrinter.h - Pretty-print stackmaps --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_READOBJ_STACKMAPPRINTER_H
+#define LLVM_TOOLS_LLVM_READOBJ_STACKMAPPRINTER_H
+
+#include "llvm/Object/StackMapParser.h"
+
+namespace llvm {
+
+// Pretty print a stackmap to the given ostream.
+template <typename OStreamT, typename StackMapParserT>
+void prettyPrintStackMap(OStreamT &OS, const StackMapParserT &SMP) {
+
+  OS << "LLVM StackMap Version: " << SMP.getVersion()
+     << "\nNum Functions: " << SMP.getNumFunctions();
+
+  // Functions:
+  for (const auto &F : SMP.functions())
+    OS << "\n  Function address: " << F.getFunctionAddress()
+       << ", stack size: " << F.getStackSize();
+
+  // Constants:
+  OS << "\nNum Constants: " << SMP.getNumConstants();
+  unsigned ConstantIndex = 0;
+  for (const auto &C : SMP.constants())
+    OS << "\n  #" << ++ConstantIndex << ": " << C.getValue();
+
+  // Records:
+  OS << "\nNum Records: " << SMP.getNumRecords();
+  for (const auto &R : SMP.records()) {
+    OS << "\n  Record ID: " << R.getID()
+       << ", instruction offset: " << R.getInstructionOffset()
+       << "\n    " << R.getNumLocations() << " locations:";
+
+    unsigned LocationIndex = 0;
+    for (const auto &Loc : R.locations()) {
+      OS << "\n      #" << ++LocationIndex << ": ";
+      switch (Loc.getKind()) {
+      case StackMapParserT::LocationKind::Register:
+        OS << "Register R#" << Loc.getDwarfRegNum();
+        break;
+      case StackMapParserT::LocationKind::Direct:
+        OS << "Direct R#" << Loc.getDwarfRegNum() << " + "
+           << Loc.getOffset();
+        break;
+      case StackMapParserT::LocationKind::Indirect:
+        OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + "
+           << Loc.getOffset() << "]";
+        break;
+      case StackMapParserT::LocationKind::Constant:
+        OS << "Constant " << Loc.getSmallConstant();
+        break;
+      case StackMapParserT::LocationKind::ConstantIndex:
+        OS << "ConstantIndex #" << Loc.getConstantIndex() << " ("
+           << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")";
+        break;
+      }
+    }
+
+    OS << "\n    " << R.getNumLiveOuts() << " live-outs: [ ";
+    for (const auto &LO : R.liveouts())
+      OS << "R#" << LO.getDwarfRegNum() << " ("
+         << LO.getSizeInBytes() << "-bytes) ";
+    OS << "]\n";
+  }
+
+ OS << "\n";
+
+}
+
+}
+
+#endif

Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=240860&r1=240859&r2=240860&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Fri Jun 26 18:56:53 2015
@@ -176,6 +176,12 @@ namespace opts {
   cl::opt<bool>
   COFFBaseRelocs("coff-basereloc",
                  cl::desc("Display the PE/COFF .reloc section"));
+
+  // -stackmap
+  cl::opt<bool>
+  PrintStackMap("stackmap",
+                cl::desc("Display contents of stackmap section"));
+
 } // namespace opts
 
 static int ReturnValue = EXIT_SUCCESS;
@@ -316,6 +322,9 @@ static void dumpObject(const ObjectFile
     Dumper->printCOFFDirectives();
   if (opts::COFFBaseRelocs)
     Dumper->printCOFFBaseReloc();
+
+  if (opts::PrintStackMap)
+    Dumper->printStackMap();
 }
 
 /// @brief Dumps each object file in \a Arc;





More information about the llvm-commits mailing list