[llvm] r364427 - Add GSYM utility files along with unit tests.

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 26 11:15:11 PDT 2019


yep, the bots seem to be happy with this now.
thanks!

--kcc

On Wed, Jun 26, 2019 at 10:23 AM Greg Clayton <clayborg at gmail.com> wrote:

> $ svn commit
> Sending        lib/DebugInfo/GSYM/Range.cpp
> Transmitting file data .done
> Committing transaction...
> Committed revision 364447.
>
>
> On Jun 26, 2019, at 9:59 AM, Kostya Serebryany <kcc at google.com> wrote:
>
> Hi,
>
> I think this is causing a failure on the asan bot.
> Please fix or revert ASAP
>
>
>
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/33102/steps/check-llvm%20asan/logs/stdio
>
> Note: Google Test filter = GSYMTest.TestRanges
> [==========] Running 1 test from 1 test case.
> [----------] Global test environment set-up.
> [----------] 1 test from GSYMTest
> [ RUN      ] GSYMTest.TestRanges
> =================================================================
> ==19204==ERROR: AddressSanitizer: container-overflow on address 0x606000000390 at pc 0x00000052cde7 bp 0x7ffdbaad4740 sp 0x7ffdbaad4738
> READ of size 8 at 0x606000000390 thread T0
>     #0 0x52cde6 in endAddress /b/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/DebugInfo/GSYM/Range.h:48:40
>     #1 0x52cde6 in intersects /b/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/DebugInfo/GSYM/Range.h:58
>     #2 0x52cde6 in intersect /b/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/DebugInfo/GSYM/Range.h:61
>     #3 0x52cde6 in llvm::gsym::AddressRanges::insert(llvm::gsym::AddressRange const&) /b/sanitizer-x86_64-linux-fast/build/llvm/lib/DebugInfo/GSYM/Range.cpp:35
>     #4 0x511b8d in GSYMTest_TestRanges_Test::TestBody() /b/sanitizer-x86_64-linux-fast/build/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp:350:10
>
>
> On Wed, Jun 26, 2019 at 7:09 AM Greg Clayton via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: gclayton
>> Date: Wed Jun 26 07:09:09 2019
>> New Revision: 364427
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=364427&view=rev
>> Log:
>> Add GSYM utility files along with unit tests.
>>
>> The full GSYM patch started with: https://reviews.llvm.org/D53379
>>
>> In that patch we wanted to split up getting GSYM into the LLVM code base
>> so we are not committing too much code at once.
>>
>> This is a first in a series of patches where I only add the foundation
>> classes along with complete unit tests. They provide the foundation for
>> encoding and decoding a GSYM file.
>>
>> File entries are defined in llvm::gsym::FileEntry. This class splits the
>> file up into a directory and filename represented by uniqued string table
>> offsets. This allows all files that are referred to in a GSYM file to be
>> encoded as 1 based indexes into a global file table in the GSYM file.
>>
>> Function information in stored in llvm::gsym::FunctionInfo. This object
>> represents a contiguous address range that has a name and range with an
>> optional line table and inline call stack information.
>>
>> Line table entries are defined in llvm::gsym::LineEntry. They store only
>> address, file and line information to keep the line tables simple and
>> allows the information to be efficiently encoded in a subsequent patch.
>>
>> Inline information is defined in llvm::gsym::InlineInfo. These structs
>> store the name of the inline function, along with one or more address
>> ranges, and the file and line that called this function. They also contain
>> any child inline information.
>>
>> There are also utility classes for address ranges in
>> llvm::gsym::AddressRange, and string table support in
>> llvm::gsym::StringTable which are simple classes.
>>
>> The unit tests test all the APIs on these simple classes so they will be
>> ready for the next patches where we will create GSYM files and parse GSYM
>> files.
>>
>> Differential Revision: https://reviews.llvm.org/D63104
>>
>>
>>
>> Added:
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/FileEntry.h
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/FunctionInfo.h
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/InlineInfo.h
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/LineEntry.h
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/Range.h
>>     llvm/trunk/include/llvm/DebugInfo/GSYM/StringTable.h
>>     llvm/trunk/lib/DebugInfo/GSYM/
>>     llvm/trunk/lib/DebugInfo/GSYM/CMakeLists.txt
>>     llvm/trunk/lib/DebugInfo/GSYM/FunctionInfo.cpp
>>     llvm/trunk/lib/DebugInfo/GSYM/InlineInfo.cpp
>>     llvm/trunk/lib/DebugInfo/GSYM/Range.cpp
>>     llvm/trunk/unittests/DebugInfo/GSYM/
>>     llvm/trunk/unittests/DebugInfo/GSYM/CMakeLists.txt
>>     llvm/trunk/unittests/DebugInfo/GSYM/GSYMTest.cpp
>> Modified:
>>     llvm/trunk/lib/DebugInfo/CMakeLists.txt
>>     llvm/trunk/unittests/DebugInfo/CMakeLists.txt
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/FileEntry.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/FileEntry.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/FileEntry.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/FileEntry.h Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,69 @@
>> +//===- FileEntry.h ----------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_FILEENTRY_H
>> +#define LLVM_DEBUGINFO_GSYM_FILEENTRY_H
>> +
>> +#include "llvm/ADT/DenseMapInfo.h"
>> +#include "llvm/ADT/Hashing.h"
>> +#include <functional>
>> +#include <stdint.h>
>> +#include <utility>
>> +
>> +namespace llvm {
>> +namespace gsym {
>> +
>> +/// Files in GSYM are contained in FileEntry structs where we split the
>> +/// directory and basename into two different strings in the string
>> +/// table. This allows paths to shared commont directory and filename
>> +/// strings and saves space.
>> +struct FileEntry {
>> +
>> +  /// Offsets in the string table.
>> +  /// @{
>> +  uint32_t Dir = 0;
>> +  uint32_t Base = 0;
>> +  /// @}
>> +
>> +  FileEntry() = default;
>> +  FileEntry(uint32_t D, uint32_t B) : Dir(D), Base(B) {}
>> +
>> +  // Implement operator== so that FileEntry can be used as key in
>> +  // unordered containers.
>> +  bool operator==(const FileEntry &RHS) const {
>> +    return Base == RHS.Base && Dir == RHS.Dir;
>> +  };
>> +  bool operator!=(const FileEntry &RHS) const {
>> +    return Base != RHS.Base || Dir != RHS.Dir;
>> +  };
>> +};
>> +
>> +} // namespace gsym
>> +
>> +template <> struct DenseMapInfo<gsym::FileEntry> {
>> +  static inline gsym::FileEntry getEmptyKey() {
>> +    const auto key = DenseMapInfo<uint32_t>::getEmptyKey();
>> +    return gsym::FileEntry(key, key);
>> +
>> +  }
>> +  static inline gsym::FileEntry getTombstoneKey() {
>> +    const auto key = DenseMapInfo<uint32_t>::getTombstoneKey();
>> +    return gsym::FileEntry(key, key);
>> +  }
>> +  static unsigned getHashValue(const gsym::FileEntry &Val) {
>> +    return
>> llvm::hash_combine(DenseMapInfo<uint32_t>::getHashValue(Val.Dir),
>> +
>> DenseMapInfo<uint32_t>::getHashValue(Val.Base));
>> +  }
>> +  static bool isEqual(const gsym::FileEntry &LHS, const gsym::FileEntry
>> &RHS) {
>> +    return LHS == RHS;
>> +  }
>> +};
>> +
>> +} // namespace llvm
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_FILEENTRY_H
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/FunctionInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/FunctionInfo.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/FunctionInfo.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/FunctionInfo.h Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,107 @@
>> +//===- FunctionInfo.h -------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_FUNCTIONINFO_H
>> +#define LLVM_DEBUGINFO_GSYM_FUNCTIONINFO_H
>> +
>> +#include "llvm/DebugInfo/GSYM/InlineInfo.h"
>> +#include "llvm/DebugInfo/GSYM/LineEntry.h"
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +#include "llvm/DebugInfo/GSYM/StringTable.h"
>> +#include <tuple>
>> +#include <vector>
>> +
>> +namespace llvm {
>> +class raw_ostream;
>> +namespace gsym {
>> +
>> +/// Function information in GSYM files encodes information for one
>> +/// contiguous address range. The name of the function is encoded as
>> +/// a string table offset and allows multiple functions with the same
>> +/// name to share the name string in the string table. Line tables are
>> +/// stored in a sorted vector of gsym::LineEntry objects and are split
>> +/// into line tables for each function. If a function has a discontiguous
>> +/// range, it will be split into two gsym::FunctionInfo objects. If the
>> +/// function has inline functions, the information will be encoded in
>> +/// the "Inline" member, see gsym::InlineInfo for more information.
>> +struct FunctionInfo {
>> +  AddressRange Range;
>> +  uint32_t Name; ///< String table offset in the string table.
>> +  std::vector<gsym::LineEntry> Lines;
>> +  InlineInfo Inline;
>> +
>> +  FunctionInfo(uint64_t Addr = 0, uint64_t Size = 0, uint32_t N = 0)
>> +      : Range(Addr, Addr + Size), Name(N) {}
>> +
>> +  bool hasRichInfo() const {
>> +    /// Returns whether we have something else than range and name. When
>> +    /// converting information from a symbol table and from debug info,
>> we
>> +    /// might end up with multiple FunctionInfo objects for the same
>> range
>> +    /// and we need to be able to tell which one is the better object to
>> use.
>> +    return !Lines.empty() || Inline.isValid();
>> +  }
>> +
>> +  bool isValid() const {
>> +    /// Address and size can be zero and there can be no line entries
>> for a
>> +    /// symbol so the only indication this entry is valid is if the name
>> is
>> +    /// not zero. This can happen when extracting information from
>> symbol
>> +    /// tables that do not encode symbol sizes. In that case only the
>> +    /// address and name will be filled in.
>> +    return Name != 0;
>> +  }
>> +
>> +  uint64_t startAddress() const { return Range.startAddress(); }
>> +  uint64_t endAddress() const { return Range.endAddress(); }
>> +  uint64_t size() const { return Range.size(); }
>> +  void setStartAddress(uint64_t Addr) { Range.setStartAddress(Addr); }
>> +  void setEndAddress(uint64_t Addr) { Range.setEndAddress(Addr); }
>> +  void setSize(uint64_t Size) { Range.setSize(Size); }
>> +
>> +  void clear() {
>> +    Range.clear();
>> +    Name = 0;
>> +    Lines.clear();
>> +    Inline.clear();
>> +  }
>> +};
>> +
>> +inline bool operator==(const FunctionInfo &LHS, const FunctionInfo &RHS)
>> {
>> +  return LHS.Range == RHS.Range && LHS.Name == RHS.Name &&
>> +         LHS.Lines == RHS.Lines && LHS.Inline == RHS.Inline;
>> +}
>> +inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS)
>> {
>> +  return !(LHS == RHS);
>> +}
>> +/// This sorting will order things consistently by address range first,
>> but then
>> +/// followed by inlining being valid and line tables. We might end up
>> with a
>> +/// FunctionInfo from debug info that will have the same range as one
>> from the
>> +/// symbol table, but we want to quickly be able to sort and use the
>> best version
>> +/// when creating the final GSYM file.
>> +inline bool operator<(const FunctionInfo &LHS, const FunctionInfo &RHS) {
>> +  // First sort by address range
>> +  if (LHS.Range != RHS.Range)
>> +    return LHS.Range < RHS.Range;
>> +
>> +  // Then sort by inline
>> +  if (LHS.Inline.isValid() != RHS.Inline.isValid())
>> +    return RHS.Inline.isValid();
>> +
>> +  // If the number of lines is the same, then compare line table entries
>> +  if (LHS.Lines.size() == RHS.Lines.size())
>> +    return LHS.Lines < RHS.Lines;
>> +  // Then sort by number of line table entries (more is better)
>> +  return LHS.Lines.size() < RHS.Lines.size();
>> +}
>> +
>> +raw_ostream &operator<<(raw_ostream &OS, const FunctionInfo &R);
>> +
>> +} // namespace gsym
>> +} // namespace llvm
>> +
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_FUNCTIONINFO_H
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/InlineInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/InlineInfo.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/InlineInfo.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/InlineInfo.h Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,77 @@
>> +//===- InlineInfo.h ---------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_INLINEINFO_H
>> +#define LLVM_DEBUGINFO_GSYM_INLINEINFO_H
>> +
>> +#include "llvm/ADT/Optional.h"
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +#include <stdint.h>
>> +#include <vector>
>> +
>> +
>> +namespace llvm {
>> +class raw_ostream;
>> +
>> +namespace gsym {
>> +
>> +/// Inline information stores the name of the inline function along with
>> +/// an array of address ranges. It also stores the call file and call
>> line
>> +/// that called this inline function. This allows us to unwind inline
>> call
>> +/// stacks back to the inline or concrete function that called this
>> +/// function. Inlined functions contained in this function are stored in
>> the
>> +/// "Children" variable. All address ranges must be sorted and all
>> address
>> +/// ranges of all children must be contained in the ranges of this
>> function.
>> +/// Any clients that encode information will need to ensure the ranges
>> are
>> +/// all contined correctly or lookups could fail. Add ranges in these
>> objects
>> +/// must be contained in the top level FunctionInfo address ranges as
>> well.
>> +struct InlineInfo {
>> +
>> +  uint32_t Name; ///< String table offset in the string table.
>> +  uint32_t CallFile; ///< 1 based file index in the file table.
>> +  uint32_t CallLine; ///< Source line number.
>> +  AddressRanges Ranges;
>> +  std::vector<InlineInfo> Children;
>> +  InlineInfo() : Name(0), CallFile(0), CallLine(0) {}
>> +  void clear() {
>> +    Name = 0;
>> +    CallFile = 0;
>> +    CallLine = 0;
>> +    Ranges.clear();
>> +    Children.clear();
>> +  }
>> +  bool isValid() const { return !Ranges.empty(); }
>> +  /// Lookup an address in the InlineInfo object
>> +  ///
>> +  /// This function is used to symbolicate an inline call stack and can
>> +  /// turn one address in the program into one or more inline call stacks
>> +  /// and have the stack trace show the original call site from
>> +  /// non-inlined code.
>> +  ///
>> +  /// \param Addr the address to lookup
>> +  /// \param InlineStack a vector of InlineInfo objects that describe the
>> +  /// inline call stack for a given address.
>> +  ///
>> +  /// \returns true if successful, false otherwise
>> +  typedef std::vector<const InlineInfo *> InlineArray;
>> +  llvm::Optional<InlineArray> getInlineStack(uint64_t Addr) const;
>> +};
>> +
>> +inline bool operator==(const InlineInfo &LHS, const InlineInfo &RHS) {
>> +  return LHS.Name == RHS.Name && LHS.CallFile == RHS.CallFile &&
>> +         LHS.CallLine == RHS.CallLine && LHS.Ranges == RHS.Ranges &&
>> +         LHS.Children == RHS.Children;
>> +}
>> +
>> +raw_ostream &operator<<(raw_ostream &OS, const InlineInfo &FI);
>> +
>> +} // namespace gsym
>> +} // namespace llvm
>> +
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_INLINEINFO_H
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/LineEntry.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/LineEntry.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/LineEntry.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/LineEntry.h Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,48 @@
>> +//===- LineEntry.h ----------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_LINEENTRY_H
>> +#define LLVM_DEBUGINFO_GSYM_LINEENTRY_H
>> +
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +
>> +namespace llvm {
>> +namespace gsym {
>> +
>> +/// Line entries are used to encode the line tables in FunctionInfo
>> objects.
>> +/// They are stored as a sorted vector of these objects and store the
>> +/// address, file and line of the line table row for a given address. The
>> +/// size of a line table entry is calculated by looking at the next entry
>> +/// in the FunctionInfo's vector of entries.
>> +struct LineEntry {
>> +  uint64_t Addr; ///< Start address of this line entry.
>> +  uint32_t File; ///< 1 based index of file in FileTable
>> +  uint32_t Line; ///< Source line number.
>> +  LineEntry(uint64_t A = 0, uint32_t F = 0, uint32_t L = 0)
>> +      : Addr(A), File(F), Line(L) {}
>> +  bool isValid() { return File != 0; }
>> +};
>> +
>> +inline raw_ostream &operator<<(raw_ostream &OS, const LineEntry &LE) {
>> +  return OS << "addr=" << HEX64(LE.Addr) << ", file=" << format("%3u",
>> LE.File)
>> +      << ", line=" << format("%3u", LE.Line);
>> +}
>> +
>> +inline bool operator==(const LineEntry &LHS, const LineEntry &RHS) {
>> +  return LHS.Addr == RHS.Addr && LHS.File == RHS.File && LHS.Line ==
>> RHS.Line;
>> +}
>> +inline bool operator!=(const LineEntry &LHS, const LineEntry &RHS) {
>> +  return !(LHS == RHS);
>> +}
>> +inline bool operator<(const LineEntry &LHS, const LineEntry &RHS) {
>> +  return LHS.Addr < RHS.Addr;
>> +}
>> +} // namespace gsym
>> +} // namespace llvm
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_LINEENTRY_H
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/Range.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/Range.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/Range.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/Range.h Wed Jun 26 07:09:09
>> 2019
>> @@ -0,0 +1,123 @@
>> +//===- AddressRange.h -------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_RANGE_H
>> +#define LLVM_DEBUGINFO_GSYM_RANGE_H
>> +
>> +#include "llvm/Support/Format.h"
>> +#include "llvm/Support/raw_ostream.h"
>> +#include <stdint.h>
>> +#include <vector>
>> +
>> +#define HEX8(v) llvm::format_hex(v, 4)
>> +#define HEX16(v) llvm::format_hex(v, 6)
>> +#define HEX32(v) llvm::format_hex(v, 10)
>> +#define HEX64(v) llvm::format_hex(v, 18)
>> +
>> +namespace llvm {
>> +class raw_ostream;
>> +
>> +namespace gsym {
>> +
>> +/// A class that represents an address range. The range is specified
>> using
>> +/// a start and an end address.
>> +class AddressRange {
>> +  uint64_t Start;
>> +  uint64_t End;
>> +public:
>> +  AddressRange(uint64_t S = 0, uint64_t E = 0) : Start(S), End(E) {}
>> +  /// Access to the size must use the size() accessor to ensure the
>> correct
>> +  /// answer. This allows an AddressRange to be constructed with invalid
>> +  /// address ranges where the end address is less that the start address
>> +  /// either because it was not set, or because of incorrect data.
>> +  uint64_t size() const { return Start < End ? End - Start : 0; }
>> +  void setStartAddress(uint64_t Addr) { Start = Addr; }
>> +  void setEndAddress(uint64_t Addr) { End = Addr; }
>> +  void setSize(uint64_t Size) { End = Start + Size; }
>> +  uint64_t startAddress() const { return Start; }
>> +  /// Access to the end address must use the size() accessor to ensure
>> the
>> +  /// correct answer. This allows an AddressRange to be constructed with
>> +  /// invalid address ranges where the end address is less that the
>> start
>> +  /// address either because it was not set, or because of incorrect
>> data.
>> +  uint64_t endAddress() const { return Start + size(); }
>> +  void clear() {
>> +    Start = 0;
>> +    End = 0;
>> +  }
>> +  bool contains(uint64_t Addr) const { return Start <= Addr && Addr <
>> endAddress(); }
>> +  bool isContiguousWith(const AddressRange &R) const {
>> +    return (Start <= R.endAddress()) && (endAddress() >= R.Start);
>> +  }
>> +  bool intersects(const AddressRange &R) const {
>> +    return (Start < R.endAddress()) && (endAddress() > R.Start);
>> +  }
>> +  bool intersect(const AddressRange &R) {
>> +    if (intersects(R)) {
>> +      Start = std::min<uint64_t>(Start, R.Start);
>> +      End = std::max<uint64_t>(endAddress(), R.endAddress());
>> +      return true;
>> +    }
>> +    return false;
>> +  }
>> +};
>> +
>> +inline bool operator==(const AddressRange &LHS, const AddressRange &RHS)
>> {
>> +  return LHS.startAddress() == RHS.startAddress() && LHS.endAddress() ==
>> RHS.endAddress();
>> +}
>> +inline bool operator!=(const AddressRange &LHS, const AddressRange &RHS)
>> {
>> +  return LHS.startAddress() != RHS.startAddress() || LHS.endAddress() !=
>> RHS.endAddress();
>> +}
>> +inline bool operator<(const AddressRange &LHS, const AddressRange &RHS) {
>> +  if (LHS.startAddress() == RHS.startAddress())
>> +    return LHS.endAddress() < RHS.endAddress();
>> +  return LHS.startAddress() < RHS.startAddress();
>> +}
>> +inline bool operator<(const AddressRange &LHS, uint64_t Addr) {
>> +  return LHS.startAddress() < Addr;
>> +}
>> +inline bool operator<(uint64_t Addr, const AddressRange &RHS) {
>> +  return Addr < RHS.startAddress();
>> +}
>> +
>> +raw_ostream &operator<<(raw_ostream &OS, const AddressRange &R);
>> +
>> +/// The AddressRanges class helps normalize address range collections.
>> +/// This class keeps a sorted vector of AddressRange objects and can
>> perform
>> +/// insertions and searches efficiently. The address ranges are always
>> sorted
>> +/// and never contain any invalid or empty address ranges. This allows
>> us to
>> +/// emit address ranges into the GSYM file efficiently. Intersecting
>> address
>> +/// ranges are combined during insertion so that we can emit the most
>> compact
>> +/// representation for address ranges when writing to disk.
>> +class AddressRanges {
>> +protected:
>> +  typedef std::vector<AddressRange> Collection;
>> +  Collection Ranges;
>> +public:
>> +  void clear() { Ranges.clear(); }
>> +  bool empty() const { return Ranges.empty(); }
>> +  bool contains(uint64_t Addr) const;
>> +  void insert(const AddressRange &R);
>> +  size_t size() const { return Ranges.size(); }
>> +  bool operator==(const AddressRanges &RHS) const {
>> +    return Ranges == RHS.Ranges;
>> +  }
>> +  const AddressRange &operator[](size_t i) const {
>> +    assert(i < Ranges.size());
>> +    return Ranges[i];
>> +  }
>> +  Collection::const_iterator begin() const { return Ranges.begin(); }
>> +  Collection::const_iterator end() const { return Ranges.end(); }
>> +};
>> +
>> +raw_ostream &operator<<(raw_ostream &OS, const AddressRanges &AR);
>> +
>> +} // namespace gsym
>> +} // namespace llvm
>> +
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_RANGE_H
>>
>> Added: llvm/trunk/include/llvm/DebugInfo/GSYM/StringTable.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/GSYM/StringTable.h?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/DebugInfo/GSYM/StringTable.h (added)
>> +++ llvm/trunk/include/llvm/DebugInfo/GSYM/StringTable.h Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,54 @@
>> +//===- StringTable.h --------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#ifndef LLVM_DEBUGINFO_GSYM_STRINGTABLE_H
>> +#define LLVM_DEBUGINFO_GSYM_STRINGTABLE_H
>> +
>> +#include "llvm/ADT/Optional.h"
>> +#include "llvm/ADT/StringRef.h"
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +#include <stdint.h>
>> +#include <string>
>> +
>> +
>> +namespace llvm {
>> +namespace gsym {
>> +
>> +/// String tables in GSYM files are required to start with an empty
>> +/// string at offset zero. Strings must be UTF8 NULL terminated strings.
>> +struct StringTable {
>> +  StringRef Data;
>> +  StringTable() : Data() {}
>> +  StringTable(StringRef D) : Data(D) {}
>> +  StringRef operator[](size_t Offset) const { return getString(Offset); }
>> +  StringRef getString(uint32_t Offset) const {
>> +    if (Offset < Data.size()) {
>> +      auto End = Data.find('\0', Offset);
>> +      return Data.substr(Offset, End - Offset);
>> +    }
>> +    return StringRef();
>> +  }
>> +  void clear() { Data = StringRef(); }
>> +};
>> +
>> +inline raw_ostream &operator<<(raw_ostream &OS, const StringTable &S) {
>> +  OS << "String table:\n";
>> +  uint32_t Offset = 0;
>> +  const size_t Size = S.Data.size();
>> +  while (Offset < Size) {
>> +    StringRef Str = S.getString(Offset);
>> +    OS << HEX32(Offset) << ": \"" << Str << "\"\n";
>> +    Offset += Str.size() + 1;
>> +  }
>> +  return OS;
>> +}
>> +
>> +} // namespace gsym
>> +} // namespace llvm
>> +#endif // #ifndef LLVM_DEBUGINFO_GSYM_STRINGTABLE_H
>>
>> Modified: llvm/trunk/lib/DebugInfo/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CMakeLists.txt?rev=364427&r1=364426&r2=364427&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/DebugInfo/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/DebugInfo/CMakeLists.txt Wed Jun 26 07:09:09 2019
>> @@ -1,4 +1,5 @@
>>  add_subdirectory(DWARF)
>> +add_subdirectory(GSYM)
>>  add_subdirectory(MSF)
>>  add_subdirectory(CodeView)
>>  add_subdirectory(PDB)
>>
>> Added: llvm/trunk/lib/DebugInfo/GSYM/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/GSYM/CMakeLists.txt?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/lib/DebugInfo/GSYM/CMakeLists.txt (added)
>> +++ llvm/trunk/lib/DebugInfo/GSYM/CMakeLists.txt Wed Jun 26 07:09:09 2019
>> @@ -0,0 +1,9 @@
>> +add_llvm_library(LLVMDebugInfoGSYM
>> +  FunctionInfo.cpp
>> +  InlineInfo.cpp
>> +  Range.cpp
>> +
>> +  ADDITIONAL_HEADER_DIRS
>> +  ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/GSYM
>> +  ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo
>> +  )
>>
>> Added: llvm/trunk/lib/DebugInfo/GSYM/FunctionInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/GSYM/FunctionInfo.cpp?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/lib/DebugInfo/GSYM/FunctionInfo.cpp (added)
>> +++ llvm/trunk/lib/DebugInfo/GSYM/FunctionInfo.cpp Wed Jun 26 07:09:09
>> 2019
>> @@ -0,0 +1,23 @@
>> +//===- FunctionInfo.cpp -----------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
>> +
>> +using namespace llvm;
>> +using namespace gsym;
>> +
>> +raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo
>> &FI) {
>> +  OS << '[' << HEX64(FI.Range.startAddress()) << '-'
>> +     << HEX64(FI.Range.endAddress()) << "): "
>> +     << "Name=" << HEX32(FI.Name) << '\n';
>> +  for (const auto &Line : FI.Lines)
>> +    OS << Line << '\n';
>> +  OS << FI.Inline;
>> +  return OS;
>> +}
>>
>> Added: llvm/trunk/lib/DebugInfo/GSYM/InlineInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/GSYM/InlineInfo.cpp?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/lib/DebugInfo/GSYM/InlineInfo.cpp (added)
>> +++ llvm/trunk/lib/DebugInfo/GSYM/InlineInfo.cpp Wed Jun 26 07:09:09 2019
>> @@ -0,0 +1,59 @@
>> +//===- InlineInfo.cpp -------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "llvm/DebugInfo/GSYM/FileEntry.h"
>> +#include "llvm/DebugInfo/GSYM/InlineInfo.h"
>> +#include <algorithm>
>> +#include <inttypes.h>
>> +
>> +using namespace llvm;
>> +using namespace gsym;
>> +
>> +
>> +raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const InlineInfo
>> &II) {
>> +  if (!II.isValid())
>> +    return OS;
>> +  bool First = true;
>> +  for (auto Range : II.Ranges) {
>> +    if (First)
>> +      First = false;
>> +    else
>> +      OS << ' ';
>> +    OS << Range;
>> +  }
>> +  OS << " Name = " << HEX32(II.Name) << ", CallFile = " << II.CallFile
>> +     << ", CallLine = " << II.CallFile << '\n';
>> +  for (const auto &Child : II.Children)
>> +    OS << Child;
>> +  return OS;
>> +}
>> +
>> +static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr,
>> +    std::vector<const InlineInfo *> &InlineStack) {
>> +  if (II.Ranges.contains(Addr)) {
>> +    // If this is the top level that represents the concrete function,
>> +    // there will be no name and we shoud clear the inline stack.
>> Otherwise
>> +    // we have found an inline call stack that we need to insert.
>> +    if (II.Name != 0)
>> +      InlineStack.insert(InlineStack.begin(), &II);
>> +    for (const auto &Child : II.Children) {
>> +      if (::getInlineStackHelper(Child, Addr, InlineStack))
>> +        break;
>> +    }
>> +    return !InlineStack.empty();
>> +  }
>> +  return false;
>> +}
>> +
>> +llvm::Optional<InlineInfo::InlineArray>
>> InlineInfo::getInlineStack(uint64_t Addr) const {
>> +  InlineArray Result;
>> +  if (getInlineStackHelper(*this, Addr, Result))
>> +    return Result;
>> +  return llvm::None;
>> +}
>>
>> Added: llvm/trunk/lib/DebugInfo/GSYM/Range.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/GSYM/Range.cpp?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/lib/DebugInfo/GSYM/Range.cpp (added)
>> +++ llvm/trunk/lib/DebugInfo/GSYM/Range.cpp Wed Jun 26 07:09:09 2019
>> @@ -0,0 +1,71 @@
>> +//===- Range.cpp ------------------------------------------------*- C++
>> -*-===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +#include <algorithm>
>> +#include <inttypes.h>
>> +
>> +using namespace llvm;
>> +using namespace gsym;
>> +
>> +
>> +void AddressRanges::insert(const AddressRange &Range) {
>> +  if (Range.size() == 0)
>> +    return;
>> +  // Ranges.insert(std::upper_bound(Ranges.begin(), Ranges.end(),
>> Range), Range);
>> +
>> +  // // Check if an existing range intersects with this range, and if
>> so,
>> +  // // grow the intersecting ranges instead of adding a new one.
>> +  auto Begin = Ranges.begin();
>> +  auto End = Ranges.end();
>> +  const auto Iter = std::upper_bound(Begin, End, Range);
>> +  if (Iter != Begin) {
>> +    auto PrevIter = Iter - 1;
>> +    // If the previous range itersects with "Range" they will be
>> combined.
>> +    if (PrevIter->intersect(Range)) {
>> +      // Now check if the previous range intersects with the next range
>> since
>> +      // the previous range was combined. If so, combine them and remove
>> the
>> +      // next range.
>> +      if (PrevIter->intersect(*Iter))
>> +        Ranges.erase(Iter);
>> +      return;
>> +    }
>> +  }
>> +  // If the next range intersects with "Range", combined and return.
>> +  if (Iter != End && Iter->intersect(Range))
>> +    return;
>> +  Ranges.insert(Iter, Range);
>> +}
>> +
>> +bool AddressRanges::contains(uint64_t Addr) const {
>> +  if (Ranges.empty())
>> +    return false;
>> +  auto Begin = Ranges.begin();
>> +  auto Pos = std::upper_bound(Begin, Ranges.end(), Addr);
>> +  if (Pos == Begin)
>> +    return false;
>> +  --Pos;
>> +  return Pos->contains(Addr);
>> +}
>> +
>> +raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const AddressRange
>> &R) {
>> +  return OS << '[' << HEX64(R.startAddress()) << " - " <<
>> HEX64(R.endAddress())
>> +            << ")";
>> +}
>> +
>> +raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const AddressRanges
>> &AR) {
>> +  size_t Size = AR.size();
>> +  for (size_t I=0; I<Size; ++I) {
>> +    if (I)
>> +      OS << ' ';
>> +    OS << AR[I];
>> +  }
>> +  return OS;
>> +}
>> +
>>
>> Modified: llvm/trunk/unittests/DebugInfo/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/CMakeLists.txt?rev=364427&r1=364426&r2=364427&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/unittests/DebugInfo/CMakeLists.txt (original)
>> +++ llvm/trunk/unittests/DebugInfo/CMakeLists.txt Wed Jun 26 07:09:09 2019
>> @@ -1,4 +1,5 @@
>>  add_subdirectory(CodeView)
>>  add_subdirectory(DWARF)
>> +add_subdirectory(GSYM)
>>  add_subdirectory(MSF)
>>  add_subdirectory(PDB)
>>
>> Added: llvm/trunk/unittests/DebugInfo/GSYM/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/GSYM/CMakeLists.txt?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/unittests/DebugInfo/GSYM/CMakeLists.txt (added)
>> +++ llvm/trunk/unittests/DebugInfo/GSYM/CMakeLists.txt Wed Jun 26
>> 07:09:09 2019
>> @@ -0,0 +1,15 @@
>> +set(LLVM_LINK_COMPONENTS
>> +  ${LLVM_TARGETS_TO_BUILD}
>> +  AsmPrinter
>> +  DebugInfoGSYM
>> +  MC
>> +  Object
>> +  ObjectYAML
>> +  Support
>> +  )
>> +
>> +add_llvm_unittest(DebugInfoGSYMTests
>> +  GSYMTest.cpp
>> +  )
>> +
>> +target_link_libraries(DebugInfoGSYMTests PRIVATE LLVMTestingSupport)
>>
>> Added: llvm/trunk/unittests/DebugInfo/GSYM/GSYMTest.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/DebugInfo/GSYM/GSYMTest.cpp?rev=364427&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/unittests/DebugInfo/GSYM/GSYMTest.cpp (added)
>> +++ llvm/trunk/unittests/DebugInfo/GSYM/GSYMTest.cpp Wed Jun 26 07:09:09
>> 2019
>> @@ -0,0 +1,390 @@
>> +//===- llvm/unittest/DebugInfo/GSYMTest.cpp
>> -------------------------------===//
>> +//
>> +//                     The LLVM Compiler Infrastructure
>> +//
>> +// This file is distributed under the University of Illinois Open Source
>> +// License. See LICENSE.TXT for details.
>> +//
>>
>> +//===----------------------------------------------------------------------===//
>> +
>> +#include "llvm/ADT/DenseMap.h"
>> +#include "llvm/DebugInfo/GSYM/FileEntry.h"
>> +#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
>> +#include "llvm/DebugInfo/GSYM/InlineInfo.h"
>> +#include "llvm/DebugInfo/GSYM/Range.h"
>> +#include "llvm/DebugInfo/GSYM/StringTable.h"
>> +#include "llvm/Testing/Support/Error.h"
>> +
>> +#include "gtest/gtest.h"
>> +#include <sstream>
>> +#include <string>
>> +
>> +using namespace llvm;
>> +using namespace gsym;
>> +
>> +TEST(GSYMTest, TestFileEntry) {
>> +  // Make sure default constructed GSYM FileEntry has zeroes in the
>> +  // directory and basename string table indexes.
>> +  FileEntry empty1;
>> +  FileEntry empty2;
>> +  EXPECT_EQ(empty1.Dir, 0u);
>> +  EXPECT_EQ(empty1.Base, 0u);
>> +  // Verify equality operator works
>> +  FileEntry a1(10,30);
>> +  FileEntry a2(10,30);
>> +  FileEntry b(10,40);
>> +  EXPECT_EQ(empty1, empty2);
>> +  EXPECT_EQ(a1, a2);
>> +  EXPECT_NE(a1, b);
>> +  EXPECT_NE(a1, empty1);
>> +  // Test we can use llvm::gsym::FileEntry in llvm::DenseMap.
>> +  DenseMap<FileEntry, uint32_t> EntryToIndex;
>> +  constexpr uint32_t Index1 = 1;
>> +  constexpr uint32_t Index2 = 1;
>> +  auto R = EntryToIndex.insert(std::make_pair(a1, Index1));
>> +  EXPECT_TRUE(R.second);
>> +  EXPECT_EQ(R.first->second, Index1);
>> +  R = EntryToIndex.insert(std::make_pair(a1, Index1));
>> +  EXPECT_FALSE(R.second);
>> +  EXPECT_EQ(R.first->second, Index1);
>> +  R = EntryToIndex.insert(std::make_pair(b, Index2));
>> +  EXPECT_TRUE(R.second);
>> +  EXPECT_EQ(R.first->second, Index2);
>> +  R = EntryToIndex.insert(std::make_pair(a1, Index2));
>> +  EXPECT_FALSE(R.second);
>> +  EXPECT_EQ(R.first->second, Index2);
>> +}
>> +
>> +
>> +TEST(GSYMTest, TestFunctionInfo) {
>> +  // Test GSYM FunctionInfo structs and functionality.
>> +  FunctionInfo invalid;
>> +  EXPECT_FALSE(invalid.isValid());
>> +  EXPECT_FALSE(invalid.hasRichInfo());
>> +  const uint64_t StartAddr = 0x1000;
>> +  const uint64_t EndAddr = 0x1100;
>> +  const uint64_t Size = EndAddr - StartAddr;
>> +  const uint32_t NameOffset = 30;
>> +  FunctionInfo FI(StartAddr, Size, NameOffset);
>> +  EXPECT_TRUE(FI.isValid());
>> +  EXPECT_FALSE(FI.hasRichInfo());
>> +  EXPECT_EQ(FI.startAddress(), StartAddr);
>> +  EXPECT_EQ(FI.endAddress(), EndAddr);
>> +  EXPECT_EQ(FI.size(), Size);
>> +  const uint32_t FileIdx = 1;
>> +  const uint32_t Line = 12;
>> +  FI.Lines.push_back(LineEntry(StartAddr,FileIdx,Line));
>> +  EXPECT_TRUE(FI.hasRichInfo());
>> +  FI.clear();
>> +  EXPECT_FALSE(FI.isValid());
>> +  EXPECT_FALSE(FI.hasRichInfo());
>> +
>> +  FunctionInfo A1(0x1000, 0x100, NameOffset);
>> +  FunctionInfo A2(0x1000, 0x100, NameOffset);
>> +  FunctionInfo B;
>> +  // Check == operator
>> +  EXPECT_EQ(A1, A2);
>> +  // Make sure things are not equal if they only differ by start address.
>> +  B = A2;
>> +  B.setStartAddress(0x2000);
>> +  EXPECT_NE(B, A2);
>> +  // Make sure things are not equal if they only differ by size.
>> +  B = A2;
>> +  B.setSize(0x101);
>> +  EXPECT_NE(B, A2);
>> +  // Make sure things are not equal if they only differ by name.
>> +  B = A2;
>> +  B.Name = 60;
>> +  EXPECT_NE(B, A2);
>> +  // Check < operator.
>> +  // Check less than where address differs.
>> +  B = A2;
>> +  B.setStartAddress(A2.startAddress() + 0x1000);
>> +  EXPECT_LT(A1, B);
>> +
>> +  // We use the < operator to take a variety of different FunctionInfo
>> +  // structs from a variety of sources: symtab, debug info, runtime info
>> +  // and we sort them and want the sorting to allow us to quickly get the
>> +  // best version of a function info.
>> +  FunctionInfo FISymtab(StartAddr, Size, NameOffset);
>> +  FunctionInfo FIWithLines(StartAddr, Size, NameOffset);
>> +  FIWithLines.Lines.push_back(LineEntry(StartAddr,FileIdx,Line));
>> +  // Test that a FunctionInfo with just a name and size is less than one
>> +  // that has name, size and any number of line table entries
>> +  EXPECT_LT(FISymtab, FIWithLines);
>> +
>> +  FunctionInfo FIWithLinesAndInline = FIWithLines;
>> +  FIWithLinesAndInline.Inline.Ranges.insert(AddressRange(StartAddr,
>> StartAddr + 0x10));
>> +  // Test that a FunctionInfo with name, size, and line entries is less
>> than
>> +  // the same one with valid inline info
>> +  EXPECT_LT(FIWithLines, FIWithLinesAndInline);
>> +
>> +  // Test if we have an entry with lines and one with more lines for the
>> same
>> +  // range, the ones with more lines is greater than the one with less.
>> +  FunctionInfo FIWithMoreLines = FIWithLines;
>> +  FIWithMoreLines.Lines.push_back(LineEntry(StartAddr,FileIdx,Line+5));
>> +  EXPECT_LT(FIWithLines, FIWithMoreLines);
>> +
>> +  // Test that if we have the same number of lines we compare the line
>> entries
>> +  // in the FunctionInfo.Lines vector.
>> +  FunctionInfo FIWithLinesWithHigherAddress = FIWithLines;
>> +  FIWithLinesWithHigherAddress.Lines[0].Addr += 0x10;
>> +  EXPECT_LT(FIWithLines, FIWithLinesWithHigherAddress);
>> +}
>> +
>> +TEST(GSYMTest, TestInlineInfo) {
>> +  // Test InlineInfo structs.
>> +  InlineInfo II;
>> +  EXPECT_FALSE(II.isValid());
>> +  II.Ranges.insert(AddressRange(0x1000,0x2000));
>> +  // Make sure InlineInfo in valid with just an address range since
>> +  // top level InlineInfo objects have ranges with no name, call file
>> +  // or call line
>> +  EXPECT_TRUE(II.isValid());
>> +  // Make sure InlineInfo isn't after being cleared.
>> +  II.clear();
>> +  EXPECT_FALSE(II.isValid());
>> +
>> +  // Create an InlineInfo that contains the following data. The
>> +  // indentation of the address range indicates the parent child
>> +  // relationships of the InlineInfo objects:
>> +  //
>> +  // Variable    Range and values
>> +  // =========== ====================================================
>> +  // Root        [0x100-0x200) (no name, file, or line)
>> +  // Inline1       [0x150-0x160) Name = 1, File = 1, Line = 11
>> +  // Inline1Sub1     [0x152-0x155) Name = 2, File = 2, Line = 22
>> +  // Inline1Sub2     [0x157-0x158) Name = 3, File = 3, Line = 33
>> +  InlineInfo Root;
>> +  Root.Ranges.insert(AddressRange(0x100,0x200));
>> +  InlineInfo Inline1;
>> +  Inline1.Ranges.insert(AddressRange(0x150,0x160));
>> +  Inline1.Name = 1;
>> +  Inline1.CallFile = 1;
>> +  Inline1.CallLine = 11;
>> +  InlineInfo Inline1Sub1;
>> +  Inline1Sub1.Ranges.insert(AddressRange(0x152, 0x155));
>> +  Inline1Sub1.Name = 2;
>> +  Inline1Sub1.CallFile = 2;
>> +  Inline1Sub1.CallLine = 22;
>> +  InlineInfo Inline1Sub2;
>> +  Inline1Sub2.Ranges.insert(AddressRange(0x157,0x158));
>> +  Inline1Sub2.Name = 3;
>> +  Inline1Sub2.CallFile = 3;
>> +  Inline1Sub2.CallLine = 33;
>> +  Inline1.Children.push_back(Inline1Sub1);
>> +  Inline1.Children.push_back(Inline1Sub2);
>> +  Root.Children.push_back(Inline1);
>> +
>> +  // Make sure an address that is out of range won't match
>> +  EXPECT_FALSE(Root.getInlineStack(0x50));
>> +
>> +  // Verify that we get no inline stacks for addresses out of
>> [0x100-0x200)
>> +  EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].startAddress()-1));
>> +  EXPECT_FALSE(Root.getInlineStack(Root.Ranges[0].endAddress()));
>> +
>> +  // Verify we get no inline stack entries for addresses that are in
>> +  // [0x100-0x200) but not in [0x150-0x160)
>> +  EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].startAddress()-1));
>> +  EXPECT_FALSE(Root.getInlineStack(Inline1.Ranges[0].endAddress()));
>> +
>> +
>> +  // Verify we get one inline stack entry for addresses that are in
>> +  // [[0x150-0x160)) but not in [0x152-0x155) or [0x157-0x158)
>> +  auto InlineInfos =
>> Root.getInlineStack(Inline1.Ranges[0].startAddress());
>> +  ASSERT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 1u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1);
>> +  InlineInfos = Root.getInlineStack(Inline1.Ranges[0].endAddress()-1);
>> +  EXPECT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 1u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1);
>> +
>> +  // Verify we get two inline stack entries for addresses that are in
>> +  // [0x152-0x155)
>> +  InlineInfos =
>> Root.getInlineStack(Inline1Sub1.Ranges[0].startAddress());
>> +  EXPECT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 2u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
>> +  ASSERT_EQ(*InlineInfos->at(1), Inline1);
>> +  InlineInfos =
>> Root.getInlineStack(Inline1Sub1.Ranges[0].endAddress()-1);
>> +  EXPECT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 2u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1Sub1);
>> +  ASSERT_EQ(*InlineInfos->at(1), Inline1);
>> +
>> +  // Verify we get two inline stack entries for addresses that are in
>> +  // [0x157-0x158)
>> +  InlineInfos =
>> Root.getInlineStack(Inline1Sub2.Ranges[0].startAddress());
>> +  EXPECT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 2u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
>> +  ASSERT_EQ(*InlineInfos->at(1), Inline1);
>> +  InlineInfos =
>> Root.getInlineStack(Inline1Sub2.Ranges[0].endAddress()-1);
>> +  EXPECT_TRUE(InlineInfos);
>> +  ASSERT_EQ(InlineInfos->size(), 2u);
>> +  ASSERT_EQ(*InlineInfos->at(0), Inline1Sub2);
>> +  ASSERT_EQ(*InlineInfos->at(1), Inline1);
>> +}
>> +
>> +TEST(GSYMTest, TestLineEntry) {
>> +  // test llvm::gsym::LineEntry structs.
>> +  const uint64_t ValidAddr = 0x1000;
>> +  const uint64_t InvalidFileIdx = 0;
>> +  const uint32_t ValidFileIdx = 1;
>> +  const uint32_t ValidLine = 5;
>> +
>> +  LineEntry Invalid;
>> +  EXPECT_FALSE(Invalid.isValid());
>> +  // Make sure that an entry is invalid if it has a bad file index.
>> +  LineEntry BadFile(ValidAddr, InvalidFileIdx, ValidLine);
>> +  EXPECT_FALSE(BadFile.isValid());
>> +  // Test operators
>> +  LineEntry E1(ValidAddr, ValidFileIdx, ValidLine);
>> +  LineEntry E2(ValidAddr, ValidFileIdx, ValidLine);
>> +  LineEntry DifferentAddr(ValidAddr+1, ValidFileIdx, ValidLine);
>> +  LineEntry DifferentFile(ValidAddr, ValidFileIdx+1, ValidLine);
>> +  LineEntry DifferentLine(ValidAddr, ValidFileIdx, ValidLine+1);
>> +  EXPECT_TRUE(E1.isValid());
>> +  EXPECT_EQ(E1, E2);
>> +  EXPECT_NE(E1, DifferentAddr);
>> +  EXPECT_NE(E1, DifferentFile);
>> +  EXPECT_NE(E1, DifferentLine);
>> +  EXPECT_LT(E1, DifferentAddr);
>> +}
>> +
>> +TEST(GSYMTest, TestRanges) {
>> +  // test llvm::gsym::AddressRange.
>> +  const uint64_t StartAddr = 0x1000;
>> +  const uint64_t EndAddr = 0x2000;
>> +  // Verify constructor and API to ensure it takes start and end address.
>> +  const AddressRange Range(StartAddr, EndAddr);
>> +  EXPECT_EQ(Range.startAddress(), StartAddr);
>> +  EXPECT_EQ(Range.endAddress(), EndAddr);
>> +  EXPECT_EQ(Range.size(), EndAddr-StartAddr);
>> +
>> +  // Verify llvm::gsym::AddressRange::contains().
>> +  EXPECT_FALSE(Range.contains(0));
>> +  EXPECT_FALSE(Range.contains(StartAddr-1));
>> +  EXPECT_TRUE(Range.contains(StartAddr));
>> +  EXPECT_TRUE(Range.contains(EndAddr-1));
>> +  EXPECT_FALSE(Range.contains(EndAddr));
>> +  EXPECT_FALSE(Range.contains(UINT64_MAX));
>> +
>> +  const AddressRange RangeSame(StartAddr, EndAddr);
>> +  const AddressRange RangeDifferentStart(StartAddr+1, EndAddr);
>> +  const AddressRange RangeDifferentEnd(StartAddr, EndAddr+1);
>> +  const AddressRange RangeDifferentStartEnd(StartAddr+1, EndAddr+1);
>> +  // Test == and != with values that are the same
>> +  EXPECT_EQ(Range, RangeSame);
>> +  EXPECT_FALSE(Range != RangeSame);
>> +  // Test == and != with values that are the different
>> +  EXPECT_NE(Range, RangeDifferentStart);
>> +  EXPECT_NE(Range, RangeDifferentEnd);
>> +  EXPECT_NE(Range, RangeDifferentStartEnd);
>> +  EXPECT_FALSE(Range == RangeDifferentStart);
>> +  EXPECT_FALSE(Range == RangeDifferentEnd);
>> +  EXPECT_FALSE(Range == RangeDifferentStartEnd);
>> +
>> +  // Test "bool operator<(const AddressRange &, const AddressRange &)".
>> +  EXPECT_FALSE(Range < RangeSame);
>> +  EXPECT_FALSE(RangeSame < Range);
>> +  EXPECT_LT(Range, RangeDifferentStart);
>> +  EXPECT_LT(Range, RangeDifferentEnd);
>> +  EXPECT_LT(Range, RangeDifferentStartEnd);
>> +  // Test "bool operator<(const AddressRange &, uint64_t)"
>> +  EXPECT_LT(Range, StartAddr + 1);
>> +  // Test "bool operator<(uint64_t, const AddressRange &)"
>> +  EXPECT_LT(StartAddr - 1, Range);
>> +
>> +  // Verify llvm::gsym::AddressRange::isContiguousWith() and
>> +  // llvm::gsym::AddressRange::intersects().
>> +  const AddressRange EndsBeforeRangeStart(0, StartAddr-1);
>> +  const AddressRange EndsAtRangeStart(0, StartAddr);
>> +  const AddressRange OverlapsRangeStart(StartAddr-1, StartAddr+1);
>> +  const AddressRange InsideRange(StartAddr+1, EndAddr-1);
>> +  const AddressRange OverlapsRangeEnd(EndAddr-1, EndAddr+1);
>> +  const AddressRange StartsAtRangeEnd(EndAddr, EndAddr+0x100);
>> +  const AddressRange StartsAfterRangeEnd(EndAddr+1, EndAddr+0x100);
>> +
>> +  EXPECT_FALSE(Range.isContiguousWith(EndsBeforeRangeStart));
>> +  EXPECT_TRUE(Range.isContiguousWith(EndsAtRangeStart));
>> +  EXPECT_TRUE(Range.isContiguousWith(OverlapsRangeStart));
>> +  EXPECT_TRUE(Range.isContiguousWith(InsideRange));
>> +  EXPECT_TRUE(Range.isContiguousWith(OverlapsRangeEnd));
>> +  EXPECT_TRUE(Range.isContiguousWith(StartsAtRangeEnd));
>> +  EXPECT_FALSE(Range.isContiguousWith(StartsAfterRangeEnd));
>> +
>> +  EXPECT_FALSE(Range.intersects(EndsBeforeRangeStart));
>> +  EXPECT_FALSE(Range.intersects(EndsAtRangeStart));
>> +  EXPECT_TRUE(Range.intersects(OverlapsRangeStart));
>> +  EXPECT_TRUE(Range.intersects(InsideRange));
>> +  EXPECT_TRUE(Range.intersects(OverlapsRangeEnd));
>> +  EXPECT_FALSE(Range.intersects(StartsAtRangeEnd));
>> +  EXPECT_FALSE(Range.intersects(StartsAfterRangeEnd));
>> +
>> +  // Test the functions that maintain GSYM address ranges:
>> +  //  "bool AddressRange::contains(uint64_t Addr) const;"
>> +  //  "void AddressRanges::insert(const AddressRange &R);"
>> +  AddressRanges Ranges;
>> +  Ranges.insert(AddressRange(0x1000, 0x2000));
>> +  Ranges.insert(AddressRange(0x2000, 0x3000));
>> +  Ranges.insert(AddressRange(0x4000, 0x5000));
>> +
>> +  EXPECT_FALSE(Ranges.contains(0));
>> +  EXPECT_FALSE(Ranges.contains(0x1000-1));
>> +  EXPECT_TRUE(Ranges.contains(0x1000));
>> +  EXPECT_TRUE(Ranges.contains(0x2000));
>> +  EXPECT_TRUE(Ranges.contains(0x4000));
>> +  EXPECT_TRUE(Ranges.contains(0x2000-1));
>> +  EXPECT_TRUE(Ranges.contains(0x3000-1));
>> +  EXPECT_FALSE(Ranges.contains(0x3000+1));
>> +  EXPECT_TRUE(Ranges.contains(0x5000-1));
>> +  EXPECT_FALSE(Ranges.contains(0x5000+1));
>> +  EXPECT_FALSE(Ranges.contains(UINT64_MAX));
>> +
>> +  // Verify that intersecting ranges get combined
>> +  Ranges.clear();
>> +  Ranges.insert(AddressRange(0x1100, 0x1F00));
>> +  // Verify a wholy contained range that is added doesn't do anything.
>> +  Ranges.insert(AddressRange(0x1500, 0x1F00));
>> +  EXPECT_EQ(Ranges.size(), 1u);
>> +  EXPECT_EQ(Ranges[0], AddressRange(0x1100, 0x1F00));
>> +
>> +  // Verify a range that starts before and intersects gets combined.
>> +  Ranges.insert(AddressRange(0x1000, Ranges[0].startAddress()+1));
>> +  EXPECT_EQ(Ranges.size(), 1u);
>> +  EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x1F00));
>> +
>> +  // Verify a range that starts inside and extends ranges gets combined.
>> +  Ranges.insert(AddressRange(Ranges[0].endAddress()-1, 0x2000));
>> +  EXPECT_EQ(Ranges.size(), 1u);
>> +  EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
>> +
>> +  // Verify that adjacent ranges don't get combined
>> +  Ranges.insert(AddressRange(0x2000, 0x3000));
>> +  EXPECT_EQ(Ranges.size(), 2u);
>> +  EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x2000));
>> +  EXPECT_EQ(Ranges[1], AddressRange(0x2000, 0x3000));
>> +  // Verify if we add an address range that intersects two ranges
>> +  // that they get combined
>> +  Ranges.insert(AddressRange(Ranges[0].endAddress()-1,
>> +                             Ranges[1].startAddress()+1));
>> +  EXPECT_EQ(Ranges.size(), 1u);
>> +  EXPECT_EQ(Ranges[0], AddressRange(0x1000, 0x3000));
>> +
>> +
>> +}
>> +
>> +TEST(GSYMTest, TestStringTable) {
>> +  StringTable StrTab(StringRef("\0Hello\0World\0", 13));
>> +  // Test extracting strings from a string table.
>> +  EXPECT_EQ(StrTab.getString(0), "");
>> +  EXPECT_EQ(StrTab.getString(1), "Hello");
>> +  EXPECT_EQ(StrTab.getString(7), "World");
>> +  EXPECT_EQ(StrTab.getString(8), "orld");
>> +  // Test pointing to last NULL terminator gets empty string.
>> +  EXPECT_EQ(StrTab.getString(12), "");
>> +  // Test pointing to past end gets empty string.
>> +  EXPECT_EQ(StrTab.getString(13), "");
>> +}
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> https://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/20190626/d4ea5bd5/attachment.html>


More information about the llvm-commits mailing list