summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/MC/MCBTFContext.h364
-rw-r--r--llvm/include/llvm/MC/MCContext.h7
-rw-r--r--llvm/include/llvm/MC/MCObjectFileInfo.h8
-rw-r--r--llvm/include/llvm/MC/MCObjectStreamer.h1
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt1
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp501
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.h134
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp10
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h3
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp10
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DwarfFile.h3
-rw-r--r--llvm/lib/MC/CMakeLists.txt2
-rw-r--r--llvm/lib/MC/MCBTFContext.cpp235
-rw-r--r--llvm/lib/MC/MCContext.cpp11
-rw-r--r--llvm/lib/MC/MCDwarf2BTF.cpp99
-rw-r--r--llvm/lib/MC/MCDwarf2BTF.h29
-rw-r--r--llvm/lib/MC/MCObjectFileInfo.cpp3
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp34
18 files changed, 1454 insertions, 1 deletions
diff --git a/llvm/include/llvm/MC/MCBTFContext.h b/llvm/include/llvm/MC/MCBTFContext.h
new file mode 100644
index 00000000000..f180a69340b
--- /dev/null
+++ b/llvm/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 <linux/types.h>
+
+#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 <map>
+
+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<struct btf_enum> EnumValues;
+
+public:
+ BTFTypeEntryEnum(size_t id, struct btf_type &type,
+ std::vector<struct btf_enum> &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<struct btf_member> Members;
+
+public:
+ BTFTypeEntryStruct(size_t id, struct btf_type &type,
+ std::vector<struct btf_member> &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<unsigned> Parameters;
+
+public:
+ BTFTypeEntryFunc(size_t id, struct btf_type &type,
+ std::vector<unsigned> &params) :
+ 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<size_t, unsigned> OffsetToIdMap;
+ std::vector<std::string> Table;
+
+ public:
+ BTFStringTable() : Size(0) {}
+ size_t getSize() { return Size; }
+ std::vector<std::string> &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<std::unique_ptr<BTFTypeEntry>> TypeEntries;
+ BTFStringTable StringTable;
+ std::map<unsigned, std::vector<BTFFuncInfo>> FuncInfoTable;
+ std::map<unsigned, std::vector<BTFLineInfo>> 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<BTFTypeEntry> Entry);
+ void addFuncInfo(unsigned SecNameOff, BTFFuncInfo Info) {
+ FuncInfoTable[SecNameOff].push_back(Info);
+ }
+ void addLineInfo(unsigned SecNameOff, BTFLineInfo Info) {
+ LineInfoTable[SecNameOff].push_back(Info);
+ }
+};
+
+}
+#endif
diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h
index 3b8ac8b79e2..d5c49408c68 100644
--- a/llvm/include/llvm/MC/MCContext.h
+++ b/llvm/include/llvm/MC/MCContext.h
@@ -56,6 +56,7 @@ namespace llvm {
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 @@ namespace llvm {
/// Map of currently defined macros.
StringMap<MCAsmMacro> MacroMap;
+ /// for BTF debug information
+ std::unique_ptr<MCBTFContext> BTFCtx;
+
public:
explicit MCContext(const MCAsmInfo *MAI, const MCRegisterInfo *MRI,
const MCObjectFileInfo *MOFI,
@@ -286,6 +290,9 @@ namespace llvm {
MCContext &operator=(const MCContext &) = delete;
~MCContext();
+ void setBTFContext(std::unique_ptr<MCBTFContext> Ctx);
+ std::unique_ptr<MCBTFContext> &getBTFContext() { return BTFCtx; }
+
const SourceMgr *getSourceManager() const { return SrcMgr; }
void setInlineSourceManager(SourceMgr *SM) { InlineSrcMgr = SM; }
diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h
index 8cf9e1cc55a..1dda7b0712f 100644
--- a/llvm/include/llvm/MC/MCObjectFileInfo.h
+++ b/llvm/include/llvm/MC/MCObjectFileInfo.h
@@ -207,6 +207,10 @@ protected:
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 @@ public:
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; }
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index c9e577b7e29..9d15086ac63 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -138,6 +138,7 @@ public:
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;
diff --git a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt
index 6cba4a0d4b8..14c895a9c82 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt
+++ b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt
@@ -17,6 +17,7 @@ add_llvm_library(LLVMAsmPrinter
DwarfFile.cpp
DwarfStringPool.cpp
DwarfUnit.cpp
+ Dwarf2BTF.cpp
EHStreamer.cpp
ErlangGCPrinter.cpp
OcamlGCPrinter.cpp
diff --git a/llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp b/llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.cpp
new file mode 100644
index 00000000000..20eab4d1fb8
--- /dev/null
+++ b/llvm/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> Die2BTFEntry::dieToBTFTypeEntry(const DIE &Die) {
+ unsigned char Kind = getDieKind(Die);
+
+ switch (Kind) {
+ case BTF_KIND_INT:
+ return make_unique<Die2BTFEntryInt>(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<Die2BTFEntry>(Die);
+ case BTF_KIND_ARRAY:
+ return make_unique<Die2BTFEntryArray>(Die);
+ case BTF_KIND_STRUCT:
+ case BTF_KIND_UNION:
+ return make_unique<Die2BTFEntryStruct>(Die);
+ case BTF_KIND_ENUM:
+ return make_unique<Die2BTFEntryEnum>(Die);
+ case BTF_KIND_FUNC:
+ case BTF_KIND_FUNC_PROTO:
+ return make_unique<Die2BTFEntryFunc>(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<BTFTypeEntry>(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<BTFTypeEntryInt>(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<BTFTypeEntryEnum>(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<BTFTypeEntryArray>(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<BTFTypeEntryStruct>(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<BTFTypeEntryFunc>(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<MCSectionELF>(&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<MCBTFContext>();
+}
+
+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*>(&Die)] = TypeEntry->getId();
+ TypeEntries.push_back(std::move(TypeEntry));
+ }
+ }
+}
+
+void Dwarf2BTF::addBTFTypeEntry(std::unique_ptr<BTFTypeEntry> 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));
+}
+
+}
diff --git a/llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.h b/llvm/lib/CodeGen/AsmPrinter/Dwarf2BTF.h
new file mode 100644
index 00000000000..3df4dd802a7
--- /dev/null
+++ b/llvm/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 <map>
+
+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<Die2BTFEntry> 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<struct btf_enum> 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<struct btf_member> 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<std::unique_ptr<Die2BTFEntry>> TypeEntries;
+ std::map<DIE*, size_t> DieToIdMap;
+ std::unique_ptr<MCBTFContext> 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*>(&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<BTFTypeEntry> 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*>(&Die)) != DieToIdMap.end();
+ }
+ void completeData();
+};
+
+}
+#endif
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index 94e12658cfe..184ec4dabe9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -971,6 +971,10 @@ void DwarfDebug::endModule() {
// 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 @@ MCDwarfDwoLineTable *DwarfDebug::getDwoLineTable(const DwarfCompileUnit &CU) {
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);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index fecf8056765..1350317db02 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -567,6 +567,9 @@ class DwarfDebug : public DebugHandlerBase {
/// 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;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp
index 0ab9ea87c23..7ac16b34c4c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp
+++ b/llvm/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 <algorithm>
#include <cstdint>
@@ -88,6 +91,13 @@ void DwarfFile::emitStrings(MCSection *StrSection, MCSection *OffsetSection,
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();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
index c315f44a8d8..9aafe2613f6 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.h
@@ -114,6 +114,9 @@ public:
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; }
diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt
index ba36d99e8f7..85bf1616fd6 100644
--- a/llvm/lib/MC/CMakeLists.txt
+++ b/llvm/lib/MC/CMakeLists.txt
@@ -10,11 +10,13 @@ add_llvm_library(LLVMMC
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
diff --git a/llvm/lib/MC/MCBTFContext.cpp b/llvm/lib/MC/MCBTFContext.cpp
new file mode 100644
index 00000000000..cb846ee5e51
--- /dev/null
+++ b/llvm/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 <cstdlib>
+#include <tuple>
+#include <utility>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "btf"
+
+void MCBTFContext::addTypeEntry(std::unique_ptr<BTFTypeEntry> 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=<Omitted> 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=<Omitted> 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);
+}
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
index fab517075c5..18250a474b7 100644
--- a/llvm/lib/MC/MCContext.cpp
+++ b/llvm/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 @@ MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri,
: 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 @@ void MCContext::reset() {
GenDwarfFileNumber = 0;
HadError = false;
+ BTFCtx.reset();
+}
+
+//===----------------------------------------------------------------------===//
+// BTFCtx Manipulation
+//===----------------------------------------------------------------------===//
+void MCContext::setBTFContext(std::unique_ptr<MCBTFContext> Ctx) {
+ BTFCtx = std::move(Ctx);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/MC/MCDwarf2BTF.cpp b/llvm/lib/MC/MCDwarf2BTF.cpp
new file mode 100644
index 00000000000..08a70e6f318
--- /dev/null
+++ b/llvm/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 <fstream>
+
+using namespace llvm;
+
+void MCDwarf2BTF::addFiles(MCObjectStreamer *MCOS, std::string &FileName,
+ std::vector<FileContent> &Files) {
+ std::vector<std::string> 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<FileContent> &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<std::string> Dirs;
+ std::vector<FileContent> 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<MCSectionELF>(Section))
+ SectionName = SectionELF->getSectionName();
+ else
+ return;
+ MCDwarf2BTF::addLines(MCOS, SectionName, Files, LineEntries);
+ }
+ }
+}
diff --git a/llvm/lib/MC/MCDwarf2BTF.h b/llvm/lib/MC/MCDwarf2BTF.h
new file mode 100644
index 00000000000..22d1b7741a5
--- /dev/null
+++ b/llvm/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<std::string, std::vector<std::string>>;
+
+class MCDwarf2BTF {
+public:
+ static void addFiles(MCObjectStreamer *MCOS, std::string &FileName,
+ std::vector<FileContent> &Files);
+ static void addLines(MCObjectStreamer *MCOS, StringRef &SectionName,
+ std::vector<FileContent> &Files,
+ const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
+ static void addDwarfLineInfo(MCObjectStreamer *MCOS);
+};
+
+}
+#endif
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index edfccfcb9ed..bddcf459ac0 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -468,6 +468,9 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
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) {
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 8c88db009bd..4f74f4101c8 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/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 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
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 @@ void MCObjectStreamer::FinishImpl() {
// 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();
}
OpenPOWER on IntegriCloud