Kumar Kartikeya Dwivedi reported a bug ([1]) where BTF_KIND_TYPE_TAG types
are not generated.
Currently, BPF backend only generates BTF types which are used by
the program, e.g., global variables, functions and some builtin functions.
For example, suppose we have
struct task_struct {
...
struct task_group *sched_task_group;
struct mm_struct *mm;
...
pid_t pid;
pid_t tgid;
...
}
If BPF program intends to access task_struct->pid and task_struct->tgid,
there really no need to generate BTF types for struct task_group
and mm_struct.
In BPF backend, during BTF generation, when generating BTF for struct
task_struct, if types for task_group and mm_struct have not been generated
yet, a Fixup structure will be created, which will be reexamined later
to instantiate into either a full type or a forward type.
In current implementation, if we have something like
struct foo {
struct bar __tag1 *f;
};
and when generating types for struct foo, struct bar type
has not been generated, the __tag1 will be lost during later
Fixup instantiation. This patch fixed this issue by properly
handling btf_type_tag's during Fixup instantiation stage.
[1] https://lore.kernel.org/bpf/20220210232411.pmhzj7v5uptqby7r@apollo.legion/
Differential Revision: https://reviews.llvm.org/D119799
414 lines
13 KiB
C++
414 lines
13 KiB
C++
//===- BTFDebug.h -----------------------------------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// This file contains support for writing BTF debug info.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TARGET_BPF_BTFDEBUG_H
|
|
#define LLVM_LIB_TARGET_BPF_BTFDEBUG_H
|
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/CodeGen/DebugHandlerBase.h"
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <set>
|
|
#include <unordered_map>
|
|
#include "BTF.h"
|
|
|
|
namespace llvm {
|
|
|
|
class AsmPrinter;
|
|
class BTFDebug;
|
|
class DIType;
|
|
class GlobalVariable;
|
|
class MachineFunction;
|
|
class MachineInstr;
|
|
class MachineOperand;
|
|
class MCInst;
|
|
class MCStreamer;
|
|
class MCSymbol;
|
|
|
|
/// The base class for BTF type generation.
|
|
class BTFTypeBase {
|
|
protected:
|
|
uint8_t Kind;
|
|
bool IsCompleted;
|
|
uint32_t Id;
|
|
struct BTF::CommonType BTFType;
|
|
|
|
public:
|
|
BTFTypeBase() : IsCompleted(false) {}
|
|
virtual ~BTFTypeBase() = default;
|
|
void setId(uint32_t Id) { this->Id = Id; }
|
|
uint32_t getId() { return Id; }
|
|
uint32_t roundupToBytes(uint32_t NumBits) { return (NumBits + 7) >> 3; }
|
|
/// Get the size of this BTF type entry.
|
|
virtual uint32_t getSize() { return BTF::CommonTypeSize; }
|
|
/// Complete BTF type generation after all related DebugInfo types
|
|
/// have been visited so their BTF type id's are available
|
|
/// for cross referece.
|
|
virtual void completeType(BTFDebug &BDebug) {}
|
|
/// Emit types for this BTF type entry.
|
|
virtual void emitType(MCStreamer &OS);
|
|
};
|
|
|
|
/// Handle several derived types include pointer, const,
|
|
/// volatile, typedef and restrict.
|
|
class BTFTypeDerived : public BTFTypeBase {
|
|
const DIDerivedType *DTy;
|
|
bool NeedsFixup;
|
|
StringRef Name;
|
|
|
|
public:
|
|
BTFTypeDerived(const DIDerivedType *Ty, unsigned Tag, bool NeedsFixup);
|
|
BTFTypeDerived(unsigned NextTypeId, unsigned Tag, StringRef Name);
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
void setPointeeType(uint32_t PointeeType);
|
|
};
|
|
|
|
/// Handle struct or union forward declaration.
|
|
class BTFTypeFwd : public BTFTypeBase {
|
|
StringRef Name;
|
|
|
|
public:
|
|
BTFTypeFwd(StringRef Name, bool IsUnion);
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle int type.
|
|
class BTFTypeInt : public BTFTypeBase {
|
|
StringRef Name;
|
|
uint32_t IntVal; ///< Encoding, offset, bits
|
|
|
|
public:
|
|
BTFTypeInt(uint32_t Encoding, uint32_t SizeInBits, uint32_t OffsetInBits,
|
|
StringRef TypeName);
|
|
uint32_t getSize() override { return BTFTypeBase::getSize() + sizeof(uint32_t); }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle enumerate type.
|
|
class BTFTypeEnum : public BTFTypeBase {
|
|
const DICompositeType *ETy;
|
|
std::vector<struct BTF::BTFEnum> EnumValues;
|
|
|
|
public:
|
|
BTFTypeEnum(const DICompositeType *ETy, uint32_t NumValues);
|
|
uint32_t getSize() override {
|
|
return BTFTypeBase::getSize() + EnumValues.size() * BTF::BTFEnumSize;
|
|
}
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle array type.
|
|
class BTFTypeArray : public BTFTypeBase {
|
|
struct BTF::BTFArray ArrayInfo;
|
|
|
|
public:
|
|
BTFTypeArray(uint32_t ElemTypeId, uint32_t NumElems);
|
|
uint32_t getSize() override { return BTFTypeBase::getSize() + BTF::BTFArraySize; }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle struct/union type.
|
|
class BTFTypeStruct : public BTFTypeBase {
|
|
const DICompositeType *STy;
|
|
bool HasBitField;
|
|
std::vector<struct BTF::BTFMember> Members;
|
|
|
|
public:
|
|
BTFTypeStruct(const DICompositeType *STy, bool IsStruct, bool HasBitField,
|
|
uint32_t NumMembers);
|
|
uint32_t getSize() override {
|
|
return BTFTypeBase::getSize() + Members.size() * BTF::BTFMemberSize;
|
|
}
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
std::string getName();
|
|
};
|
|
|
|
/// Handle function pointer.
|
|
class BTFTypeFuncProto : public BTFTypeBase {
|
|
const DISubroutineType *STy;
|
|
std::unordered_map<uint32_t, StringRef> FuncArgNames;
|
|
std::vector<struct BTF::BTFParam> Parameters;
|
|
|
|
public:
|
|
BTFTypeFuncProto(const DISubroutineType *STy, uint32_t NumParams,
|
|
const std::unordered_map<uint32_t, StringRef> &FuncArgNames);
|
|
uint32_t getSize() override {
|
|
return BTFTypeBase::getSize() + Parameters.size() * BTF::BTFParamSize;
|
|
}
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle subprogram
|
|
class BTFTypeFunc : public BTFTypeBase {
|
|
StringRef Name;
|
|
|
|
public:
|
|
BTFTypeFunc(StringRef FuncName, uint32_t ProtoTypeId, uint32_t Scope);
|
|
uint32_t getSize() override { return BTFTypeBase::getSize(); }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle variable instances
|
|
class BTFKindVar : public BTFTypeBase {
|
|
StringRef Name;
|
|
uint32_t Info;
|
|
|
|
public:
|
|
BTFKindVar(StringRef VarName, uint32_t TypeId, uint32_t VarInfo);
|
|
uint32_t getSize() override { return BTFTypeBase::getSize() + 4; }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle data sections
|
|
class BTFKindDataSec : public BTFTypeBase {
|
|
AsmPrinter *Asm;
|
|
std::string Name;
|
|
std::vector<std::tuple<uint32_t, const MCSymbol *, uint32_t>> Vars;
|
|
|
|
public:
|
|
BTFKindDataSec(AsmPrinter *AsmPrt, std::string SecName);
|
|
uint32_t getSize() override {
|
|
return BTFTypeBase::getSize() + BTF::BTFDataSecVarSize * Vars.size();
|
|
}
|
|
void addDataSecEntry(uint32_t Id, const MCSymbol *Sym, uint32_t Size) {
|
|
Vars.push_back(std::make_tuple(Id, Sym, Size));
|
|
}
|
|
std::string getName() { return Name; }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
/// Handle binary floating point type.
|
|
class BTFTypeFloat : public BTFTypeBase {
|
|
StringRef Name;
|
|
|
|
public:
|
|
BTFTypeFloat(uint32_t SizeInBits, StringRef TypeName);
|
|
void completeType(BTFDebug &BDebug) override;
|
|
};
|
|
|
|
/// Handle decl tags.
|
|
class BTFTypeDeclTag : public BTFTypeBase {
|
|
uint32_t Info;
|
|
StringRef Tag;
|
|
|
|
public:
|
|
BTFTypeDeclTag(uint32_t BaseTypeId, int ComponentId, StringRef Tag);
|
|
uint32_t getSize() override { return BTFTypeBase::getSize() + 4; }
|
|
void completeType(BTFDebug &BDebug) override;
|
|
void emitType(MCStreamer &OS) override;
|
|
};
|
|
|
|
class BTFTypeTypeTag : public BTFTypeBase {
|
|
const DIDerivedType *DTy;
|
|
StringRef Tag;
|
|
|
|
public:
|
|
BTFTypeTypeTag(uint32_t NextTypeId, StringRef Tag);
|
|
BTFTypeTypeTag(const DIDerivedType *DTy, StringRef Tag);
|
|
void completeType(BTFDebug &BDebug) override;
|
|
};
|
|
|
|
/// String table.
|
|
class BTFStringTable {
|
|
/// String table size in bytes.
|
|
uint32_t Size;
|
|
/// A mapping from string table offset to the index
|
|
/// of the Table. It is used to avoid putting
|
|
/// duplicated strings in the table.
|
|
std::map<uint32_t, uint32_t> OffsetToIdMap;
|
|
/// A vector of strings to represent the string table.
|
|
std::vector<std::string> Table;
|
|
|
|
public:
|
|
BTFStringTable() : Size(0) {}
|
|
uint32_t getSize() { return Size; }
|
|
std::vector<std::string> &getTable() { return Table; }
|
|
/// Add a string to the string table and returns its offset
|
|
/// in the table.
|
|
uint32_t addString(StringRef S);
|
|
};
|
|
|
|
/// Represent one func and its type id.
|
|
struct BTFFuncInfo {
|
|
const MCSymbol *Label; ///< Func MCSymbol
|
|
uint32_t TypeId; ///< Type id referring to .BTF type section
|
|
};
|
|
|
|
/// Represent one line info.
|
|
struct BTFLineInfo {
|
|
MCSymbol *Label; ///< MCSymbol identifying insn for the lineinfo
|
|
uint32_t FileNameOff; ///< file name offset in the .BTF string table
|
|
uint32_t LineOff; ///< line offset in the .BTF string table
|
|
uint32_t LineNum; ///< the line number
|
|
uint32_t ColumnNum; ///< the column number
|
|
};
|
|
|
|
/// Represent one field relocation.
|
|
struct BTFFieldReloc {
|
|
const MCSymbol *Label; ///< MCSymbol identifying insn for the reloc
|
|
uint32_t TypeID; ///< Type ID
|
|
uint32_t OffsetNameOff; ///< The string to traverse types
|
|
uint32_t RelocKind; ///< What to patch the instruction
|
|
};
|
|
|
|
/// Collect and emit BTF information.
|
|
class BTFDebug : public DebugHandlerBase {
|
|
MCStreamer &OS;
|
|
bool SkipInstruction;
|
|
bool LineInfoGenerated;
|
|
uint32_t SecNameOff;
|
|
uint32_t ArrayIndexTypeId;
|
|
bool MapDefNotCollected;
|
|
BTFStringTable StringTable;
|
|
std::vector<std::unique_ptr<BTFTypeBase>> TypeEntries;
|
|
std::unordered_map<const DIType *, uint32_t> DIToIdMap;
|
|
std::map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable;
|
|
std::map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable;
|
|
std::map<uint32_t, std::vector<BTFFieldReloc>> FieldRelocTable;
|
|
StringMap<std::vector<std::string>> FileContent;
|
|
std::map<std::string, std::unique_ptr<BTFKindDataSec>> DataSecEntries;
|
|
std::vector<BTFTypeStruct *> StructTypes;
|
|
std::map<const GlobalVariable *, std::pair<int64_t, uint32_t>> PatchImms;
|
|
std::map<const DICompositeType *,
|
|
std::vector<std::pair<const DIDerivedType *, BTFTypeDerived *>>>
|
|
FixupDerivedTypes;
|
|
std::set<const Function *>ProtoFunctions;
|
|
|
|
/// Add types to TypeEntries.
|
|
/// @{
|
|
/// Add types to TypeEntries and DIToIdMap.
|
|
uint32_t addType(std::unique_ptr<BTFTypeBase> TypeEntry, const DIType *Ty);
|
|
/// Add types to TypeEntries only and return type id.
|
|
uint32_t addType(std::unique_ptr<BTFTypeBase> TypeEntry);
|
|
/// @}
|
|
|
|
/// IR type visiting functions.
|
|
/// @{
|
|
void visitTypeEntry(const DIType *Ty);
|
|
void visitTypeEntry(const DIType *Ty, uint32_t &TypeId, bool CheckPointer,
|
|
bool SeenPointer);
|
|
void visitBasicType(const DIBasicType *BTy, uint32_t &TypeId);
|
|
void visitSubroutineType(
|
|
const DISubroutineType *STy, bool ForSubprog,
|
|
const std::unordered_map<uint32_t, StringRef> &FuncArgNames,
|
|
uint32_t &TypeId);
|
|
void visitFwdDeclType(const DICompositeType *CTy, bool IsUnion,
|
|
uint32_t &TypeId);
|
|
void visitCompositeType(const DICompositeType *CTy, uint32_t &TypeId);
|
|
void visitStructType(const DICompositeType *STy, bool IsStruct,
|
|
uint32_t &TypeId);
|
|
void visitArrayType(const DICompositeType *ATy, uint32_t &TypeId);
|
|
void visitEnumType(const DICompositeType *ETy, uint32_t &TypeId);
|
|
void visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId,
|
|
bool CheckPointer, bool SeenPointer);
|
|
void visitMapDefType(const DIType *Ty, uint32_t &TypeId);
|
|
/// @}
|
|
|
|
/// Get the file content for the subprogram. Certain lines of the file
|
|
/// later may be put into string table and referenced by line info.
|
|
std::string populateFileContent(const DISubprogram *SP);
|
|
|
|
/// Construct a line info.
|
|
void constructLineInfo(const DISubprogram *SP, MCSymbol *Label, uint32_t Line,
|
|
uint32_t Column);
|
|
|
|
/// Generate types and variables for globals.
|
|
void processGlobals(bool ProcessingMapDef);
|
|
|
|
/// Generate types for function prototypes.
|
|
void processFuncPrototypes(const Function *);
|
|
|
|
/// Generate types for decl annotations.
|
|
void processDeclAnnotations(DINodeArray Annotations, uint32_t BaseTypeId,
|
|
int ComponentId);
|
|
|
|
/// Generate BTF type_tag's. If BaseTypeId is nonnegative, the last
|
|
/// BTF type_tag in the chain points to BaseTypeId. Otherwise, it points to
|
|
/// the base type of DTy. Return the type id of the first BTF type_tag
|
|
/// in the chain. If no type_tag's are generated, a negative value
|
|
/// is returned.
|
|
int genBTFTypeTags(const DIDerivedType *DTy, int BaseTypeId);
|
|
|
|
/// Generate one field relocation record.
|
|
void generatePatchImmReloc(const MCSymbol *ORSym, uint32_t RootId,
|
|
const GlobalVariable *, bool IsAma);
|
|
|
|
/// Populating unprocessed type on demand.
|
|
unsigned populateType(const DIType *Ty);
|
|
|
|
/// Process global variables referenced by relocation instructions
|
|
/// and extern function references.
|
|
void processGlobalValue(const MachineOperand &MO);
|
|
|
|
/// Emit common header of .BTF and .BTF.ext sections.
|
|
void emitCommonHeader();
|
|
|
|
/// Emit the .BTF section.
|
|
void emitBTFSection();
|
|
|
|
/// Emit the .BTF.ext section.
|
|
void emitBTFExtSection();
|
|
|
|
protected:
|
|
/// Gather pre-function debug information.
|
|
void beginFunctionImpl(const MachineFunction *MF) override;
|
|
|
|
/// Post process after all instructions in this function are processed.
|
|
void endFunctionImpl(const MachineFunction *MF) override;
|
|
|
|
public:
|
|
BTFDebug(AsmPrinter *AP);
|
|
|
|
///
|
|
bool InstLower(const MachineInstr *MI, MCInst &OutMI);
|
|
|
|
/// Get the special array index type id.
|
|
uint32_t getArrayIndexTypeId() {
|
|
assert(ArrayIndexTypeId);
|
|
return ArrayIndexTypeId;
|
|
}
|
|
|
|
/// Add string to the string table.
|
|
size_t addString(StringRef S) { return StringTable.addString(S); }
|
|
|
|
/// Get the type id for a particular DIType.
|
|
uint32_t getTypeId(const DIType *Ty) {
|
|
assert(Ty && "Invalid null Type");
|
|
assert(DIToIdMap.find(Ty) != DIToIdMap.end() &&
|
|
"DIType not added in the BDIToIdMap");
|
|
return DIToIdMap[Ty];
|
|
}
|
|
|
|
void setSymbolSize(const MCSymbol *Symbol, uint64_t Size) override {}
|
|
|
|
/// Process beginning of an instruction.
|
|
void beginInstruction(const MachineInstr *MI) override;
|
|
|
|
/// Complete all the types and emit the BTF sections.
|
|
void endModule() override;
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif
|