forked from OSchip/llvm-project
160 lines
5.9 KiB
C++
160 lines
5.9 KiB
C++
//===- 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/FileWriter.h"
|
|
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
|
|
#include "llvm/Support/DataExtractor.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;
|
|
}
|
|
|
|
/// Decode an InlineInfo in Data at the specified offset.
|
|
///
|
|
/// A local helper function to decode InlineInfo objects. This function is
|
|
/// called recursively when parsing child InlineInfo objects.
|
|
///
|
|
/// \param Data The data extractor to decode from.
|
|
/// \param Offset The offset within \a Data to decode from.
|
|
/// \param BaseAddr The base address to use when decoding address ranges.
|
|
/// \returns An InlineInfo or an error describing the issue that was
|
|
/// encountered during decoding.
|
|
static llvm::Expected<InlineInfo> decode(DataExtractor &Data, uint64_t &Offset,
|
|
uint64_t BaseAddr) {
|
|
InlineInfo Inline;
|
|
if (!Data.isValidOffset(Offset))
|
|
return createStringError(std::errc::io_error,
|
|
"0x%8.8" PRIx64 ": missing InlineInfo address ranges data", Offset);
|
|
Inline.Ranges.decode(Data, BaseAddr, Offset);
|
|
if (Inline.Ranges.empty())
|
|
return Inline;
|
|
if (!Data.isValidOffsetForDataOfSize(Offset, 1))
|
|
return createStringError(std::errc::io_error,
|
|
"0x%8.8" PRIx64 ": missing InlineInfo uint8_t indicating children",
|
|
Offset);
|
|
bool HasChildren = Data.getU8(&Offset) != 0;
|
|
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
|
|
return createStringError(std::errc::io_error,
|
|
"0x%8.8" PRIx64 ": missing InlineInfo uint32_t for name", Offset);
|
|
Inline.Name = Data.getU32(&Offset);
|
|
if (!Data.isValidOffset(Offset))
|
|
return createStringError(std::errc::io_error,
|
|
"0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call file", Offset);
|
|
Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
|
|
if (!Data.isValidOffset(Offset))
|
|
return createStringError(std::errc::io_error,
|
|
"0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call line", Offset);
|
|
Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
|
|
if (HasChildren) {
|
|
// Child address ranges are encoded relative to the first address in the
|
|
// parent InlineInfo object.
|
|
const auto ChildBaseAddr = Inline.Ranges[0].Start;
|
|
while (true) {
|
|
llvm::Expected<InlineInfo> Child = decode(Data, Offset, ChildBaseAddr);
|
|
if (!Child)
|
|
return Child.takeError();
|
|
// InlineInfo with empty Ranges termintes a child sibling chain.
|
|
if (Child.get().Ranges.empty())
|
|
break;
|
|
Inline.Children.emplace_back(std::move(*Child));
|
|
}
|
|
}
|
|
return Inline;
|
|
}
|
|
|
|
llvm::Expected<InlineInfo> InlineInfo::decode(DataExtractor &Data,
|
|
uint64_t BaseAddr) {
|
|
uint64_t Offset = 0;
|
|
return ::decode(Data, Offset, BaseAddr);
|
|
}
|
|
|
|
llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const {
|
|
// Users must verify the InlineInfo is valid prior to calling this funtion.
|
|
// We don't want to emit any InlineInfo objects if they are not valid since
|
|
// it will waste space in the GSYM file.
|
|
if (!isValid())
|
|
return createStringError(std::errc::invalid_argument,
|
|
"attempted to encode invalid InlineInfo object");
|
|
Ranges.encode(O, BaseAddr);
|
|
bool HasChildren = !Children.empty();
|
|
O.writeU8(HasChildren);
|
|
O.writeU32(Name);
|
|
O.writeULEB(CallFile);
|
|
O.writeULEB(CallLine);
|
|
if (HasChildren) {
|
|
// Child address ranges are encoded as relative to the first
|
|
// address in the Ranges for this object. This keeps the offsets
|
|
// small and allows for efficient encoding using ULEB offsets.
|
|
const uint64_t ChildBaseAddr = Ranges[0].Start;
|
|
for (const auto &Child : Children) {
|
|
// Make sure all child address ranges are contained in the parent address
|
|
// ranges.
|
|
for (const auto &ChildRange: Child.Ranges) {
|
|
if (!Ranges.contains(ChildRange))
|
|
return createStringError(std::errc::invalid_argument,
|
|
"child range not contained in parent");
|
|
}
|
|
llvm::Error Err = Child.encode(O, ChildBaseAddr);
|
|
if (Err)
|
|
return Err;
|
|
}
|
|
|
|
// Terminate child sibling chain by emitting a zero. This zero will cause
|
|
// the decodeAll() function above to return false and stop the decoding
|
|
// of child InlineInfo objects that are siblings.
|
|
O.writeULEB(0);
|
|
}
|
|
return Error::success();
|
|
}
|