diff options
| author | Yonghong Song <yhs@fb.com> | 2019-03-16 15:36:31 +0000 |
|---|---|---|
| committer | Yonghong Song <yhs@fb.com> | 2019-03-16 15:36:31 +0000 |
| commit | 6db6b56a5c8fc6dd2ab7d50d289e292a14121cd4 (patch) | |
| tree | bc6bc59c0b1a761a96fb27a3c7f711b7a6dc1da7 /llvm/lib/Target | |
| parent | f2c53b5d6c5516ed5f270e3e8e90281ea6acbea9 (diff) | |
| download | bcm5719-llvm-6db6b56a5c8fc6dd2ab7d50d289e292a14121cd4.tar.gz bcm5719-llvm-6db6b56a5c8fc6dd2ab7d50d289e292a14121cd4.zip | |
[BPF] Add BTF Var and DataSec Support
Two new kinds, BTF_KIND_VAR and BTF_KIND_DATASEC, are added.
BTF_KIND_VAR has the following specification:
btf_type.name: var name
btf_type.info: type kind
btf_type.type: var type
// btf_type is followed by one u32
u32: varinfo (currently, only 0 - static, 1 - global allocated in elf sections)
Not all globals are supported in this patch. The following globals are supported:
. static variables with or without section attributes
. global variables with section attributes
The inclusion of globals with section attributes
is for future potential extraction of key/value
type id's from map definition.
BTF_KIND_DATASEC has the following specification:
btf_type.name: section name associated with variable or
one of .data/.bss/.readonly
btf_type.info: type kind and vlen for # of variables
btf_type.size: 0
#vlen number of the following:
u32: id of corresponding BTF_KIND_VAR
u32: in-session offset of the var
u32: the size of memory var occupied
At the time of debug info emission, the data section
size is unknown, so the btf_type.size = 0 for
BTF_KIND_DATASEC. The loader can patch it during
loading time.
The in-session offseet of the var is only available
for static variables. For global variables, the
loader neeeds to assign the global variable symbol value in
symbol table to in-section offset.
The size of memory is used to specify the amount of the
memory a variable occupies. Typically, it equals to
the type size, but for certain structures, e.g.,
struct tt {
int a;
int b;
char c[];
};
static volatile struct tt s2 = {3, 4, "abcdefghi"};
The static variable s2 has size of 20.
Note that for BTF_KIND_DATASEC name, the section name
does not contain object name. The compiler does have
input module name. For example, two cases below:
. clang -target bpf -O2 -g -c test.c
The compiler knows the input file (module) is test.c
and can generate sec name like test.data/test.bss etc.
. clang -target bpf -O2 -g -emit-llvm -c test.c -o - |
llc -march=bpf -filetype=obj -o test.o
The llc compiler has the input file as stdin, and
would generate something like stdin.data/stdin.bss etc.
which does not really make sense.
For any user specificed section name, e.g.,
static volatile int a __attribute__((section("id1")));
static volatile const int b __attribute__((section("id2")));
The DataSec with name "id1" and "id2" does not contain
information whether the section is readonly or not.
The loader needs to check the corresponding elf section
flags for such information.
A simple example:
-bash-4.4$ cat t.c
int g1;
int g2 = 3;
const int g3 = 4;
static volatile int s1;
struct tt {
int a;
int b;
char c[];
};
static volatile struct tt s2 = {3, 4, "abcdefghi"};
static volatile const int s3 = 4;
int m __attribute__((section("maps"), used)) = 4;
int test() { return g1 + g2 + g3 + s1 + s2.a + s3 + m; }
-bash-4.4$ clang -target bpf -O2 -g -S t.c
Checking t.s, 4 BTF_KIND_VAR's are generated (s1, s2, s3 and m).
4 BTF_KIND_DATASEC's are generated with names
".data", ".bss", ".rodata" and "maps".
Signed-off-by: Yonghong Song <yhs@fb.com>
Differential Revision: https://reviews.llvm.org/D59441
llvm-svn: 356326
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/BPF/BTF.def | 2 | ||||
| -rw-r--r-- | llvm/lib/Target/BPF/BTF.h | 28 | ||||
| -rw-r--r-- | llvm/lib/Target/BPF/BTFDebug.cpp | 164 | ||||
| -rw-r--r-- | llvm/lib/Target/BPF/BTFDebug.h | 55 |
4 files changed, 208 insertions, 41 deletions
diff --git a/llvm/lib/Target/BPF/BTF.def b/llvm/lib/Target/BPF/BTF.def index 4069e41fa71..2d2e9a04aa6 100644 --- a/llvm/lib/Target/BPF/BTF.def +++ b/llvm/lib/Target/BPF/BTF.def @@ -28,5 +28,7 @@ HANDLE_BTF_KIND(10, CONST) HANDLE_BTF_KIND(11, RESTRICT) HANDLE_BTF_KIND(12, FUNC) HANDLE_BTF_KIND(13, FUNC_PROTO) +HANDLE_BTF_KIND(14, VAR) +HANDLE_BTF_KIND(15, DATASEC) #undef HANDLE_BTF_KIND diff --git a/llvm/lib/Target/BPF/BTF.h b/llvm/lib/Target/BPF/BTF.h index cbe0c858891..23af0f07b4a 100644 --- a/llvm/lib/Target/BPF/BTF.h +++ b/llvm/lib/Target/BPF/BTF.h @@ -55,6 +55,7 @@ enum { BTFEnumSize = 8, BTFMemberSize = 12, BTFParamSize = 8, + BTFDataSecVarSize = 12, SecFuncInfoSize = 8, SecLineInfoSize = 8, BPFFuncInfoSize = 8, @@ -76,7 +77,7 @@ struct Header { }; enum : uint32_t { - MAX_VLEN = 0xffff ///< Max # of struct/union/enum members or func args + MAX_VLEN = 0xffff ///< Max # of struct/union/enum members or func args }; enum TypeKinds : uint8_t { @@ -103,7 +104,7 @@ struct CommonType { /// "Size" tells the size of the type it is describing. /// /// "Type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, - /// FUNC and FUNC_PROTO. + /// FUNC, FUNC_PROTO and VAR. /// "Type" is a type_id referring to another type. union { uint32_t Size; @@ -121,7 +122,11 @@ struct CommonType { // BTF_INT_BITS(VAL) : ((VAL) & 0x000000ff) /// Attributes stored in the INT_ENCODING. -enum : uint8_t { INT_SIGNED = (1 << 0), INT_CHAR = (1 << 1), INT_BOOL = (1 << 2) }; +enum : uint8_t { + INT_SIGNED = (1 << 0), + INT_CHAR = (1 << 1), + INT_BOOL = (1 << 2) +}; /// BTF_KIND_ENUM is followed by multiple "struct BTFEnum". /// The exact number of btf_enum is stored in the vlen (of the @@ -162,6 +167,23 @@ struct BTFParam { uint32_t Type; }; +/// Variable scoping information. +enum : uint8_t { + VAR_STATIC = 0, ///< Linkage: InternalLinkage + VAR_GLOBAL_ALLOCATED = 1, ///< Linkage: ExternalLinkage + VAR_GLOBAL_TENTATIVE = 2, ///< Linkage: CommonLinkage + VAR_GLOBAL_EXTERNAL = 3, ///< Linkage: ExternalLinkage +}; + +/// BTF_KIND_DATASEC are followed by multiple "struct BTFDataSecVar". +/// The exist number of BTFDataSec is stored in the vlen (of the info +/// in "struct CommonType"). +struct BTFDataSec { + uint32_t Type; ///< A BTF_KIND_VAR type + uint32_t Offset; ///< In-section offset + uint32_t Size; ///< Occupied memory size +}; + /// The .BTF.ext section header definition. struct ExtHeader { uint16_t Magic; diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp index d00bc015835..01d3b9e9d00 100644 --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -302,6 +302,45 @@ void BTFTypeFunc::completeType(BTFDebug &BDebug) { void BTFTypeFunc::emitType(MCStreamer &OS) { BTFTypeBase::emitType(OS); } +BTFKindVar::BTFKindVar(StringRef VarName, uint32_t TypeId, uint32_t VarInfo) + : Name(VarName) { + Kind = BTF::BTF_KIND_VAR; + BTFType.Info = Kind << 24; + BTFType.Type = TypeId; + Info = VarInfo; +} + +void BTFKindVar::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); +} + +void BTFKindVar::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + OS.EmitIntValue(Info, 4); +} + +BTFKindDataSec::BTFKindDataSec(AsmPrinter *AsmPrt, std::string SecName) + : Asm(AsmPrt), Name(SecName) { + Kind = BTF::BTF_KIND_DATASEC; + BTFType.Info = Kind << 24; + BTFType.Size = 0; +} + +void BTFKindDataSec::completeType(BTFDebug &BDebug) { + BTFType.NameOff = BDebug.addString(Name); + BTFType.Info |= Vars.size(); +} + +void BTFKindDataSec::emitType(MCStreamer &OS) { + BTFTypeBase::emitType(OS); + + for (const auto &V : Vars) { + OS.EmitIntValue(std::get<0>(V), 4); + Asm->EmitLabelReference(std::get<1>(V), 4); + OS.EmitIntValue(std::get<2>(V), 4); + } +} + uint32_t BTFStringTable::addString(StringRef S) { // Check whether the string already exists. for (auto &OffsetM : OffsetToIdMap) { @@ -322,11 +361,13 @@ BTFDebug::BTFDebug(AsmPrinter *AP) addString("\0"); } -void BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry, - const DIType *Ty) { +uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry, + const DIType *Ty) { TypeEntry->setId(TypeEntries.size() + 1); - DIToIdMap[Ty] = TypeEntry->getId(); + uint32_t Id = TypeEntry->getId(); + DIToIdMap[Ty] = Id; TypeEntries.push_back(std::move(TypeEntry)); + return Id; } uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry) { @@ -336,7 +377,7 @@ uint32_t BTFDebug::addType(std::unique_ptr<BTFTypeBase> TypeEntry) { return Id; } -void BTFDebug::visitBasicType(const DIBasicType *BTy) { +void BTFDebug::visitBasicType(const DIBasicType *BTy, uint32_t &TypeId) { // Only int types are supported in BTF. uint32_t Encoding = BTy->getEncoding(); if (Encoding != dwarf::DW_ATE_boolean && Encoding != dwarf::DW_ATE_signed && @@ -349,7 +390,7 @@ void BTFDebug::visitBasicType(const DIBasicType *BTy) { // DIToIdMap for cross-type reference check. auto TypeEntry = llvm::make_unique<BTFTypeInt>( Encoding, BTy->getSizeInBits(), BTy->getOffsetInBits(), BTy->getName()); - addType(std::move(TypeEntry), BTy); + TypeId = addType(std::move(TypeEntry), BTy); } /// Handle subprogram or subroutine types. @@ -370,7 +411,7 @@ void BTFDebug::visitSubroutineType( if (ForSubprog) TypeId = addType(std::move(TypeEntry)); // For subprogram else - addType(std::move(TypeEntry), STy); // For func ptr + TypeId = addType(std::move(TypeEntry), STy); // For func ptr // Visit return type and func arg types. for (const auto Element : Elements) { @@ -379,7 +420,8 @@ void BTFDebug::visitSubroutineType( } /// Handle structure/union types. -void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct) { +void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct, + uint32_t &TypeId) { const DINodeArray Elements = CTy->getElements(); uint32_t VLen = Elements.size(); if (VLen > BTF::MAX_VLEN) @@ -397,16 +439,16 @@ void BTFDebug::visitStructType(const DICompositeType *CTy, bool IsStruct) { auto TypeEntry = llvm::make_unique<BTFTypeStruct>(CTy, IsStruct, HasBitField, VLen); - addType(std::move(TypeEntry), CTy); + TypeId = addType(std::move(TypeEntry), CTy); // Visit all struct members. for (const auto *Element : Elements) visitTypeEntry(cast<DIDerivedType>(Element)); } -void BTFDebug::visitArrayType(const DICompositeType *CTy) { +void BTFDebug::visitArrayType(const DICompositeType *CTy, uint32_t &TypeId) { auto TypeEntry = llvm::make_unique<BTFTypeArray>(CTy); - addType(std::move(TypeEntry), CTy); + TypeId = addType(std::move(TypeEntry), CTy); // The IR does not have a type for array index while BTF wants one. // So create an array index type if there is none. @@ -420,74 +462,82 @@ void BTFDebug::visitArrayType(const DICompositeType *CTy) { visitTypeEntry(CTy->getBaseType().resolve()); } -void BTFDebug::visitEnumType(const DICompositeType *CTy) { +void BTFDebug::visitEnumType(const DICompositeType *CTy, uint32_t &TypeId) { DINodeArray Elements = CTy->getElements(); uint32_t VLen = Elements.size(); if (VLen > BTF::MAX_VLEN) return; auto TypeEntry = llvm::make_unique<BTFTypeEnum>(CTy, VLen); - addType(std::move(TypeEntry), CTy); + TypeId = addType(std::move(TypeEntry), CTy); // No need to visit base type as BTF does not encode it. } /// Handle structure/union forward declarations. -void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion) { +void BTFDebug::visitFwdDeclType(const DICompositeType *CTy, bool IsUnion, + uint32_t &TypeId) { auto TypeEntry = llvm::make_unique<BTFTypeFwd>(CTy->getName(), IsUnion); - addType(std::move(TypeEntry), CTy); + TypeId = addType(std::move(TypeEntry), CTy); } /// Handle structure, union, array and enumeration types. -void BTFDebug::visitCompositeType(const DICompositeType *CTy) { +void BTFDebug::visitCompositeType(const DICompositeType *CTy, + uint32_t &TypeId) { auto Tag = CTy->getTag(); if (Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { // Handle forward declaration differently as it does not have members. if (CTy->isForwardDecl()) - visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type); + visitFwdDeclType(CTy, Tag == dwarf::DW_TAG_union_type, TypeId); else - visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type); + visitStructType(CTy, Tag == dwarf::DW_TAG_structure_type, TypeId); } else if (Tag == dwarf::DW_TAG_array_type) - visitArrayType(CTy); + visitArrayType(CTy, TypeId); else if (Tag == dwarf::DW_TAG_enumeration_type) - visitEnumType(CTy); + visitEnumType(CTy, TypeId); } /// Handle pointer, typedef, const, volatile, restrict and member types. -void BTFDebug::visitDerivedType(const DIDerivedType *DTy) { +void BTFDebug::visitDerivedType(const DIDerivedType *DTy, uint32_t &TypeId) { unsigned Tag = DTy->getTag(); if (Tag == dwarf::DW_TAG_pointer_type || Tag == dwarf::DW_TAG_typedef || Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || Tag == dwarf::DW_TAG_restrict_type) { auto TypeEntry = llvm::make_unique<BTFTypeDerived>(DTy, Tag); - addType(std::move(TypeEntry), DTy); + TypeId = addType(std::move(TypeEntry), DTy); } else if (Tag != dwarf::DW_TAG_member) { return; } // Visit base type of pointer, typedef, const, volatile, restrict or // struct/union member. - visitTypeEntry(DTy->getBaseType().resolve()); + visitTypeEntry(DTy->getBaseType().resolve(), TypeId); } -void BTFDebug::visitTypeEntry(const DIType *Ty) { - if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) +void BTFDebug::visitTypeEntry(const DIType *Ty, uint32_t &TypeId) { + if (!Ty || DIToIdMap.find(Ty) != DIToIdMap.end()) { + TypeId = DIToIdMap[Ty]; return; + } - uint32_t TypeId; if (const auto *BTy = dyn_cast<DIBasicType>(Ty)) - visitBasicType(BTy); + visitBasicType(BTy, TypeId); else if (const auto *STy = dyn_cast<DISubroutineType>(Ty)) visitSubroutineType(STy, false, std::unordered_map<uint32_t, StringRef>(), TypeId); else if (const auto *CTy = dyn_cast<DICompositeType>(Ty)) - visitCompositeType(CTy); + visitCompositeType(CTy, TypeId); else if (const auto *DTy = dyn_cast<DIDerivedType>(Ty)) - visitDerivedType(DTy); + visitDerivedType(DTy, TypeId); else llvm_unreachable("Unknown DIType"); } +void BTFDebug::visitTypeEntry(const DIType *Ty) { + uint32_t TypeId; + visitTypeEntry(Ty, TypeId); +} + /// Read file contents from the actual file or from the source std::string BTFDebug::populateFileContent(const DISubprogram *SP) { auto File = SP->getFile(); @@ -746,7 +796,7 @@ void BTFDebug::beginInstruction(const MachineInstr *MI) { PrevInstLoc = DL; } -void BTFDebug::endModule() { +void BTFDebug::processGlobals() { // Collect all types referenced by globals. const Module *M = MMI->getModule(); for (const GlobalVariable &Global : M->globals()) { @@ -756,11 +806,65 @@ void BTFDebug::endModule() { SmallVector<DIGlobalVariableExpression *, 1> GVs; Global.getDebugInfo(GVs); + uint32_t GVTypeId = 0; for (auto *GVE : GVs) { - visitTypeEntry(GVE->getVariable()->getType().resolve()); + visitTypeEntry(GVE->getVariable()->getType().resolve(), GVTypeId); + break; + } + + // Only support the following globals: + // . static variables + // . non-static global variables with section attributes + // Essentially means: + // . .bcc/.data/.rodata DataSec entities only contain static data + // . Other DataSec entities contain static or initialized global data. + // Initialized global data are mostly used for finding map key/value type + // id's. Whether DataSec is readonly or not can be found from + // corresponding ELF section flags. + auto Linkage = Global.getLinkage(); + if (Linkage != GlobalValue::InternalLinkage && + (Linkage != GlobalValue::ExternalLinkage || !Global.hasSection())) + continue; + + uint32_t GVarInfo = Linkage == GlobalValue::ExternalLinkage + ? BTF::VAR_GLOBAL_ALLOCATED + : BTF::VAR_STATIC; + auto VarEntry = + llvm::make_unique<BTFKindVar>(Global.getName(), GVTypeId, GVarInfo); + uint32_t VarId = addType(std::move(VarEntry)); + + // Decide the section name. + std::string SecName; + if (Global.hasSection()) { + SecName = Global.getSection().str(); + } else { + // data, bss, or readonly sections + if (Global.isConstant()) + SecName += ".rodata"; + else + SecName += Global.getInitializer()->isZeroValue() ? ".bss" : ".data"; } + + // Find or create a DataSec + if (DataSecEntries.find(SecName) == DataSecEntries.end()) { + DataSecEntries[SecName] = llvm::make_unique<BTFKindDataSec>(Asm, SecName); + } + + // Calculate symbol size + const DataLayout &DL = Global.getParent()->getDataLayout(); + uint32_t Size = DL.getTypeAllocSize(Global.getType()->getElementType()); + + DataSecEntries[SecName]->addVar(VarId, Asm->getSymbol(&Global), Size); } + for (auto &DataSec : DataSecEntries) + addType(std::move(DataSec.second)); +} + +void BTFDebug::endModule() { + // Collect all global types/variables. + processGlobals(); + // Complete BTF type cross refereences. for (const auto &TypeEntry : TypeEntries) TypeEntry->completeType(*this); diff --git a/llvm/lib/Target/BPF/BTFDebug.h b/llvm/lib/Target/BPF/BTFDebug.h index 5a50b0810ca..016cc985283 100644 --- a/llvm/lib/Target/BPF/BTFDebug.h +++ b/llvm/lib/Target/BPF/BTFDebug.h @@ -153,6 +153,37 @@ public: void emitType(MCStreamer &OS); }; +/// 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() { return BTFTypeBase::getSize() + 4; } + void completeType(BTFDebug &BDebug); + void emitType(MCStreamer &OS); +}; + +/// 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() { + return BTFTypeBase::getSize() + BTF::BTFDataSecVarSize * Vars.size(); + } + void addVar(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); + void emitType(MCStreamer &OS); +}; + /// String table. class BTFStringTable { /// String table size in bytes. @@ -201,11 +232,13 @@ class BTFDebug : public DebugHandlerBase { std::unordered_map<uint32_t, std::vector<BTFFuncInfo>> FuncInfoTable; std::unordered_map<uint32_t, std::vector<BTFLineInfo>> LineInfoTable; StringMap<std::vector<std::string>> FileContent; + std::unordered_map<std::string, std::unique_ptr<BTFKindDataSec>> + DataSecEntries; /// Add types to TypeEntries. /// @{ /// Add types to TypeEntries and DIToIdMap. - void addType(std::unique_ptr<BTFTypeBase> TypeEntry, const DIType *Ty); + 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); /// @} @@ -213,17 +246,20 @@ class BTFDebug : public DebugHandlerBase { /// IR type visiting functions. /// @{ void visitTypeEntry(const DIType *Ty); - void visitBasicType(const DIBasicType *BTy); + void visitTypeEntry(const DIType *Ty, uint32_t &TypeId); + 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); - void visitCompositeType(const DICompositeType *CTy); - void visitStructType(const DICompositeType *STy, bool IsStruct); - void visitArrayType(const DICompositeType *ATy); - void visitEnumType(const DICompositeType *ETy); - void visitDerivedType(const DIDerivedType *DTy); + 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); /// @} /// Get the file content for the subprogram. Certain lines of the file @@ -234,6 +270,9 @@ class BTFDebug : public DebugHandlerBase { void constructLineInfo(const DISubprogram *SP, MCSymbol *Label, uint32_t Line, uint32_t Column); + /// Generate types and variables for globals. + void processGlobals(void); + /// Emit common header of .BTF and .BTF.ext sections. void emitCommonHeader(); |

