llvm-project/llvm/lib/DebugInfo/GSYM/MergedFunctionsInfo.cpp
alx32 6f28b4b5e9
[GSYM] Add support for querying merged functions in llvm-gsymutil (#120991)
Adds the ability to lookup and display all merged functions for an
address in llvm-gsymutil.

Now, when `--merged-functions` is used in combination with
`--address/--addresses-from-stdin`, lookup results will contain
information about merged functions, if available.

To support printing merged function information when using the
`--verbose` option, the `LookupResult` data structure also had to be
extended with pointers to the raw function data and raw merged function
data. This is because merged functions share the same address range, so
it's not easy to look up the raw merged function data for a particular
`LookupResult` that is based on a merged function.
2025-01-06 11:55:27 -08:00

97 lines
3.3 KiB
C++

//===- MergedFunctionsInfo.cpp ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/GSYM/MergedFunctionsInfo.h"
#include "llvm/DebugInfo/GSYM/FileWriter.h"
#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
#include "llvm/Support/DataExtractor.h"
using namespace llvm;
using namespace gsym;
void MergedFunctionsInfo::clear() { MergedFunctions.clear(); }
llvm::Error MergedFunctionsInfo::encode(FileWriter &Out) const {
Out.writeU32(MergedFunctions.size());
for (const auto &F : MergedFunctions) {
Out.writeU32(0);
const auto StartOffset = Out.tell();
// Encode the FunctionInfo with no padding so later we can just read them
// one after the other without knowing the offset in the stream for each.
llvm::Expected<uint64_t> result = F.encode(Out, /*NoPadding =*/true);
if (!result)
return result.takeError();
const auto Length = Out.tell() - StartOffset;
Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
}
return Error::success();
}
llvm::Expected<MergedFunctionsInfo>
MergedFunctionsInfo::decode(DataExtractor &Data, uint64_t BaseAddr) {
MergedFunctionsInfo MFI;
auto FuncExtractorsOrError = MFI.getFuncsDataExtractors(Data);
if (!FuncExtractorsOrError)
return FuncExtractorsOrError.takeError();
for (DataExtractor &FuncData : *FuncExtractorsOrError) {
llvm::Expected<FunctionInfo> FI = FunctionInfo::decode(FuncData, BaseAddr);
if (!FI)
return FI.takeError();
MFI.MergedFunctions.push_back(std::move(*FI));
}
return MFI;
}
llvm::Expected<std::vector<DataExtractor>>
MergedFunctionsInfo::getFuncsDataExtractors(DataExtractor &Data) {
std::vector<DataExtractor> Results;
uint64_t Offset = 0;
// Ensure there is enough data to read the function count.
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
return createStringError(
std::errc::io_error,
"unable to read the function count at offset 0x%8.8" PRIx64, Offset);
uint32_t Count = Data.getU32(&Offset);
for (uint32_t i = 0; i < Count; ++i) {
// Ensure there is enough data to read the function size.
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
return createStringError(
std::errc::io_error,
"unable to read size of function %u at offset 0x%8.8" PRIx64, i,
Offset);
uint32_t FnSize = Data.getU32(&Offset);
// Ensure there is enough data for the function content.
if (!Data.isValidOffsetForDataOfSize(Offset, FnSize))
return createStringError(
std::errc::io_error,
"function data is truncated for function %u at offset 0x%8.8" PRIx64
", expected size %u",
i, Offset, FnSize);
// Extract the function data.
Results.emplace_back(Data.getData().substr(Offset, FnSize),
Data.isLittleEndian(), Data.getAddressSize());
Offset += FnSize;
}
return Results;
}
bool operator==(const MergedFunctionsInfo &LHS,
const MergedFunctionsInfo &RHS) {
return LHS.MergedFunctions == RHS.MergedFunctions;
}