Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- GsymReader.h ---------------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8.  
  9. #ifndef LLVM_DEBUGINFO_GSYM_GSYMREADER_H
  10. #define LLVM_DEBUGINFO_GSYM_GSYMREADER_H
  11.  
  12. #include "llvm/ADT/ArrayRef.h"
  13. #include "llvm/DebugInfo/GSYM/FileEntry.h"
  14. #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
  15. #include "llvm/DebugInfo/GSYM/Header.h"
  16. #include "llvm/DebugInfo/GSYM/LineEntry.h"
  17. #include "llvm/DebugInfo/GSYM/StringTable.h"
  18. #include "llvm/Support/DataExtractor.h"
  19. #include "llvm/Support/Endian.h"
  20. #include "llvm/Support/ErrorOr.h"
  21. #include <inttypes.h>
  22. #include <memory>
  23. #include <stdint.h>
  24. #include <vector>
  25.  
  26. namespace llvm {
  27. class MemoryBuffer;
  28. class raw_ostream;
  29.  
  30. namespace gsym {
  31.  
  32. /// GsymReader is used to read GSYM data from a file or buffer.
  33. ///
  34. /// This class is optimized for very quick lookups when the endianness matches
  35. /// the host system. The Header, address table, address info offsets, and file
  36. /// table is designed to be mmap'ed as read only into memory and used without
  37. /// any parsing needed. If the endianness doesn't match, we swap these objects
  38. /// and tables into GsymReader::SwappedData and then point our header and
  39. /// ArrayRefs to this swapped internal data.
  40. ///
  41. /// GsymReader objects must use one of the static functions to create an
  42. /// instance: GsymReader::openFile(...) and GsymReader::copyBuffer(...).
  43.  
  44. class GsymReader {
  45.   GsymReader(std::unique_ptr<MemoryBuffer> Buffer);
  46.   llvm::Error parse();
  47.  
  48.   std::unique_ptr<MemoryBuffer> MemBuffer;
  49.   StringRef GsymBytes;
  50.   llvm::support::endianness Endian;
  51.   const Header *Hdr = nullptr;
  52.   ArrayRef<uint8_t> AddrOffsets;
  53.   ArrayRef<uint32_t> AddrInfoOffsets;
  54.   ArrayRef<FileEntry> Files;
  55.   StringTable StrTab;
  56.   /// When the GSYM file's endianness doesn't match the host system then
  57.   /// we must decode all data structures that need to be swapped into
  58.   /// local storage and set point the ArrayRef objects above to these swapped
  59.   /// copies.
  60.   struct SwappedData {
  61.     Header Hdr;
  62.     std::vector<uint8_t> AddrOffsets;
  63.     std::vector<uint32_t> AddrInfoOffsets;
  64.     std::vector<FileEntry> Files;
  65.   };
  66.   std::unique_ptr<SwappedData> Swap;
  67.  
  68. public:
  69.   GsymReader(GsymReader &&RHS);
  70.   ~GsymReader();
  71.  
  72.   /// Construct a GsymReader from a file on disk.
  73.   ///
  74.   /// \param Path The file path the GSYM file to read.
  75.   /// \returns An expected GsymReader that contains the object or an error
  76.   /// object that indicates reason for failing to read the GSYM.
  77.   static llvm::Expected<GsymReader> openFile(StringRef Path);
  78.  
  79.   /// Construct a GsymReader from a buffer.
  80.   ///
  81.   /// \param Bytes A set of bytes that will be copied and owned by the
  82.   /// returned object on success.
  83.   /// \returns An expected GsymReader that contains the object or an error
  84.   /// object that indicates reason for failing to read the GSYM.
  85.   static llvm::Expected<GsymReader> copyBuffer(StringRef Bytes);
  86.  
  87.   /// Access the GSYM header.
  88.   /// \returns A native endian version of the GSYM header.
  89.   const Header &getHeader() const;
  90.  
  91.   /// Get the full function info for an address.
  92.   ///
  93.   /// This should be called when a client will store a copy of the complete
  94.   /// FunctionInfo for a given address. For one off lookups, use the lookup()
  95.   /// function below.
  96.   ///
  97.   /// Symbolication server processes might want to parse the entire function
  98.   /// info for a given address and cache it if the process stays around to
  99.   /// service many symbolication addresses, like for parsing profiling
  100.   /// information.
  101.   ///
  102.   /// \param Addr A virtual address from the orignal object file to lookup.
  103.   ///
  104.   /// \returns An expected FunctionInfo that contains the function info object
  105.   /// or an error object that indicates reason for failing to lookup the
  106.   /// address.
  107.   llvm::Expected<FunctionInfo> getFunctionInfo(uint64_t Addr) const;
  108.  
  109.   /// Lookup an address in the a GSYM.
  110.   ///
  111.   /// Lookup just the information needed for a specific address \a Addr. This
  112.   /// function is faster that calling getFunctionInfo() as it will only return
  113.   /// information that pertains to \a Addr and allows the parsing to skip any
  114.   /// extra information encoded for other addresses. For example the line table
  115.   /// parsing can stop when a matching LineEntry has been fouhnd, and the
  116.   /// InlineInfo can stop parsing early once a match has been found and also
  117.   /// skip information that doesn't match. This avoids memory allocations and
  118.   /// is much faster for lookups.
  119.   ///
  120.   /// \param Addr A virtual address from the orignal object file to lookup.
  121.   /// \returns An expected LookupResult that contains only the information
  122.   /// needed for the current address, or an error object that indicates reason
  123.   /// for failing to lookup the address.
  124.   llvm::Expected<LookupResult> lookup(uint64_t Addr) const;
  125.  
  126.   /// Get a string from the string table.
  127.   ///
  128.   /// \param Offset The string table offset for the string to retrieve.
  129.   /// \returns The string from the strin table.
  130.   StringRef getString(uint32_t Offset) const { return StrTab[Offset]; }
  131.  
  132.   /// Get the a file entry for the suppplied file index.
  133.   ///
  134.   /// Used to convert any file indexes in the FunctionInfo data back into
  135.   /// files. This function can be used for iteration, but is more commonly used
  136.   /// for random access when doing lookups.
  137.   ///
  138.   /// \param Index An index into the file table.
  139.   /// \returns An optional FileInfo that will be valid if the file index is
  140.   /// valid, or std::nullopt if the file index is out of bounds,
  141.   std::optional<FileEntry> getFile(uint32_t Index) const {
  142.     if (Index < Files.size())
  143.       return Files[Index];
  144.     return std::nullopt;
  145.   }
  146.  
  147.   /// Dump the entire Gsym data contained in this object.
  148.   ///
  149.   /// \param  OS The output stream to dump to.
  150.   void dump(raw_ostream &OS);
  151.  
  152.   /// Dump a FunctionInfo object.
  153.   ///
  154.   /// This function will convert any string table indexes and file indexes
  155.   /// into human readable format.
  156.   ///
  157.   /// \param  OS The output stream to dump to.
  158.   ///
  159.   /// \param FI The object to dump.
  160.   void dump(raw_ostream &OS, const FunctionInfo &FI);
  161.  
  162.   /// Dump a LineTable object.
  163.   ///
  164.   /// This function will convert any string table indexes and file indexes
  165.   /// into human readable format.
  166.   ///
  167.   ///
  168.   /// \param  OS The output stream to dump to.
  169.   ///
  170.   /// \param LT The object to dump.
  171.   void dump(raw_ostream &OS, const LineTable &LT);
  172.  
  173.   /// Dump a InlineInfo object.
  174.   ///
  175.   /// This function will convert any string table indexes and file indexes
  176.   /// into human readable format.
  177.   ///
  178.   /// \param  OS The output stream to dump to.
  179.   ///
  180.   /// \param II The object to dump.
  181.   ///
  182.   /// \param Indent The indentation as number of spaces. Used for recurive
  183.   /// dumping.
  184.   void dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent = 0);
  185.  
  186.   /// Dump a FileEntry object.
  187.   ///
  188.   /// This function will convert any string table indexes into human readable
  189.   /// format.
  190.   ///
  191.   /// \param  OS The output stream to dump to.
  192.   ///
  193.   /// \param FE The object to dump.
  194.   void dump(raw_ostream &OS, std::optional<FileEntry> FE);
  195.  
  196.   /// Get the number of addresses in this Gsym file.
  197.   uint32_t getNumAddresses() const {
  198.     return Hdr->NumAddresses;
  199.   }
  200.  
  201.   /// Gets an address from the address table.
  202.   ///
  203.   /// Addresses are stored as offsets frrom the gsym::Header::BaseAddress.
  204.   ///
  205.   /// \param Index A index into the address table.
  206.   /// \returns A resolved virtual address for adddress in the address table
  207.   /// or std::nullopt if Index is out of bounds.
  208.   std::optional<uint64_t> getAddress(size_t Index) const;
  209.  
  210. protected:
  211.  
  212.   /// Get an appropriate address info offsets array.
  213.   ///
  214.   /// The address table in the GSYM file is stored as array of 1, 2, 4 or 8
  215.   /// byte offsets from the The gsym::Header::BaseAddress. The table is stored
  216.   /// internally as a array of bytes that are in the correct endianness. When
  217.   /// we access this table we must get an array that matches those sizes. This
  218.   /// templatized helper function is used when accessing address offsets in the
  219.   /// AddrOffsets member variable.
  220.   ///
  221.   /// \returns An ArrayRef of an appropriate address offset size.
  222.   template <class T> ArrayRef<T>
  223.   getAddrOffsets() const {
  224.     return ArrayRef<T>(reinterpret_cast<const T *>(AddrOffsets.data()),
  225.                        AddrOffsets.size()/sizeof(T));
  226.   }
  227.  
  228.   /// Get an appropriate address from the address table.
  229.   ///
  230.   /// The address table in the GSYM file is stored as array of 1, 2, 4 or 8
  231.   /// byte address offsets from the The gsym::Header::BaseAddress. The table is
  232.   /// stored internally as a array of bytes that are in the correct endianness.
  233.   /// In order to extract an address from the address table we must access the
  234.   /// address offset using the correct size and then add it to the BaseAddress
  235.   /// in the header.
  236.   ///
  237.   /// \param Index An index into the AddrOffsets array.
  238.   /// \returns An virtual address that matches the original object file for the
  239.   /// address as the specified index, or std::nullopt if Index is out of bounds.
  240.   template <class T>
  241.   std::optional<uint64_t> addressForIndex(size_t Index) const {
  242.     ArrayRef<T> AIO = getAddrOffsets<T>();
  243.     if (Index < AIO.size())
  244.       return AIO[Index] + Hdr->BaseAddress;
  245.     return std::nullopt;
  246.   }
  247.   /// Lookup an address offset in the AddrOffsets table.
  248.   ///
  249.   /// Given an address offset, look it up using a binary search of the
  250.   /// AddrOffsets table.
  251.   ///
  252.   /// \param AddrOffset An address offset, that has already been computed by
  253.   /// subtracting the gsym::Header::BaseAddress.
  254.   /// \returns The matching address offset index. This index will be used to
  255.   /// extract the FunctionInfo data's offset from the AddrInfoOffsets array.
  256.   template <class T>
  257.   std::optional<uint64_t>
  258.   getAddressOffsetIndex(const uint64_t AddrOffset) const {
  259.     ArrayRef<T> AIO = getAddrOffsets<T>();
  260.     const auto Begin = AIO.begin();
  261.     const auto End = AIO.end();
  262.     auto Iter = std::lower_bound(Begin, End, AddrOffset);
  263.     // Watch for addresses that fall between the gsym::Header::BaseAddress and
  264.     // the first address offset.
  265.     if (Iter == Begin && AddrOffset < *Begin)
  266.       return std::nullopt;
  267.     if (Iter == End || AddrOffset < *Iter)
  268.       --Iter;
  269.     return std::distance(Begin, Iter);
  270.   }
  271.  
  272.   /// Create a GSYM from a memory buffer.
  273.   ///
  274.   /// Called by both openFile() and copyBuffer(), this function does all of the
  275.   /// work of parsing the GSYM file and returning an error.
  276.   ///
  277.   /// \param MemBuffer A memory buffer that will transfer ownership into the
  278.   /// GsymReader.
  279.   /// \returns An expected GsymReader that contains the object or an error
  280.   /// object that indicates reason for failing to read the GSYM.
  281.   static llvm::Expected<llvm::gsym::GsymReader>
  282.   create(std::unique_ptr<MemoryBuffer> &MemBuffer);
  283.  
  284.  
  285.   /// Given an address, find the address index.
  286.   ///
  287.   /// Binary search the address table and find the matching address index.
  288.   ///
  289.   /// \param Addr A virtual address that matches the original object file
  290.   /// to lookup.
  291.   /// \returns An index into the address table. This index can be used to
  292.   /// extract the FunctionInfo data's offset from the AddrInfoOffsets array.
  293.   /// Returns an error if the address isn't in the GSYM with details of why.
  294.   Expected<uint64_t> getAddressIndex(const uint64_t Addr) const;
  295.  
  296.   /// Given an address index, get the offset for the FunctionInfo.
  297.   ///
  298.   /// Looking up an address is done by finding the corresponding address
  299.   /// index for the address. This index is then used to get the offset of the
  300.   /// FunctionInfo data that we will decode using this function.
  301.   ///
  302.   /// \param Index An index into the address table.
  303.   /// \returns An optional GSYM data offset for the offset of the FunctionInfo
  304.   /// that needs to be decoded.
  305.   std::optional<uint64_t> getAddressInfoOffset(size_t Index) const;
  306. };
  307.  
  308. } // namespace gsym
  309. } // namespace llvm
  310.  
  311. #endif // LLVM_DEBUGINFO_GSYM_GSYMREADER_H
  312.