1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00
llvm-mirror/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
Greg Clayton 75aaaf95b6 Add a llvm-gsymutil tool that can convert object files to GSYM and perform lookups.
Summary:
This patch creates the llvm-gsymutil binary that can convert object files to GSYM using the --convert <path> option. It can also dump and lookup addresses within GSYM files that have been saved to disk.

To dump a file:

llvm-gsymutil /path/to/a.gsym

To perform address lookups, like with atos, on GSYM files:

llvm-gsymutil --address 0x1000 --address 0x1100 /path/to/a.gsym

To convert a mach-o or ELF file, including any DWARF debug info contained within the object files:

llvm-gsymutil --convert /path/to/a.out --out-file /path/to/a.out.gsym

Conversion highlights:
- convert DWARF debug info in mach-o or ELF files to GSYM
- convert symbols in symbol table to GSYM and don't convert symbols that overlap with DWARF debug info
- extract UUID from object files
- extract .text (read + execute) section address ranges and filter out any DWARF or symbols that don't fall in those ranges.
- if .text sections are extracted, and if the last gsym::FunctionInfo object has no size, cap the size to the end of the section the function was contained in

Dumping GSYM files will dump all sections of the GSYM file in textual format.

Reviewers: labath, aadsm, serhiy.redko, jankratochvil, xiaobai, wallace, aprantl, JDevlieghere, jdoerfert

Subscribers: mgorny, hiraditya, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74883
2020-02-25 21:11:05 -08:00

108 lines
3.9 KiB
C++

//===- ObjectFileTransformer.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 <unordered_set>
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
#include "llvm/DebugInfo/GSYM/GsymCreator.h"
using namespace llvm;
using namespace gsym;
constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
// Extract the UUID from the object file
std::vector<uint8_t> UUID;
if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
if (!MachUUID.empty())
UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
} else if (isa<object::ELFObjectFileBase>(&Obj)) {
const StringRef GNUBuildID(".note.gnu.build-id");
for (const object::SectionRef &Sect : Obj.sections()) {
Expected<StringRef> SectNameOrErr = Sect.getName();
if (!SectNameOrErr) {
consumeError(SectNameOrErr.takeError());
continue;
}
StringRef SectName(*SectNameOrErr);
if (SectName != GNUBuildID)
continue;
StringRef BuildIDData;
Expected<StringRef> E = Sect.getContents();
if (E)
BuildIDData = *E;
else {
consumeError(E.takeError());
continue;
}
DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
uint64_t Offset = 0;
const uint32_t NameSize = Decoder.getU32(&Offset);
const uint32_t PayloadSize = Decoder.getU32(&Offset);
const uint32_t PayloadType = Decoder.getU32(&Offset);
StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
Offset = alignTo(Offset, 4);
StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
if (!UUIDBytes.empty()) {
auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
UUID.assign(Ptr, Ptr + UUIDBytes.size());
}
}
}
}
return UUID;
}
llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
raw_ostream &Log,
GsymCreator &Gsym) {
using namespace llvm::object;
const bool IsMachO = isa<MachOObjectFile>(&Obj);
const bool IsELF = isa<ELFObjectFileBase>(&Obj);
// Read build ID.
Gsym.setUUID(getUUID(Obj));
// Parse the symbol table.
size_t NumBefore = Gsym.getNumFunctionInfos();
for (const object::SymbolRef &Sym : Obj.symbols()) {
Expected<SymbolRef::Type> SymType = Sym.getType();
const uint64_t Addr = Sym.getValue();
if (!SymType || SymType.get() != SymbolRef::Type::ST_Function ||
!Gsym.IsValidTextAddress(Addr) || Gsym.hasFunctionInfoForAddress(Addr))
continue;
// Function size for MachO files will be 0
constexpr bool NoCopy = false;
const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
Expected<StringRef> Name = Sym.getName();
if (!Name) {
logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: ");
continue;
}
// Remove the leading '_' character in any symbol names if there is one
// for mach-o files.
if (IsMachO)
Name->consume_front("_");
Gsym.addFunctionInfo(FunctionInfo(Addr, size,
Gsym.insertString(*Name, NoCopy)));
}
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n";
return Error::success();
}