[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