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

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 26 09:59:00 PDT 2019


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/86b89ccb/attachment.html>


More information about the llvm-commits mailing list