Index: llvm/trunk/include/llvm/MC/MCBTFContext.h =================================================================== --- llvm/trunk/include/llvm/MC/MCBTFContext.h +++ llvm/trunk/include/llvm/MC/MCBTFContext.h @@ -0,0 +1,364 @@ +//===- MCBTFContext.h ---------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// This header file contains two parts. The first part is the BTF ELF +// specification in C format, and the second part is the various +// C++ classes to manipulate the data structure in order to generate +// the BTF related ELF sections. +//===----------------------------------------------------------------------===// +#ifndef LLVM_MC_MCBTFCONTEXT_H +#define LLVM_MC_MCBTFCONTEXT_H + +#include + +#define BTF_MAGIC 0xeB9F +#define BTF_VERSION 1 + +struct btf_header { + __u16 magic; + __u8 version; + __u8 flags; + __u32 hdr_len; + + /* All offsets are in bytes relative to the end of this header */ + __u32 type_off; /* offset of type section */ + __u32 type_len; /* length of type section */ + __u32 str_off; /* offset of string section */ + __u32 str_len; /* length of string section */ +}; + +/* Max # of type identifier */ +#define BTF_MAX_TYPE 0x0000ffff +/* Max offset into the string section */ +#define BTF_MAX_NAME_OFFSET 0x0000ffff +/* Max # of struct/union/enum members or func args */ +#define BTF_MAX_VLEN 0xffff + +struct btf_type { + __u32 name_off; + /* "info" bits arrangement + * bits 0-15: vlen (e.g. # of struct's members) + * bits 16-23: unused + * bits 24-27: kind (e.g. int, ptr, array...etc) + * bits 28-31: unused + */ + __u32 info; + /* "size" is used by INT, ENUM, STRUCT and UNION. + * "size" tells the size of the type it is describing. + * + * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + * FUNC and FUNC_PROTO. + * "type" is a type_id referring to another type. + */ + union { + __u32 size; + __u32 type; + }; +}; + +#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f) +#define BTF_INFO_VLEN(info) ((info) & 0xffff) + +#define BTF_KIND_UNKN 0 /* Unknown */ +#define BTF_KIND_INT 1 /* Integer */ +#define BTF_KIND_PTR 2 /* Pointer */ +#define BTF_KIND_ARRAY 3 /* Array */ +#define BTF_KIND_STRUCT 4 /* Struct */ +#define BTF_KIND_UNION 5 /* Union */ +#define BTF_KIND_ENUM 6 /* Enumeration */ +#define BTF_KIND_FWD 7 /* Forward */ +#define BTF_KIND_TYPEDEF 8 /* Typedef */ +#define BTF_KIND_VOLATILE 9 /* Volatile */ +#define BTF_KIND_CONST 10 /* Const */ +#define BTF_KIND_RESTRICT 11 /* Restrict */ +#define BTF_KIND_FUNC 12 /* Function */ +#define BTF_KIND_FUNC_PROTO 13 /* Function Prototype */ +#define BTF_KIND_MAX 13 +#define NR_BTF_KINDS 14 + +/* For some specific BTF_KIND, "struct btf_type" is immediately + * followed by extra data. + */ + +/* BTF_KIND_INT is followed by a u32 and the following + * is the 32 bits arrangement: + */ +#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24) +#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16) +#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff) + +/* Attributes stored in the BTF_INT_ENCODING */ +#define BTF_INT_SIGNED (1 << 0) +#define BTF_INT_CHAR (1 << 1) +#define BTF_INT_BOOL (1 << 2) + +/* BTF_KIND_ENUM is followed by multiple "struct btf_enum". + * The exact number of btf_enum is stored in the vlen (of the + * info in "struct btf_type"). + */ +struct btf_enum { + __u32 name_off; + __s32 val; +}; + +/* BTF_KIND_ARRAY is followed by one "struct btf_array" */ +struct btf_array { + __u32 type; + __u32 index_type; + __u32 nelems; +}; + +/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed + * by multiple "struct btf_member". The exact number + * of btf_member is stored in the vlen (of the info in + * "struct btf_type"). + */ +struct btf_member { + __u32 name_off; + __u32 type; + __u32 offset; /* offset in bits */ +}; + +/* .BTF.ext section contains func_info and line_info. + */ +struct btf_ext_header { + __u16 magic; + __u8 version; + __u8 flags; + __u32 hdr_len; + + __u32 func_info_off; + __u32 func_info_len; + __u32 line_info_off; + __u32 line_info_len; +}; + +struct bpf_func_info { + __u32 insn_offset; + __u32 type_id; +}; + +struct btf_sec_func_info { + __u32 sec_name_off; + __u32 num_func_info; +}; + +struct bpf_line_info { + __u32 insn_offset; + __u32 file_name_off; + __u32 line_off; + __u32 line_col; /* line num: line_col >> 10, col num: line_col & 0x3ff */ +}; + +struct btf_sec_line_info { + __u32 sec_name_off; + __u32 num_line_info; +}; + +namespace llvm { + +const char *const btf_kind_str[NR_BTF_KINDS] = { + [BTF_KIND_UNKN] = "UNKNOWN", + [BTF_KIND_INT] = "INT", + [BTF_KIND_PTR] = "PTR", + [BTF_KIND_ARRAY] = "ARRAY", + [BTF_KIND_STRUCT] = "STRUCT", + [BTF_KIND_UNION] = "UNION", + [BTF_KIND_ENUM] = "ENUM", + [BTF_KIND_FWD] = "FWD", + [BTF_KIND_TYPEDEF] = "TYPEDEF", + [BTF_KIND_VOLATILE] = "VOLATILE", + [BTF_KIND_CONST] = "CONST", + [BTF_KIND_RESTRICT] = "RESTRICT", + [BTF_KIND_FUNC] = "FUNC", + [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", +}; + +#include "llvm/ADT/SmallVector.h" +#include + +class MCBTFContext; +class MCObjectStreamer; + +// This is base class of all BTF KIND. It is also used directly +// by the reference kinds: +// BTF_KIND_CONST, BTF_KIND_PTR, BTF_KIND_VOLATILE, +// BTF_KIND_TYPEDEF, BTF_KIND_RESTRICT, and BTF_KIND_FWD +class BTFTypeEntry { +protected: + size_t Id; /* type index in the BTF list, started from 1 */ + struct btf_type BTFType; + +public: + BTFTypeEntry(size_t id, struct btf_type &type) : + Id(id), BTFType(type) {} + unsigned char getKind() { return BTF_INFO_KIND(BTFType.info); } + void setId(size_t Id) { this->Id = Id; } + size_t getId() { return Id; } + void setNameOff(unsigned NameOff) { BTFType.name_off = NameOff; } + + unsigned getTypeIndex() { return BTFType.type; } + unsigned getNameOff() { return BTFType.name_off; } + virtual size_t getSize() { return sizeof(struct btf_type); } + virtual void print(raw_ostream &s, MCBTFContext& BTFContext); + virtual void emitData(MCObjectStreamer *MCOS); +}; + +// BTF_KIND_INT +class BTFTypeEntryInt : public BTFTypeEntry { + unsigned IntVal; // encoding, offset, bits + +public: + BTFTypeEntryInt(size_t id, struct btf_type &type, unsigned intval) : + BTFTypeEntry(id, type), IntVal(intval) {} + size_t getSize() { return BTFTypeEntry::getSize() + sizeof(unsigned); } + void print(raw_ostream &s, MCBTFContext& BTFContext); + void emitData(MCObjectStreamer *MCOS); +}; + +// BTF_KIND_ENUM +class BTFTypeEntryEnum : public BTFTypeEntry { + std::vector EnumValues; + +public: + BTFTypeEntryEnum(size_t id, struct btf_type &type, + std::vector &values) : + BTFTypeEntry(id, type), EnumValues(values) {} + size_t getSize() { + return BTFTypeEntry::getSize() + + BTF_INFO_VLEN(BTFType.info) * sizeof(struct btf_enum); + } + void print(raw_ostream &s, MCBTFContext& BTFContext); + void emitData(MCObjectStreamer *MCOS); +}; + +// BTF_KIND_ARRAY +class BTFTypeEntryArray : public BTFTypeEntry { + struct btf_array ArrayInfo; + +public: + BTFTypeEntryArray(size_t id, struct btf_type &type, + struct btf_array &arrayinfo) : + BTFTypeEntry(id, type), ArrayInfo(arrayinfo) {} + size_t getSize() { + return BTFTypeEntry::getSize() + sizeof(struct btf_array); + } + void print(raw_ostream &s, MCBTFContext& BTFContext); + void emitData(MCObjectStreamer *MCOS); +}; + +// BTF_KIND_STRUCT and BTF_KIND_UNION +class BTFTypeEntryStruct : public BTFTypeEntry { + std::vector Members; + +public: + BTFTypeEntryStruct(size_t id, struct btf_type &type, + std::vector &members) : + BTFTypeEntry(id, type), Members(members) {} + size_t getSize() { + return BTFTypeEntry::getSize() + + BTF_INFO_VLEN(BTFType.info) * sizeof(struct btf_member); + } + void print(raw_ostream &s, MCBTFContext& BTFContext); + void emitData(MCObjectStreamer *MCOS); +}; + +// BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO +class BTFTypeEntryFunc : public BTFTypeEntry { + std::vector Parameters; + +public: + BTFTypeEntryFunc(size_t id, struct btf_type &type, + std::vector ¶ms) : + BTFTypeEntry(id, type), Parameters(params) {} + size_t getSize() { + return BTFTypeEntry::getSize() + + BTF_INFO_VLEN(BTFType.info) * sizeof(unsigned); + } + void print(raw_ostream &s, MCBTFContext& BTFContext); + void emitData(MCObjectStreamer *MCOS); +}; + +class BTFStringTable { + size_t Size; // total size in bytes + std::map OffsetToIdMap; + std::vector Table; + + public: + BTFStringTable() : Size(0) {} + size_t getSize() { return Size; } + std::vector &getTable() { return Table; } + size_t addString(std::string S) { + // check whether the string already exists + for (auto &OffsetM : OffsetToIdMap) { + if (Table[OffsetM.second] == S) + return OffsetM.first; + } + // not find, add to the string table + size_t Offset = Size; + OffsetToIdMap[Offset] = Table.size(); + Table.push_back(S); + Size += S.size() + 1; + return Offset; + } + std::string &getStringAtOffset(size_t Offset) { + return Table[OffsetToIdMap[Offset]]; + } + void showTable(raw_ostream &OS) { + for (auto OffsetM : OffsetToIdMap) + OS << OffsetM.first << " : " << Table[OffsetM.second] + << "\n"; + } +}; + +struct BTFFuncInfo { + const MCSymbol *Label; + unsigned int TypeId; +}; + +struct BTFLineInfo { + MCSymbol *Label; + unsigned int FileNameOff; + unsigned int LineOff; + unsigned int LineNum; + unsigned int ColumnNum; +}; + +class MCBTFContext { + std::vector> TypeEntries; + BTFStringTable StringTable; + std::map> FuncInfoTable; + std::map> LineInfoTable; + + friend class BTFTypeEntry; + friend class BTFTypeEntryInt; + friend class BTFTypeEntryEnum; + friend class BTFTypeEntryArray; + friend class BTFTypeEntryStruct; + friend class BTFTypeEntryFunc; + +public: + void dump(raw_ostream& OS); + void emitAll(MCObjectStreamer *MCOS); + void emitCommonHeader(MCObjectStreamer *MCOS); + void emitBTFSection(MCObjectStreamer *MCOS); + void emitBTFExtSection(MCObjectStreamer *MCOS); + + size_t addString(std::string S) { + return StringTable.addString(S); + } + void addTypeEntry(std::unique_ptr Entry); + void addFuncInfo(unsigned SecNameOff, BTFFuncInfo Info) { + FuncInfoTable[SecNameOff].push_back(Info); + } + void addLineInfo(unsigned SecNameOff, BTFLineInfo Info) { + LineInfoTable[SecNameOff].push_back(Info); + } +}; + +} +#endif Index: llvm/trunk/include/llvm/MC/MCContext.h =================================================================== --- llvm/trunk/include/llvm/MC/MCContext.h +++ llvm/trunk/include/llvm/MC/MCContext.h @@ -56,6 +56,7 @@ class MCSymbolWasm; class SMLoc; class SourceMgr; + class MCBTFContext; /// Context object for machine code objects. This class owns all of the /// sections that it creates. @@ -278,6 +279,9 @@ /// Map of currently defined macros. StringMap MacroMap; + /// for BTF debug information + std::unique_ptr BTFCtx; + public: explicit MCContext(const MCAsmInfo *MAI, const MCRegisterInfo *MRI, const MCObjectFileInfo *MOFI, @@ -286,6 +290,9 @@ MCContext &operator=(const MCContext &) = delete; ~MCContext(); + void setBTFContext(std::unique_ptr Ctx); + std::unique_ptr &getBTFContext() { return BTFCtx; } + const SourceMgr *getSourceManager() const { return SrcMgr; } void setInlineSourceManager(SourceMgr *SM) { InlineSrcMgr = SM; } Index: llvm/trunk/include/llvm/MC/MCObjectFileInfo.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectFileInfo.h +++ llvm/trunk/include/llvm/MC/MCObjectFileInfo.h @@ -207,6 +207,10 @@ MCSection *SXDataSection; MCSection *GFIDsSection; + // BTF specific sections. + MCSection *BTFSection; + MCSection *BTFExtSection; + public: void InitMCObjectFileInfo(const Triple &TT, bool PIC, MCContext &ctx, bool LargeCodeModel = false); @@ -372,6 +376,10 @@ return EHFrameSection; } + // BTF specific sections. + MCSection *getBTFSection() const { return BTFSection; } + MCSection *getBTFExtSection() const { return BTFExtSection; } + enum Environment { IsMachO, IsELF, IsCOFF, IsWasm }; Environment getObjectFileType() const { return Env; } Index: llvm/trunk/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectStreamer.h +++ llvm/trunk/include/llvm/MC/MCObjectStreamer.h @@ -138,6 +138,7 @@ unsigned PointerSize); void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, const MCSymbol *Label); + void EmitBTFAdvanceLineAddr(const MCSymbol *Label, unsigned Size); void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, StringRef FileName, SMLoc Loc) override; Index: llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ llvm/trunk/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -17,6 +17,7 @@ DwarfFile.cpp DwarfStringPool.cpp DwarfUnit.cpp + Dwarf2BTF.cpp EHStreamer.cpp ErlangGCPrinter.cpp OcamlGCPrinter.cpp Index: llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.h @@ -0,0 +1,134 @@ +//===- Dwarf2BTF.h -------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_DWARF2BTF_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_DWARF2BTF_H + +#include "DwarfUnit.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" +#include "llvm/MC/MCBTFContext.h" +#include + +namespace llvm { + +class Dwarf2BTF; +class MCBTFContext; + +#define BTF_INVALID_ENCODING 0xff + +class Die2BTFEntry { +protected: + const DIE &Die; + size_t Id; /* type index in the BTF list, started from 1 */ + struct btf_type BTFType; + +public: + // Return desired BTF_KIND for the Die, return BTF_KIND_UNKN for + // invalid/unsupported Die + static unsigned char getDieKind(const DIE &Die); + + // Return proper BTF_INT_ENCODING of a basetype. + // Return BTF_INVALID_ENCODING for unsupported (float, etc.) + static unsigned char getBaseTypeEncoding(const DIE &Die); + + // Return whether this Die should be skipped. + // We currently skip unsupported data type (e.g. float) + // and references to unsupported types + static bool shouldSkipDie(const DIE &Die); + + static std::unique_ptr dieToBTFTypeEntry(const DIE &Die); + + Die2BTFEntry(const DIE &Die); + void setId(size_t Id) { this->Id = Id; } + size_t getId() { return Id; } + virtual void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +// BTF_KIND_INT +class Die2BTFEntryInt : public Die2BTFEntry { + __u32 IntVal; // encoding, offset, bits + +public: + Die2BTFEntryInt(const DIE &Die); + void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +// BTF_KIND_ENUM +class Die2BTFEntryEnum : public Die2BTFEntry { + std::vector EnumValues; + +public: + Die2BTFEntryEnum(const DIE &Die); + void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +// BTF_KIND_ARRAY +class Die2BTFEntryArray : public Die2BTFEntry { + struct btf_array ArrayInfo; + +public: + Die2BTFEntryArray(const DIE &Die); + void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +// BTF_KIND_STRUCT and BTF_KIND_UNION +class Die2BTFEntryStruct : public Die2BTFEntry { + std::vector Members; + +public: + Die2BTFEntryStruct(const DIE &Die); + void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +// BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO +class Die2BTFEntryFunc : public Die2BTFEntry { + std::vector<__u32> Parameters; + +public: + Die2BTFEntryFunc(const DIE &Die); + void completeData(class Dwarf2BTF &Dwarf2BTF); +}; + +class Dwarf2BTF { + std::vector> TypeEntries; + std::map DieToIdMap; + std::unique_ptr BTFContext; + MCContext &OuterCtx; + bool IsLE; + +public: + Dwarf2BTF(MCContext &Context, bool IsLittleEndian); + bool isLittleEndian() { return IsLE; } + void addDwarfCU(DwarfUnit *TheU); + void finish(); + __u32 getTypeIndex(DIE &Die) { + DIE *DiePtr = const_cast(&Die); + assert((DieToIdMap.find(DiePtr) != DieToIdMap.end()) && + "Die not added to in the BTFContext"); + return DieToIdMap[DiePtr]; + } + size_t addBTFString(std::string S) { + return BTFContext->addString(S); + } + void addBTFTypeEntry(std::unique_ptr Entry); + void addBTFFuncInfo(unsigned SecNameOff, BTFFuncInfo FuncInfo) { + BTFContext->addFuncInfo(SecNameOff, FuncInfo); + } + +private: + void addTypeEntry(const DIE &Die); + bool alreadyAdded(DIE &Die) { + return DieToIdMap.find(const_cast(&Die)) != DieToIdMap.end(); + } + void completeData(); +}; + +} +#endif Index: llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp @@ -0,0 +1,501 @@ +//===- Dwarf2BTF.cpp ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DwarfUnit.h" +#include "Dwarf2BTF.h" +#include "llvm/MC/MCBTFContext.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" + +namespace llvm { + +unsigned char Die2BTFEntry::getDieKind(const DIE & Die) { + auto Tag = Die.getTag(); + + switch (Tag) { + case dwarf::DW_TAG_base_type: + if (getBaseTypeEncoding(Die) == BTF_INVALID_ENCODING) + return BTF_KIND_UNKN; + return BTF_KIND_INT; + case dwarf::DW_TAG_const_type: + return BTF_KIND_CONST; + case dwarf::DW_TAG_pointer_type: + return BTF_KIND_PTR; + case dwarf::DW_TAG_restrict_type: + return BTF_KIND_RESTRICT; + case dwarf::DW_TAG_volatile_type: + return BTF_KIND_VOLATILE; + case dwarf::DW_TAG_typedef: + return BTF_KIND_TYPEDEF; + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + if (Die.findAttribute(dwarf::DW_AT_declaration).getType() + != DIEValue::isNone) + return BTF_KIND_FWD; + else + return BTF_KIND_STRUCT; + case dwarf::DW_TAG_union_type: + if (Die.findAttribute(dwarf::DW_AT_declaration).getType() + != DIEValue::isNone) + return BTF_KIND_FWD; + else + return BTF_KIND_UNION; + case dwarf::DW_TAG_enumeration_type: + return BTF_KIND_ENUM; + case dwarf::DW_TAG_array_type: + return BTF_KIND_ARRAY; + case dwarf::DW_TAG_subprogram: + return BTF_KIND_FUNC; + case dwarf::DW_TAG_subroutine_type: + return BTF_KIND_FUNC_PROTO; + default: + break; + } + + return BTF_KIND_UNKN; +} + +std::unique_ptr Die2BTFEntry::dieToBTFTypeEntry(const DIE &Die) { + unsigned char Kind = getDieKind(Die); + + switch (Kind) { + case BTF_KIND_INT: + return make_unique(Die); + case BTF_KIND_PTR: + case BTF_KIND_TYPEDEF: + case BTF_KIND_VOLATILE: + case BTF_KIND_CONST: + case BTF_KIND_RESTRICT: + case BTF_KIND_FWD: + return make_unique(Die); + case BTF_KIND_ARRAY: + return make_unique(Die); + case BTF_KIND_STRUCT: + case BTF_KIND_UNION: + return make_unique(Die); + case BTF_KIND_ENUM: + return make_unique(Die); + case BTF_KIND_FUNC: + case BTF_KIND_FUNC_PROTO: + return make_unique(Die); + default: + break; + } + return nullptr; +} + +bool Die2BTFEntry::shouldSkipDie(const DIE &Die) { + auto Tag = Die.getTag(); + + switch (Tag) { + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_restrict_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_volatile_type: + { + auto TypeV = Die.findAttribute(dwarf::DW_AT_type); + if (TypeV.getType() == DIEValue::isNone) + return false; + auto &TypeDie = TypeV.getDIEEntry().getEntry(); + return Die2BTFEntry::shouldSkipDie(TypeDie); + } + default: + return getDieKind(Die) == BTF_KIND_UNKN; + } + return true; +} +unsigned char Die2BTFEntry::getBaseTypeEncoding(const DIE &Die) { + auto V = Die.findAttribute(dwarf::DW_AT_encoding); + + if (V.getType() != DIEValue::isInteger) + return BTF_INVALID_ENCODING; + + switch (V.getDIEInteger().getValue()) { + case dwarf::DW_ATE_boolean: + return BTF_INT_BOOL; + case dwarf::DW_ATE_signed: + return BTF_INT_SIGNED; + case dwarf::DW_ATE_signed_char: + return BTF_INT_CHAR; + case dwarf::DW_ATE_unsigned: + return 0; + case dwarf::DW_ATE_unsigned_char: + return BTF_INT_CHAR; + case dwarf::DW_ATE_imaginary_float: + case dwarf::DW_ATE_packed_decimal: + case dwarf::DW_ATE_numeric_string: + case dwarf::DW_ATE_edited: + case dwarf::DW_ATE_signed_fixed: + case dwarf::DW_ATE_address: + case dwarf::DW_ATE_complex_float: + case dwarf::DW_ATE_float: + default: + break; + } + return BTF_INVALID_ENCODING; +} + +Die2BTFEntry::Die2BTFEntry(const DIE &Die) : Die(Die) { + unsigned char Kind = getDieKind(Die); + + switch (Kind) { + case BTF_KIND_CONST: + case BTF_KIND_FWD: + case BTF_KIND_PTR: + case BTF_KIND_RESTRICT: + case BTF_KIND_TYPEDEF: + case BTF_KIND_VOLATILE: + break; + default: + assert("Invalid Die passed into BTFTypeEntry()"); + break; + } + + BTFType.info = (Kind & 0xf) << 24; +} + +void Die2BTFEntry::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto TypeV = Die.findAttribute(dwarf::DW_AT_type); + if (TypeV.getType() == DIEValue::isNone) { + BTFType.type = 0; + } else { + auto &TypeDie = TypeV.getDIEEntry().getEntry(); + auto Type = Dwarf2BTF.getTypeIndex(TypeDie); + BTFType.type = Type; + } + + unsigned char Kind = getDieKind(Die); + if (Kind != BTF_KIND_FWD) { + BTFType.name_off = 0; + } else { + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + auto Str = NameV.getDIEString().getString(); + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + } + + auto typeEntry = make_unique(Id, BTFType); + Dwarf2BTF.addBTFTypeEntry(std::move(typeEntry)); +} + +Die2BTFEntryInt::Die2BTFEntryInt(const DIE &Die) : Die2BTFEntry(Die) { + unsigned char Kind = getDieKind(Die); + + switch (Kind) { + case BTF_KIND_INT: + break; + default: + assert("Invalid Die passed into BTFTypeEntryInt()"); + break; + } + + // handle BTF_INT_ENCODING in IntVal + auto Encoding = Die2BTFEntry::getBaseTypeEncoding(Die); + assert((Encoding != BTF_INVALID_ENCODING) && + "Invalid Die passed to BTFTypeEntryInt()"); + __u32 IntVal = (Encoding & 0xf) << 24; + + // handle BTF_INT_OFFSET in IntVal + auto V = Die.findAttribute(dwarf::DW_AT_bit_offset); + if (V.getType() == DIEValue::isInteger) + IntVal |= (V.getDIEInteger().getValue() & 0xff) << 16; + + // get btf_type.size + V = Die.findAttribute(dwarf::DW_AT_byte_size); + __u32 Size = V.getDIEInteger().getValue() & 0xffffffff; + +// handle BTF_INT_BITS in IntVal + V = Die.findAttribute(dwarf::DW_AT_bit_size); + if (V.getType() == DIEValue::isInteger) + IntVal |= V.getDIEInteger().getValue() & 0xff; + else + IntVal |= (Size << 3) & 0xff; + + BTFType.info = BTF_KIND_INT << 24; + BTFType.size = Size; + this->IntVal = IntVal; +} + +void Die2BTFEntryInt::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + auto TypeV = Die.findAttribute(dwarf::DW_AT_type); + auto Str = NameV.getDIEString().getString(); + + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + + auto typeEntry = make_unique(Id, BTFType, IntVal); + Dwarf2BTF.addBTFTypeEntry(std::move(typeEntry)); +} + +Die2BTFEntryEnum::Die2BTFEntryEnum(const DIE &Die) : Die2BTFEntry(Die) { + // get btf_type.size + auto V = Die.findAttribute(dwarf::DW_AT_byte_size); + __u32 Size = V.getDIEInteger().getValue() & 0xffffffff; + + int Vlen = 0; + for (auto &ChildDie : Die.children()) + if (ChildDie.getTag() == dwarf::DW_TAG_enumerator) + Vlen++; + + BTFType.info = (BTF_KIND_ENUM << 24) | (Vlen & BTF_MAX_VLEN); + BTFType.type = Size; +} + +void Die2BTFEntryEnum::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto TypeV = Die.findAttribute(dwarf::DW_AT_type); + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + + if (NameV.getType() != DIEValue::isNone) { + auto Str = NameV.getDIEString().getString(); + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + } else + BTFType.name_off = 0; + + for (auto &ChildDie : Die.children()) { + struct btf_enum BTFEnum; + auto ChildNameV = ChildDie.findAttribute(dwarf::DW_AT_name); + auto Str = ChildNameV.getDIEString().getString(); + + BTFEnum.name_off = Dwarf2BTF.addBTFString(Str); + auto ChildValueV = ChildDie.findAttribute(dwarf::DW_AT_const_value); + BTFEnum.val = (__s32)(ChildValueV.getDIEInteger().getValue()); + + EnumValues.push_back(BTFEnum); + } + + auto typeEntry = make_unique(Id, BTFType, EnumValues); + Dwarf2BTF.addBTFTypeEntry(std::move(typeEntry)); +} + +Die2BTFEntryArray::Die2BTFEntryArray(const DIE &Die) : + Die2BTFEntry(Die) { + BTFType.info = (BTF_KIND_ARRAY << 24); + BTFType.size = 0; +} + +void Die2BTFEntryArray::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + + std::string Str; + if (NameV.getType() != DIEValue::isNone) + Str = NameV.getDIEString().getString(); + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + + auto &ArrayTypeDie = Die.findAttribute(dwarf::DW_AT_type).getDIEEntry().getEntry(); + ArrayInfo.type = Dwarf2BTF.getTypeIndex(ArrayTypeDie); + + // The number of elements should count all subranges + unsigned Nelems = 1; + bool IsFirstSubrange = true; + for (auto &ChildDie : Die.children()) { + if (ChildDie.getTag() == dwarf::DW_TAG_subrange_type) { + if (IsFirstSubrange) { + auto TypeV = ChildDie.findAttribute(dwarf::DW_AT_type); + auto &TypeDie = TypeV.getDIEEntry().getEntry(); + ArrayInfo.index_type = Dwarf2BTF.getTypeIndex(TypeDie); + IsFirstSubrange = false; + } + auto CountV = ChildDie.findAttribute(dwarf::DW_AT_count); + if (CountV.getType() == DIEValue::isNone) { + // array like a[] which essentially a pointer + Nelems = 0; + break; + } + Nelems *= (__u32)(CountV.getDIEInteger().getValue()); + } + } + ArrayInfo.nelems = Nelems; + + auto TypeEntry = make_unique(Id, BTFType, ArrayInfo); + Dwarf2BTF.addBTFTypeEntry(std::move(TypeEntry)); +} + +Die2BTFEntryStruct::Die2BTFEntryStruct(const DIE &Die) : Die2BTFEntry(Die) { + // get btf_type.size + auto V = Die.findAttribute(dwarf::DW_AT_byte_size); + __u32 Size = V.getDIEInteger().getValue() & 0xffffffff; + auto Kind = Die2BTFEntry::getDieKind(Die); + + int Vlen = 0; + for (auto &ChildDie : Die.children()) + if (ChildDie.getTag() == dwarf::DW_TAG_member) + Vlen++; + + BTFType.size = Size; + BTFType.info = (Kind << 24) | (Vlen & BTF_MAX_VLEN); +} + +void Die2BTFEntryStruct::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + + if (NameV.getType() != DIEValue::isNone) { + auto Str = NameV.getDIEString().getString(); + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + } else + BTFType.name_off = 0; + + + for (auto &ChildDie : Die.children()) { + if (ChildDie.getTag() != dwarf::DW_TAG_member) + continue; + + struct btf_member BTFMember; + auto ChildNameV = ChildDie.findAttribute(dwarf::DW_AT_name); + + if (ChildNameV.getType() != DIEValue::isNone) { + auto Str = ChildNameV.getDIEString().getString(); + BTFMember.name_off = Dwarf2BTF.addBTFString(Str); + } else + BTFMember.name_off = 0; + + auto TypeV = ChildDie.findAttribute(dwarf::DW_AT_type); + auto &TypeDie = TypeV.getDIEEntry().getEntry(); + BTFMember.type = Dwarf2BTF.getTypeIndex(TypeDie); + + auto MemLocV = ChildDie.findAttribute(dwarf::DW_AT_data_member_location); + unsigned MemLoc = MemLocV.getDIEInteger().getValue() * 8; + + auto ByteSizeV = ChildDie.findAttribute(dwarf::DW_AT_byte_size); + if (ByteSizeV.getType() != DIEValue::isNone) { + unsigned ByteSize = ByteSizeV.getDIEInteger().getValue(); + auto BitOffsetV = ChildDie.findAttribute(dwarf::DW_AT_bit_offset); + unsigned BitOffset = BitOffsetV.getDIEInteger().getValue(); + auto BitSizeV = ChildDie.findAttribute(dwarf::DW_AT_bit_size); + unsigned BitSize = BitSizeV.getDIEInteger().getValue(); + if (Dwarf2BTF.isLittleEndian()) + MemLoc += ByteSize * 8 - BitSize - BitOffset; + else + MemLoc += BitOffset; + } + BTFMember.offset = MemLoc; + + Members.push_back(BTFMember); + } + + auto typeEntry = make_unique(Id, BTFType, Members); + Dwarf2BTF.addBTFTypeEntry(std::move(typeEntry)); +} + +Die2BTFEntryFunc::Die2BTFEntryFunc(const DIE &Die) : Die2BTFEntry(Die) { + auto Kind = Die2BTFEntry::getDieKind(Die); + + int Vlen = 0; + for (auto &ChildDie : Die.children()) + if (ChildDie.getTag() == dwarf::DW_TAG_formal_parameter) + Vlen++; + + BTFType.size = 0; + BTFType.info = (Kind << 24) | (Vlen & BTF_MAX_VLEN); +} + +void Die2BTFEntryFunc::completeData(class Dwarf2BTF &Dwarf2BTF) { + auto NameV = Die.findAttribute(dwarf::DW_AT_name); + if (NameV.getType() == DIEValue::isNone) { + BTFType.name_off = 0; + } else { + auto Str = NameV.getDIEString().getString(); + BTFType.name_off = Dwarf2BTF.addBTFString(Str); + } + + auto RetTypeV = Die.findAttribute(dwarf::DW_AT_type); + if (RetTypeV.getType() != DIEValue::isNone) { + auto &TypeDie = RetTypeV.getDIEEntry().getEntry(); + BTFType.type = Dwarf2BTF.getTypeIndex(TypeDie); + } else { + BTFType.type = 0; + } + + for (auto &ChildDie : Die.children()) { + if (ChildDie.getTag() == dwarf::DW_TAG_formal_parameter) { + auto TypeV = ChildDie.findAttribute(dwarf::DW_AT_abstract_origin); + if (TypeV.getType() != DIEValue::isNone) { + auto &AbsOriginDie = TypeV.getDIEEntry().getEntry(); + assert(AbsOriginDie.getTag() == dwarf::DW_TAG_formal_parameter); + TypeV = AbsOriginDie.findAttribute(dwarf::DW_AT_type); + } else { + TypeV = ChildDie.findAttribute(dwarf::DW_AT_type); + } + auto &TypeDie = TypeV.getDIEEntry().getEntry(); + Parameters.push_back(Dwarf2BTF.getTypeIndex(TypeDie)); + } else if (ChildDie.getTag() == dwarf::DW_TAG_unspecified_parameters) { + Parameters.push_back(0); + } + } + + auto typeEntry = make_unique(Id, BTFType, Parameters); + Dwarf2BTF.addBTFTypeEntry(std::move(typeEntry)); + + if (BTF_INFO_KIND(BTFType.info) == BTF_KIND_FUNC) { + auto LowPCV = Die.findAttribute(dwarf::DW_AT_low_pc); + if (LowPCV.getType() != DIEValue::isNone) { + const MCSymbol *Label = LowPCV.getDIELabel().getValue(); + BTFFuncInfo FuncInfo; + unsigned SecNameOff; + + FuncInfo.Label = Label; + FuncInfo.TypeId = Id; + if (Label->isInSection()) { + MCSection &Section = Label->getSection(); + MCSectionELF *SectionELF = dyn_cast(&Section); + assert(SectionELF); + SecNameOff = Dwarf2BTF.addBTFString(SectionELF->getSectionName().str()); + } else { + SecNameOff = Dwarf2BTF.addBTFString(".text"); + } + Dwarf2BTF.addBTFFuncInfo(SecNameOff, FuncInfo); + } + } +} + +Dwarf2BTF::Dwarf2BTF(MCContext &Context, bool IsLittleEndian) + : OuterCtx(Context), IsLE(IsLittleEndian) { + BTFContext = make_unique(); +} + +void Dwarf2BTF::addTypeEntry(const DIE &Die) { + for (auto &ChildDie : Die.children()) + addTypeEntry(ChildDie); + if (Die2BTFEntry::shouldSkipDie(Die)) + return; + auto Kind = Die2BTFEntry::getDieKind(Die); + if (Kind != BTF_KIND_UNKN) { + auto TypeEntry = Die2BTFEntry::dieToBTFTypeEntry(Die); + if (TypeEntry != nullptr) { + TypeEntry->setId(TypeEntries.size() + 1); + DieToIdMap[const_cast(&Die)] = TypeEntry->getId(); + TypeEntries.push_back(std::move(TypeEntry)); + } + } +} + +void Dwarf2BTF::addBTFTypeEntry(std::unique_ptr Entry) { + BTFContext->addTypeEntry(std::move(Entry)); +} + +void Dwarf2BTF::completeData() { + BTFContext->addString("\0"); + + for (auto &TypeEntry : TypeEntries) + TypeEntry->completeData(*this); +} + +void Dwarf2BTF::addDwarfCU(DwarfUnit *TheU) { + DIE &CuDie = TheU->getUnitDie(); + + assert((CuDie.getTag() == dwarf::DW_TAG_compile_unit) && + "Not a compile unit"); + addTypeEntry(CuDie); +} + +void Dwarf2BTF::finish() { + completeData(); + OuterCtx.setBTFContext(std::move(BTFContext)); +} + +} Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -567,6 +567,9 @@ /// Emit the reference to the section. void emitSectionReference(const DwarfCompileUnit &CU); + // Emit the BTF sections + void emitBTFSection(bool IsLittleEndian); + protected: /// Gather pre-function debug information. void beginFunctionImpl(const MachineFunction *MF) override; Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -971,6 +971,10 @@ // Emit the pubnames and pubtypes sections if requested. emitDebugPubSections(); + const Triple &TT = Asm->TM.getTargetTriple(); + if (TT.getArch() == Triple::bpfel || TT.getArch() == Triple::bpfeb) + emitBTFSection(TT.getArch() == Triple::bpfel); + // clean up. // FIXME: AbstractVariables.clear(); } @@ -2455,6 +2459,12 @@ return &SplitTypeUnitFileTable; } +void DwarfDebug::emitBTFSection(bool IsLittleEndian) { + DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; + + Holder.emitBTFSection(IsLittleEndian); +} + uint64_t DwarfDebug::makeTypeSignature(StringRef Identifier) { MD5 Hash; Hash.update(Identifier); Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -114,6 +114,9 @@ void emitStrings(MCSection *StrSection, MCSection *OffsetSection = nullptr, bool UseRelativeOffsets = false); + // Emit all data for the BTF section + void emitBTFSection(bool IsLittleEndian); + /// Returns the string pool. DwarfStringPool &getStringPool() { return StrPool; } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "Dwarf2BTF.h" #include "DwarfFile.h" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" @@ -15,6 +16,8 @@ #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" #include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/MC/MCBTFContext.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include #include @@ -88,6 +91,13 @@ StrPool.emit(*Asm, StrSection, OffsetSection, UseRelativeOffsets); } +void DwarfFile::emitBTFSection(bool IsLittleEndian) { + Dwarf2BTF Dwarf2BTF(Asm->OutContext, IsLittleEndian); + for (auto &TheU : CUs) + Dwarf2BTF.addDwarfCU(TheU.get()); + Dwarf2BTF.finish(); +} + bool DwarfFile::addScopeVariable(LexicalScope *LS, DbgVariable *Var) { auto &ScopeVars = ScopeVariables[LS]; const DILocalVariable *DV = Var->getVariable(); Index: llvm/trunk/lib/MC/CMakeLists.txt =================================================================== --- llvm/trunk/lib/MC/CMakeLists.txt +++ llvm/trunk/lib/MC/CMakeLists.txt @@ -10,11 +10,13 @@ MCAsmMacro.cpp MCAsmStreamer.cpp MCAssembler.cpp + MCBTFContext.cpp MCCodeEmitter.cpp MCCodePadder.cpp MCCodeView.cpp MCContext.cpp MCDwarf.cpp + MCDwarf2BTF.cpp MCELFObjectTargetWriter.cpp MCELFStreamer.cpp MCExpr.cpp Index: llvm/trunk/lib/MC/MCBTFContext.cpp =================================================================== --- llvm/trunk/lib/MC/MCBTFContext.cpp +++ llvm/trunk/lib/MC/MCBTFContext.cpp @@ -0,0 +1,235 @@ +//===- lib/MC/MCBTFContext.cpp - Machine Code BTF Context -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCBTFContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "btf" + +void MCBTFContext::addTypeEntry(std::unique_ptr Entry) { + TypeEntries.push_back(std::move(Entry)); +} + +void MCBTFContext::dump(raw_ostream &OS) { + OS << "Type Table:\n"; + for (size_t i = 0; i < TypeEntries.size(); i++) { + auto TypeEntry = TypeEntries[i].get(); + TypeEntry->print(OS, *this); + } + + OS << "\nString Table:\n"; + StringTable.showTable(OS); + + OS << "\nFuncInfo Table:\n"; + for (auto &FuncSec : FuncInfoTable) { + OS << "sec_name_off=" << FuncSec.first << "\n"; + for (auto &FuncInfo : FuncSec.second) { + OS << "\tinsn_offset= type_id=" + << FuncInfo.TypeId << "\n"; + } + } + + OS << "\nLineInfo Table:\n"; + for (auto &LineSec : LineInfoTable) { + OS << "sec_name_off=" << LineSec.first << "\n"; + for (auto &LineInfo : LineSec.second) { + OS << "\tinsn_offset= file_name_off=" + << LineInfo.FileNameOff + << " line_off=" << LineInfo.LineOff + << " line_num=" << LineInfo.LineNum + << " column_num=" << LineInfo.ColumnNum + << "\n"; + } + } +} + +void MCBTFContext::emitCommonHeader(MCObjectStreamer *MCOS) { + MCOS->EmitIntValue(BTF_MAGIC, 2); + MCOS->EmitIntValue(BTF_VERSION, 1); + MCOS->EmitIntValue(0, 1); +} + +void MCBTFContext::emitBTFSection(MCObjectStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + MCOS->SwitchSection(context.getObjectFileInfo()->getBTFSection()); + + // emit header + emitCommonHeader(MCOS); + MCOS->EmitIntValue(sizeof(struct btf_header), 4); + + uint32_t type_len = 0, str_len; + for (auto &TypeEntry : TypeEntries) + type_len += TypeEntry->getSize(); + str_len = StringTable.getSize(); + + MCOS->EmitIntValue(0, 4); + MCOS->EmitIntValue(type_len, 4); + MCOS->EmitIntValue(type_len, 4); + MCOS->EmitIntValue(str_len, 4); + + // emit type table + for (auto &TypeEntry: TypeEntries) + TypeEntry->emitData(MCOS); + + // emit string table + for (auto &S : StringTable.getTable()) { + for (auto C : S) + MCOS->EmitIntValue(C, 1); + MCOS->EmitIntValue('\0', 1); + } +} + +void MCBTFContext::emitBTFExtSection(MCObjectStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + MCOS->SwitchSection(context.getObjectFileInfo()->getBTFExtSection()); + + // emit header + emitCommonHeader(MCOS); + MCOS->EmitIntValue(sizeof(struct btf_ext_header), 4); + + uint32_t func_len = 0, line_len = 0; + for (auto &FuncSec : FuncInfoTable) { + func_len += sizeof(struct btf_sec_func_info); + func_len += FuncSec.second.size() * sizeof(struct bpf_func_info); + } + for (auto &LineSec : LineInfoTable) { + line_len += sizeof(struct btf_sec_line_info); + line_len += LineSec.second.size() * sizeof(struct bpf_line_info); + } + + MCOS->EmitIntValue(0, 4); + MCOS->EmitIntValue(func_len, 4); + MCOS->EmitIntValue(func_len, 4); + MCOS->EmitIntValue(line_len, 4); + + // emit func_info table + for (const auto &FuncSec : FuncInfoTable) { + MCOS->EmitIntValue(FuncSec.first, 4); + MCOS->EmitIntValue(FuncSec.second.size(), 4); + for (const auto &FuncInfo : FuncSec.second) { + MCOS->EmitBTFAdvanceLineAddr(FuncInfo.Label, 4); + MCOS->EmitIntValue(FuncInfo.TypeId, 4); + } + } + + // emit line_info table + for (const auto &LineSec : LineInfoTable) { + MCOS->EmitIntValue(LineSec.first, 4); + MCOS->EmitIntValue(LineSec.second.size(), 4); + for (const auto &LineInfo : LineSec.second) { + MCOS->EmitBTFAdvanceLineAddr(LineInfo.Label, 4); + MCOS->EmitIntValue(LineInfo.FileNameOff, 4); + MCOS->EmitIntValue(LineInfo.LineOff, 4); + MCOS->EmitIntValue(LineInfo.LineNum << 10 | LineInfo.ColumnNum, 4); + } + } +} + +void MCBTFContext::emitAll(MCObjectStreamer *MCOS) { + LLVM_DEBUG(dump(dbgs())); + emitBTFSection(MCOS); + emitBTFExtSection(MCOS); +} + +void BTFTypeEntry::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + OS << "[" << Id << "] " + << btf_kind_str[BTF_INFO_KIND(BTFType.info)] + << " name_off=" << BTFType.name_off + << " info=" << format("0x%08lx", BTFType.info) + << " size/type=" << BTFType.size << "\n"; +} + +void BTFTypeEntry::emitData(MCObjectStreamer *MCOS) { + MCOS->EmitIntValue(BTFType.name_off, 4); + MCOS->EmitIntValue(BTFType.info, 4); + MCOS->EmitIntValue(BTFType.size, 4); +} + +void BTFTypeEntryInt::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + BTFTypeEntry::print(OS, MCBTFContext); + OS << "\tdesc=" << format("0x%08lx", IntVal) << "\n"; +} + +void BTFTypeEntryInt::emitData(MCObjectStreamer *MCOS) { + BTFTypeEntry::emitData(MCOS); + MCOS->EmitIntValue(IntVal, 4); +} + +void BTFTypeEntryEnum::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + BTFTypeEntry::print(OS, MCBTFContext); + for (size_t i = 0; i < BTF_INFO_VLEN(BTFType.info); i++) { + auto &EnumValue = EnumValues[i]; + OS << "\tname_off=" << EnumValue.name_off + << " value=" << EnumValue.val << "\n"; + } +} + +void BTFTypeEntryEnum::emitData(MCObjectStreamer *MCOS) { + BTFTypeEntry::emitData(MCOS); + for (auto &EnumValue : EnumValues) { + MCOS->EmitIntValue(EnumValue.name_off, 4); + MCOS->EmitIntValue(EnumValue.val, 4); + } +} + +void BTFTypeEntryArray::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + BTFTypeEntry::print(OS, MCBTFContext); + OS << "\telem_type=" << format("0x%08lx", ArrayInfo.type) + << " index_type=" << format("0x%08lx", ArrayInfo.index_type) + << " num_element=" << ArrayInfo.nelems << "\n"; +} + +void BTFTypeEntryArray::emitData(MCObjectStreamer *MCOS) { + BTFTypeEntry::emitData(MCOS); + MCOS->EmitIntValue(ArrayInfo.type, 4); + MCOS->EmitIntValue(ArrayInfo.index_type, 4); + MCOS->EmitIntValue(ArrayInfo.nelems, 4); +} + +void BTFTypeEntryStruct::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + BTFTypeEntry::print(OS, MCBTFContext); + for (size_t i = 0; i < BTF_INFO_VLEN(BTFType.info); i++) { + auto &Member = Members[i]; + OS << "\tname_off=" << Member.name_off + << " type=" << Member.type + << " bit_offset=" << Member.offset << "\n"; + } +} + +void BTFTypeEntryStruct::emitData(MCObjectStreamer *MCOS) { + BTFTypeEntry::emitData(MCOS); + for (auto &Member : Members) { + MCOS->EmitIntValue(Member.name_off, 4); + MCOS->EmitIntValue(Member.type, 4); + MCOS->EmitIntValue(Member.offset, 4); + } +} + +void BTFTypeEntryFunc::print(raw_ostream &OS, MCBTFContext& MCBTFContext) { + BTFTypeEntry::print(OS, MCBTFContext); + for (size_t i = 0; i < BTF_INFO_VLEN(BTFType.info); i++) { + auto Parameter = Parameters[i]; + OS << "\tparam_type=" << Parameter << "\n"; + } +} + +void BTFTypeEntryFunc::emitData(MCObjectStreamer *MCOS) { + BTFTypeEntry::emitData(MCOS); + for (auto &Parameter: Parameters) + MCOS->EmitIntValue(Parameter, 4); +} Index: llvm/trunk/lib/MC/MCContext.cpp =================================================================== --- llvm/trunk/lib/MC/MCContext.cpp +++ llvm/trunk/lib/MC/MCContext.cpp @@ -17,6 +17,7 @@ #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCBTFContext.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" @@ -60,7 +61,7 @@ : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi), Symbols(Allocator), UsedNames(Allocator), CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), - AutoReset(DoAutoReset) { + AutoReset(DoAutoReset), BTFCtx(nullptr) { SecureLogFile = AsSecureLogFileName; if (SrcMgr && SrcMgr->getNumBuffers()) @@ -114,6 +115,14 @@ GenDwarfFileNumber = 0; HadError = false; + BTFCtx.reset(); +} + +//===----------------------------------------------------------------------===// +// BTFCtx Manipulation +//===----------------------------------------------------------------------===// +void MCContext::setBTFContext(std::unique_ptr Ctx) { + BTFCtx = std::move(Ctx); } //===----------------------------------------------------------------------===// Index: llvm/trunk/lib/MC/MCDwarf2BTF.h =================================================================== --- llvm/trunk/lib/MC/MCDwarf2BTF.h +++ llvm/trunk/lib/MC/MCDwarf2BTF.h @@ -0,0 +1,29 @@ +//===- MCDwarf2BTF.h ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_MC_MCDWARF2BTF_H +#define LLVM_LIB_MC_MCDWARF2BTF_H + +#include "llvm/MC/MCDwarf.h" + +namespace llvm { + +using FileContent = std::pair>; + +class MCDwarf2BTF { +public: + static void addFiles(MCObjectStreamer *MCOS, std::string &FileName, + std::vector &Files); + static void addLines(MCObjectStreamer *MCOS, StringRef &SectionName, + std::vector &Files, + const MCLineSection::MCDwarfLineEntryCollection &LineEntries); + static void addDwarfLineInfo(MCObjectStreamer *MCOS); +}; + +} +#endif Index: llvm/trunk/lib/MC/MCDwarf2BTF.cpp =================================================================== --- llvm/trunk/lib/MC/MCDwarf2BTF.cpp +++ llvm/trunk/lib/MC/MCDwarf2BTF.cpp @@ -0,0 +1,99 @@ +//===- MCDwarf2BTF.cpp ---------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCDwarf2BTF.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCBTFContext.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" +#include + +using namespace llvm; + +void MCDwarf2BTF::addFiles(MCObjectStreamer *MCOS, std::string &FileName, + std::vector &Files) { + std::vector Content; + + std::ifstream Inputfile(FileName); + std::string Line; + Content.push_back(Line); // line 0 for empty string + while (std::getline(Inputfile, Line)) + Content.push_back(Line); + + Files.push_back(FileContent(FileName, Content)); +} + +void MCDwarf2BTF::addLines(MCObjectStreamer *MCOS, StringRef &SectionName, + std::vector &Files, + const MCLineSection::MCDwarfLineEntryCollection &LineEntries) { + MCContext &Context = MCOS->getContext(); + auto &BTFCxt = Context.getBTFContext(); + + unsigned SecNameOff = BTFCxt->addString(SectionName.str()); + for (const MCDwarfLineEntry &LineEntry : LineEntries) { + BTFLineInfo LineInfo; + unsigned FileNum = LineEntry.getFileNum(); + unsigned Line = LineEntry.getLine(); + + LineInfo.Label = LineEntry.getLabel(); + if (FileNum < Files.size()) { + LineInfo.FileNameOff = BTFCxt->addString(Files[FileNum].first); + if (Line < Files[FileNum].second.size()) + LineInfo.LineOff = BTFCxt->addString(Files[FileNum].second[Line]); + else + LineInfo.LineOff = 0; + } else { + LineInfo.FileNameOff = 0; + LineInfo.LineOff = 0; + } + LineInfo.LineNum = Line; + LineInfo.ColumnNum = LineEntry.getColumn(); + BTFCxt->addLineInfo(SecNameOff, LineInfo); + } +} + +void MCDwarf2BTF::addDwarfLineInfo(MCObjectStreamer *MCOS) { + MCContext &Context = MCOS->getContext(); + + auto &LineTables = Context.getMCDwarfLineTables(); + if (LineTables.empty()) + return; + + for (const auto &CUIDTablePair : LineTables) { + std::vector Dirs; + std::vector Files; + + for (auto &Dir : CUIDTablePair.second.getMCDwarfDirs()) + Dirs.push_back(Dir); + for (auto &File : CUIDTablePair.second.getMCDwarfFiles()) { + std::string FileName; + if (File.DirIndex == 0) + FileName = File.Name; + else + FileName = Dirs[File.DirIndex - 1] + "/" + File.Name; + MCDwarf2BTF::addFiles(MCOS, FileName, Files); + } + for (const auto &LineSec: CUIDTablePair.second.getMCLineSections().getMCLineEntries()) { + MCSection *Section = LineSec.first; + const MCLineSection::MCDwarfLineEntryCollection &LineEntries = LineSec.second; + + StringRef SectionName; + if (MCSectionELF *SectionELF = dyn_cast(Section)) + SectionName = SectionELF->getSectionName(); + else + return; + MCDwarf2BTF::addLines(MCOS, SectionName, Files, LineEntries); + } + } +} Index: llvm/trunk/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectFileInfo.cpp +++ llvm/trunk/lib/MC/MCObjectFileInfo.cpp @@ -468,6 +468,9 @@ Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags); StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0); + + BTFSection = Ctx->getELFSection(".BTF", ELF::SHT_PROGBITS, 0); + BTFExtSection = Ctx->getELFSection(".BTF.ext", ELF::SHT_PROGBITS, 0); } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { Index: llvm/trunk/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectStreamer.cpp +++ llvm/trunk/lib/MC/MCObjectStreamer.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCBTFContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" @@ -21,6 +22,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SourceMgr.h" +#include "MCDwarf2BTF.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, @@ -439,6 +441,31 @@ insert(new MCDwarfCallFrameFragment(*AddrDelta)); } +void MCObjectStreamer::EmitBTFAdvanceLineAddr(const MCSymbol *Label, + unsigned Size) { + const MCExpr *Value = MCSymbolRefExpr::create(Label, getContext()); + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + SMLoc Loc; + + if (Value->evaluateAsAbsolute(AbsValue, getAssemblerPtr())) { + if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) { + getContext().reportError( + Loc, "value evaluated as " + Twine(AbsValue) + " is out of range."); + return; + } + EmitIntValue(AbsValue, Size); + return; + } + + DF->getFixups().push_back( + MCFixup::create(DF->getContents().size(), Value, + MCFixup::getKindForSize(Size, false), Loc)); + DF->getContents().resize(DF->getContents().size() + Size, 0); +} + void MCObjectStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt, @@ -688,6 +715,13 @@ // Dump out the dwarf file & directory tables and line tables. MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams()); + auto &BTFCtx = getContext().getBTFContext(); + if (BTFCtx) { + MCDwarf2BTF::addDwarfLineInfo(this); + BTFCtx->emitAll(this); + BTFCtx.reset(); + } + flushPendingLabels(); getAssembler().Finish(); }