621 changes: 598 additions & 23 deletions llvm/lib/DebugInfo/BTF/BTFParser.cpp

Large diffs are not rendered by default.

39 changes: 20 additions & 19 deletions llvm/lib/Target/BPF/BPFAbstractMemberAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
#include "BPFCORE.h"
#include "BPFTargetMachine.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/BTF/BTF.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
Expand Down Expand Up @@ -369,7 +370,7 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
CInfo.Metadata = nullptr;
// Check validity of info_kind as clang did not check this.
uint64_t InfoKind = getConstant(Call->getArgOperand(1));
if (InfoKind >= BPFCoreSharedInfo::MAX_FIELD_RELOC_KIND)
if (InfoKind >= BTF::MAX_FIELD_RELOC_KIND)
report_fatal_error("Incorrect info_kind for llvm.bpf.preserve.field.info intrinsic");
CInfo.AccessIndex = InfoKind;
return true;
Expand All @@ -383,11 +384,11 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_TYPE_INFO_FLAG)
report_fatal_error("Incorrect flag for llvm.bpf.preserve.type.info intrinsic");
if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_EXISTENCE)
CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_EXISTENCE;
CInfo.AccessIndex = BTF::TYPE_EXISTENCE;
else if (Flag == BPFCoreSharedInfo::PRESERVE_TYPE_INFO_MATCH)
CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_MATCH;
CInfo.AccessIndex = BTF::TYPE_MATCH;
else
CInfo.AccessIndex = BPFCoreSharedInfo::TYPE_SIZE;
CInfo.AccessIndex = BTF::TYPE_SIZE;
return true;
}
if (GV->getName().startswith("llvm.bpf.preserve.enum.value")) {
Expand All @@ -399,9 +400,9 @@ bool BPFAbstractMemberAccess::IsPreserveDIAccessIndexCall(const CallInst *Call,
if (Flag >= BPFCoreSharedInfo::MAX_PRESERVE_ENUM_VALUE_FLAG)
report_fatal_error("Incorrect flag for llvm.bpf.preserve.enum.value intrinsic");
if (Flag == BPFCoreSharedInfo::PRESERVE_ENUM_VALUE_EXISTENCE)
CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE_EXISTENCE;
CInfo.AccessIndex = BTF::ENUM_VALUE_EXISTENCE;
else
CInfo.AccessIndex = BPFCoreSharedInfo::ENUM_VALUE;
CInfo.AccessIndex = BTF::ENUM_VALUE;
return true;
}

Expand Down Expand Up @@ -672,11 +673,11 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
uint32_t AccessIndex,
uint32_t PatchImm,
MaybeAlign RecordAlignment) {
if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
return 1;
if (InfoKind == BTF::FIELD_EXISTENCE)
return 1;

uint32_t Tag = CTy->getTag();
if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_OFFSET) {
if (InfoKind == BTF::FIELD_BYTE_OFFSET) {
if (Tag == dwarf::DW_TAG_array_type) {
auto *EltTy = stripQualifiers(CTy->getBaseType());
PatchImm += AccessIndex * calcArraySize(CTy, 1) *
Expand All @@ -695,7 +696,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
return PatchImm;
}

if (InfoKind == BPFCoreSharedInfo::FIELD_BYTE_SIZE) {
if (InfoKind == BTF::FIELD_BYTE_SIZE) {
if (Tag == dwarf::DW_TAG_array_type) {
auto *EltTy = stripQualifiers(CTy->getBaseType());
return calcArraySize(CTy, 1) * (EltTy->getSizeInBits() >> 3);
Expand All @@ -715,7 +716,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
}
}

if (InfoKind == BPFCoreSharedInfo::FIELD_SIGNEDNESS) {
if (InfoKind == BTF::FIELD_SIGNEDNESS) {
const DIType *BaseTy;
if (Tag == dwarf::DW_TAG_array_type) {
// Signedness only checked when final array elements are accessed.
Expand All @@ -741,7 +742,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
return (Encoding == dwarf::DW_ATE_signed || Encoding == dwarf::DW_ATE_signed_char);
}

if (InfoKind == BPFCoreSharedInfo::FIELD_LSHIFT_U64) {
if (InfoKind == BTF::FIELD_LSHIFT_U64) {
// The value is loaded into a value with FIELD_BYTE_SIZE size,
// and then zero or sign extended to U64.
// FIELD_LSHIFT_U64 and FIELD_RSHIFT_U64 are operations
Expand Down Expand Up @@ -778,7 +779,7 @@ uint32_t BPFAbstractMemberAccess::GetFieldInfo(uint32_t InfoKind,
return OffsetInBits + 64 - NextSBitOffset;
}

if (InfoKind == BPFCoreSharedInfo::FIELD_RSHIFT_U64) {
if (InfoKind == BTF::FIELD_RSHIFT_U64) {
DIDerivedType *MemberTy = nullptr;
bool IsBitField = false;
uint32_t SizeInBits;
Expand Down Expand Up @@ -849,7 +850,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,
// we will skip them.
uint32_t FirstIndex = 0;
uint32_t PatchImm = 0; // AccessOffset or the requested field info
uint32_t InfoKind = BPFCoreSharedInfo::FIELD_BYTE_OFFSET;
uint32_t InfoKind = BTF::FIELD_BYTE_OFFSET;
while (CallStack.size()) {
auto StackElem = CallStack.top();
Call = StackElem.first;
Expand Down Expand Up @@ -939,7 +940,7 @@ Value *BPFAbstractMemberAccess::computeBaseAndAccessKey(CallInst *Call,

if (CInfo.Kind == BPFPreserveFieldInfoAI) {
InfoKind = CInfo.AccessIndex;
if (InfoKind == BPFCoreSharedInfo::FIELD_EXISTENCE)
if (InfoKind == BTF::FIELD_EXISTENCE)
PatchImm = 1;
break;
}
Expand Down Expand Up @@ -987,10 +988,10 @@ MDNode *BPFAbstractMemberAccess::computeAccessKey(CallInst *Call,

int64_t PatchImm;
std::string AccessStr("0");
if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_EXISTENCE ||
CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_MATCH) {
if (CInfo.AccessIndex == BTF::TYPE_EXISTENCE ||
CInfo.AccessIndex == BTF::TYPE_MATCH) {
PatchImm = 1;
} else if (CInfo.AccessIndex == BPFCoreSharedInfo::TYPE_SIZE) {
} else if (CInfo.AccessIndex == BTF::TYPE_SIZE) {
// typedef debuginfo type has size 0, get the eventual base type.
DIType *BaseTy = stripQualifiers(Ty, true);
PatchImm = BaseTy->getSizeInBits() / 8;
Expand Down Expand Up @@ -1026,7 +1027,7 @@ MDNode *BPFAbstractMemberAccess::computeAccessKey(CallInst *Call,
EnumIndex++;
}

if (CInfo.AccessIndex == BPFCoreSharedInfo::ENUM_VALUE) {
if (CInfo.AccessIndex == BTF::ENUM_VALUE) {
StringRef EValueStr = ValueStr.substr(Separator + 1);
PatchImm = std::stoll(std::string(EValueStr));
} else {
Expand Down
18 changes: 0 additions & 18 deletions llvm/lib/Target/BPF/BPFCORE.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,6 @@ class Module;

class BPFCoreSharedInfo {
public:
enum PatchableRelocKind : uint32_t {
FIELD_BYTE_OFFSET = 0,
FIELD_BYTE_SIZE,
FIELD_EXISTENCE,
FIELD_SIGNEDNESS,
FIELD_LSHIFT_U64,
FIELD_RSHIFT_U64,
BTF_TYPE_ID_LOCAL,
BTF_TYPE_ID_REMOTE,
TYPE_EXISTENCE,
TYPE_SIZE,
ENUM_VALUE_EXISTENCE,
ENUM_VALUE,
TYPE_MATCH,

MAX_FIELD_RELOC_KIND,
};

enum BTFTypeIdFlag : uint32_t {
BTF_TYPE_ID_LOCAL_RELOC = 0,
BTF_TYPE_ID_REMOTE_RELOC,
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/BPF/BPFPreserveDIType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "BPF.h"
#include "BPFCORE.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/BTF/BTF.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Instruction.h"
Expand Down Expand Up @@ -82,9 +83,9 @@ static bool BPFPreserveDITypeImpl(Function &F) {

uint32_t Reloc;
if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) {
Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL;
Reloc = BTF::BTF_TYPE_ID_LOCAL;
} else {
Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE;
Reloc = BTF::BTF_TYPE_ID_REMOTE;
DIType *Ty = cast<DIType>(MD);
while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
unsigned Tag = DTy->getTag();
Expand Down
6 changes: 2 additions & 4 deletions llvm/lib/Target/BPF/BTFDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1518,10 +1518,8 @@ bool BTFDebug::InstLower(const MachineInstr *MI, MCInst &OutMI) {
return false;
}

if (Reloc == BPFCoreSharedInfo::ENUM_VALUE_EXISTENCE ||
Reloc == BPFCoreSharedInfo::ENUM_VALUE ||
Reloc == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL ||
Reloc == BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE)
if (Reloc == BTF::ENUM_VALUE_EXISTENCE || Reloc == BTF::ENUM_VALUE ||
Reloc == BTF::BTF_TYPE_ID_LOCAL || Reloc == BTF::BTF_TYPE_ID_REMOTE)
OutMI.setOpcode(BPF::LD_imm64);
else
OutMI.setOpcode(BPF::MOV_ri);
Expand Down
154 changes: 154 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-byte-offset.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
; REQUIRES: bpf-registered-target

;; Verify that llvm-objdump can use .BTF.ext to show CO-RE relocation data.

; RUN: llc --mtriple bpfel %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

; RUN: llc --mtriple bpfeb %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

;; Input generated from the following C code:
;;
;; #define __pai __attribute__((preserve_access_index))
;;
;; struct buz {
;; int a;
;; int b;
;; } __pai;
;;
;; struct foo {
;; int :4;
;; int i;
;; struct buz k[10];
;; } __pai;
;;
;; struct bar {
;; struct foo f;
;; } __pai;
;;
;; void * volatile g;
;;
;; void root(void) {
;; struct bar *bar = (void *)0;
;; g = &bar->f;
;; g = &bar->f.i;
;; g = &bar->f.k;
;; g = &bar->f.k[7].a;
;; g = &bar->f.k[7].b;
;; g = &bar[1].f.k[7].b;
;; }
;;
;; Using the following command:
;;
;; clang --target=bpf -g -O2 -emit-llvm -S t.c

; CHECK: CO-RE <byte_off> [[[#bar:]]] struct bar::f (0:0)
; CHECK: CO-RE <byte_off> [[[#bar]]] struct bar::f.i (0:0:0)
; CHECK: CO-RE <byte_off> [[[#bar]]] struct bar::f.k (0:0:1)
; CHECK: CO-RE <byte_off> [[[#bar]]] struct bar::f.k[7].a (0:0:1:7:0)
; CHECK: CO-RE <byte_off> [[[#bar]]] struct bar::f.k[7].b (0:0:1:7:1)
; CHECK: CO-RE <byte_off> [[[#bar]]] struct bar::[1].f.k[7].b (1:0:1:7:1)

@g = dso_local global ptr null, align 8, !dbg !0
@"llvm.bar:0:0$0:0" = external global i64, !llvm.preserve.access.index !14 #0
@"llvm.bar:0:8$0:0:1" = external global i64, !llvm.preserve.access.index !14 #0
@"llvm.bar:0:4$0:0:0" = external global i64, !llvm.preserve.access.index !14 #0
@"llvm.bar:0:64$0:0:1:7:0" = external global i64, !llvm.preserve.access.index !14 #0
@"llvm.bar:0:68$0:0:1:7:1" = external global i64, !llvm.preserve.access.index !14 #0
@"llvm.bar:0:156$1:0:1:7:1" = external global i64, !llvm.preserve.access.index !14 #0

; Function Attrs: nofree nounwind memory(readwrite, argmem: none)
define dso_local void @root() local_unnamed_addr #1 !dbg !29 {
entry:
call void @llvm.dbg.value(metadata ptr null, metadata !33, metadata !DIExpression()), !dbg !34
%0 = load i64, ptr @"llvm.bar:0:0$0:0", align 8
%1 = getelementptr i8, ptr null, i64 %0
%2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %1)
store volatile ptr %2, ptr @g, align 8, !dbg !35, !tbaa !36
%3 = load i64, ptr @"llvm.bar:0:4$0:0:0", align 8
%4 = getelementptr i8, ptr null, i64 %3
%5 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %4)
store volatile ptr %5, ptr @g, align 8, !dbg !40, !tbaa !36
%6 = load i64, ptr @"llvm.bar:0:8$0:0:1", align 8
%7 = getelementptr i8, ptr null, i64 %6
%8 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %7)
store volatile ptr %8, ptr @g, align 8, !dbg !41, !tbaa !36
%9 = load i64, ptr @"llvm.bar:0:64$0:0:1:7:0", align 8
%10 = getelementptr i8, ptr null, i64 %9
%11 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 3, ptr %10)
store volatile ptr %11, ptr @g, align 8, !dbg !42, !tbaa !36
%12 = load i64, ptr @"llvm.bar:0:68$0:0:1:7:1", align 8
%13 = getelementptr i8, ptr null, i64 %12
%14 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 4, ptr %13)
store volatile ptr %14, ptr @g, align 8, !dbg !43, !tbaa !36
%15 = load i64, ptr @"llvm.bar:0:156$1:0:1:7:1", align 8
%16 = getelementptr i8, ptr null, i64 %15
%17 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 5, ptr %16)
store volatile ptr %17, ptr @g, align 8, !dbg !44, !tbaa !36
ret void, !dbg !45
}

; Function Attrs: nofree nosync nounwind memory(none)
declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #2

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.value(metadata, metadata, metadata) #3

attributes #0 = { "btf_ama" }
attributes #1 = { nofree nounwind memory(readwrite, argmem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!24, !25, !26, !27}
!llvm.ident = !{!28}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 18, type: !22, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !4, globals: !21, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "f7c638151153f385e69bef98e88c80ef")
!4 = !{!5, !13}
!5 = !DICompositeType(tag: DW_TAG_array_type, baseType: !6, size: 640, elements: !11)
!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "buz", file: !3, line: 3, size: 64, elements: !7)
!7 = !{!8, !10}
!8 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !6, file: !3, line: 4, baseType: !9, size: 32)
!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !6, file: !3, line: 5, baseType: !9, size: 32, offset: 32)
!11 = !{!12}
!12 = !DISubrange(count: 10)
!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !3, line: 14, size: 704, elements: !15)
!15 = !{!16}
!16 = !DIDerivedType(tag: DW_TAG_member, name: "f", scope: !14, file: !3, line: 15, baseType: !17, size: 704)
!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo", file: !3, line: 8, size: 704, elements: !18)
!18 = !{!19, !20}
!19 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !17, file: !3, line: 10, baseType: !9, size: 32, offset: 32)
!20 = !DIDerivedType(tag: DW_TAG_member, name: "k", scope: !17, file: !3, line: 11, baseType: !5, size: 640, offset: 64)
!21 = !{!0}
!22 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !23)
!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
!24 = !{i32 7, !"Dwarf Version", i32 5}
!25 = !{i32 2, !"Debug Info Version", i32 3}
!26 = !{i32 1, !"wchar_size", i32 4}
!27 = !{i32 7, !"frame-pointer", i32 2}
!28 = !{!"clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)"}
!29 = distinct !DISubprogram(name: "root", scope: !3, file: !3, line: 20, type: !30, scopeLine: 20, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !32)
!30 = !DISubroutineType(types: !31)
!31 = !{null}
!32 = !{!33}
!33 = !DILocalVariable(name: "bar", scope: !29, file: !3, line: 21, type: !13)
!34 = !DILocation(line: 0, scope: !29)
!35 = !DILocation(line: 22, column: 5, scope: !29)
!36 = !{!37, !37, i64 0}
!37 = !{!"any pointer", !38, i64 0}
!38 = !{!"omnipotent char", !39, i64 0}
!39 = !{!"Simple C/C++ TBAA"}
!40 = !DILocation(line: 23, column: 5, scope: !29)
!41 = !DILocation(line: 24, column: 5, scope: !29)
!42 = !DILocation(line: 25, column: 5, scope: !29)
!43 = !DILocation(line: 26, column: 5, scope: !29)
!44 = !DILocation(line: 27, column: 5, scope: !29)
!45 = !DILocation(line: 28, column: 1, scope: !29)
86 changes: 86 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-enum-value.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
; REQUIRES: bpf-registered-target

;; Verify that llvm-objdump can use .BTF.ext to show CO-RE relocation data.

; RUN: llc --mtriple bpfel %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

; RUN: llc --mtriple bpfeb %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

;; Input generated from the following C code:
;;
;; #define __pai __attribute__((preserve_access_index))
;;
;; enum bar { U, V };
;; volatile unsigned long g;
;; void root(void) {
;; g = __builtin_preserve_enum_value(*(enum bar *)U, 0);
;; g = __builtin_preserve_enum_value(*(enum bar *)V, 1);
;; }
;;
;; Using the following command:
;;
;; clang --target=bpf -g -O2 -emit-llvm -S t.c

; CHECK: CO-RE <enumval_exists> [[[#]]] enum bar::U = 0
; CHECK: CO-RE <enumval_value> [[[#]]] enum bar::V = 1

@g = dso_local global i64 0, align 8, !dbg !0
@"llvm.bar:11:1$1" = external global i64, !llvm.preserve.access.index !5 #0
@"llvm.bar:10:1$0" = external global i64, !llvm.preserve.access.index !5 #0

; Function Attrs: nofree nounwind memory(readwrite, argmem: none)
define dso_local void @root() local_unnamed_addr #1 !dbg !18 {
entry:
%0 = load i64, ptr @"llvm.bar:10:1$0", align 8
%1 = tail call i64 @llvm.bpf.passthrough.i64.i64(i32 1, i64 %0)
store volatile i64 %1, ptr @g, align 8, !dbg !22, !tbaa !23
%2 = load i64, ptr @"llvm.bar:11:1$1", align 8
%3 = tail call i64 @llvm.bpf.passthrough.i64.i64(i32 0, i64 %2)
store volatile i64 %3, ptr @g, align 8, !dbg !27, !tbaa !23
ret void, !dbg !28
}

; Function Attrs: nofree nosync nounwind memory(none)
declare i64 @llvm.bpf.passthrough.i64.i64(i32, i64) #2

attributes #0 = { "btf_ama" }
attributes #1 = { nofree nounwind memory(readwrite, argmem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind memory(none) }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!13, !14, !15, !16}
!llvm.ident = !{!17}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !11, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !10, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "5423aa9ef48cb61e948b5c2bd75fd1df")
!4 = !{!5}
!5 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar", file: !3, line: 3, baseType: !6, size: 32, elements: !7)
!6 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned)
!7 = !{!8, !9}
!8 = !DIEnumerator(name: "U", value: 0)
!9 = !DIEnumerator(name: "V", value: 1)
!10 = !{!0}
!11 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !12)
!12 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned)
!13 = !{i32 7, !"Dwarf Version", i32 5}
!14 = !{i32 2, !"Debug Info Version", i32 3}
!15 = !{i32 1, !"wchar_size", i32 4}
!16 = !{i32 7, !"frame-pointer", i32 2}
!17 = !{!"clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)"}
!18 = distinct !DISubprogram(name: "root", scope: !3, file: !3, line: 5, type: !19, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !21)
!19 = !DISubroutineType(types: !20)
!20 = !{null}
!21 = !{}
!22 = !DILocation(line: 6, column: 5, scope: !18)
!23 = !{!24, !24, i64 0}
!24 = !{!"long", !25, i64 0}
!25 = !{!"omnipotent char", !26, i64 0}
!26 = !{!"Simple C/C++ TBAA"}
!27 = !DILocation(line: 7, column: 5, scope: !18)
!28 = !DILocation(line: 8, column: 1, scope: !18)
124 changes: 124 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-field-info.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
; REQUIRES: bpf-registered-target

;; Verify that llvm-objdump can use .BTF.ext to show CO-RE relocation data.

; RUN: llc --mtriple bpfel %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

; RUN: llc --mtriple bpfeb %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

;; Input generated from the following C code:
;;
;; #define __pai __attribute__((preserve_access_index))
;;
;; struct bar { int a; } __pai;
;; volatile unsigned long g;
;; void root(void) {
;; struct bar *bar = (void *)0;
;; g = __builtin_preserve_field_info(bar->a, 1);
;; g = __builtin_preserve_field_info(bar->a, 2);
;; g = __builtin_preserve_field_info(bar->a, 3);
;; g = __builtin_preserve_field_info(bar->a, 4);
;; g = __builtin_preserve_field_info(bar->a, 5);
;; }
;;
;; Using the following command:
;;
;; clang --target=bpf -g -O2 -emit-llvm -S t.c

; CHECK: CO-RE <byte_sz> [[[#]]] struct bar::a
; CHECK: CO-RE <field_exists> [[[#]]] struct bar::a
; CHECK: CO-RE <signed> [[[#]]] struct bar::a
; CHECK: CO-RE <lshift_u64> [[[#]]] struct bar::a
; CHECK: CO-RE <rshift_u64> [[[#]]] struct bar::a

@g = dso_local global i64 0, align 8, !dbg !0
@"llvm.bar:1:4$0:0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:2:1$0:0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:3:1$0:0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:4:32$0:0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:5:32$0:0" = external global i32, !llvm.preserve.access.index !7 #0

; Function Attrs: nofree nounwind memory(readwrite, argmem: none)
define dso_local void @root() local_unnamed_addr #1 !dbg !16 {
entry:
call void @llvm.dbg.value(metadata ptr null, metadata !20, metadata !DIExpression()), !dbg !22
%0 = load i32, ptr @"llvm.bar:1:4$0:0", align 4
%1 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 0, i32 %0)
%conv = zext i32 %1 to i64, !dbg !23
store volatile i64 %conv, ptr @g, align 8, !dbg !24, !tbaa !25
%2 = load i32, ptr @"llvm.bar:2:1$0:0", align 4
%3 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 1, i32 %2)
%conv1 = zext i32 %3 to i64, !dbg !29
store volatile i64 %conv1, ptr @g, align 8, !dbg !30, !tbaa !25
%4 = load i32, ptr @"llvm.bar:3:1$0:0", align 4
%5 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 2, i32 %4)
%conv2 = zext i32 %5 to i64, !dbg !31
store volatile i64 %conv2, ptr @g, align 8, !dbg !32, !tbaa !25
%6 = load i32, ptr @"llvm.bar:4:32$0:0", align 4
%7 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 3, i32 %6)
%conv3 = zext i32 %7 to i64, !dbg !33
store volatile i64 %conv3, ptr @g, align 8, !dbg !34, !tbaa !25
%8 = load i32, ptr @"llvm.bar:5:32$0:0", align 4
%9 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 4, i32 %8)
%conv4 = zext i32 %9 to i64, !dbg !35
store volatile i64 %conv4, ptr @g, align 8, !dbg !36, !tbaa !25
ret void, !dbg !37
}

; Function Attrs: nofree nosync nounwind memory(none)
declare i32 @llvm.bpf.passthrough.i32.i32(i32, i32) #2

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.value(metadata, metadata, metadata) #3

attributes #0 = { "btf_ama" }
attributes #1 = { nofree nounwind memory(readwrite, argmem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!11, !12, !13, !14}
!llvm.ident = !{!15}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "ff78616039301f51cd56ee6ea1377b86")
!4 = !{!0}
!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
!6 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned)
!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !3, line: 3, size: 32, elements: !8)
!8 = !{!9}
!9 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !7, file: !3, line: 3, baseType: !10, size: 32)
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{i32 7, !"Dwarf Version", i32 5}
!12 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !{i32 1, !"wchar_size", i32 4}
!14 = !{i32 7, !"frame-pointer", i32 2}
!15 = !{!"clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)"}
!16 = distinct !DISubprogram(name: "root", scope: !3, file: !3, line: 5, type: !17, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19)
!17 = !DISubroutineType(types: !18)
!18 = !{null}
!19 = !{!20}
!20 = !DILocalVariable(name: "bar", scope: !16, file: !3, line: 6, type: !21)
!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
!22 = !DILocation(line: 0, scope: !16)
!23 = !DILocation(line: 7, column: 7, scope: !16)
!24 = !DILocation(line: 7, column: 5, scope: !16)
!25 = !{!26, !26, i64 0}
!26 = !{!"long", !27, i64 0}
!27 = !{!"omnipotent char", !28, i64 0}
!28 = !{!"Simple C/C++ TBAA"}
!29 = !DILocation(line: 8, column: 7, scope: !16)
!30 = !DILocation(line: 8, column: 5, scope: !16)
!31 = !DILocation(line: 9, column: 7, scope: !16)
!32 = !DILocation(line: 9, column: 5, scope: !16)
!33 = !DILocation(line: 10, column: 7, scope: !16)
!34 = !DILocation(line: 10, column: 5, scope: !16)
!35 = !DILocation(line: 11, column: 7, scope: !16)
!36 = !DILocation(line: 11, column: 5, scope: !16)
!37 = !DILocation(line: 12, column: 1, scope: !16)
614 changes: 614 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-formatting.s

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-type-id.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
; REQUIRES: bpf-registered-target

;; Verify that llvm-objdump can use .BTF.ext to show CO-RE relocation data.

; RUN: llc --mtriple bpfel %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

; RUN: llc --mtriple bpfeb %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

;; Input generated from the following C code:
;;
;; #define __pai __attribute__((preserve_access_index))
;;
;; struct bar { } __pai;
;; volatile unsigned long g;
;; void root(void) {
;; struct bar *bar = (void *)0;
;; g = __builtin_btf_type_id(*bar, 0);
;; g = __builtin_btf_type_id(*bar, 1);
;; }
;;
;; Using the following command:
;;
;; clang --target=bpf -g -O2 -emit-llvm -S t.c

; CHECK: CO-RE <local_type_id> [[[#]]] struct bar
; CHECK: CO-RE <target_type_id> [[[#]]] struct bar

@g = dso_local global i64 0, align 8, !dbg !0
@"llvm.btf_type_id.0$6" = external global i64, !llvm.preserve.access.index !7 #0
@"llvm.btf_type_id.1$7" = external global i64, !llvm.preserve.access.index !7 #0

; Function Attrs: nofree nounwind memory(readwrite, argmem: none)
define dso_local void @root() local_unnamed_addr #1 !dbg !14 {
entry:
call void @llvm.dbg.value(metadata ptr null, metadata !18, metadata !DIExpression()), !dbg !20
%0 = load i64, ptr @"llvm.btf_type_id.0$6", align 8
%1 = tail call i64 @llvm.bpf.passthrough.i64.i64(i32 0, i64 %0)
store volatile i64 %1, ptr @g, align 8, !dbg !21, !tbaa !22
%2 = load i64, ptr @"llvm.btf_type_id.1$7", align 8
%3 = tail call i64 @llvm.bpf.passthrough.i64.i64(i32 1, i64 %2)
store volatile i64 %3, ptr @g, align 8, !dbg !26, !tbaa !22
ret void, !dbg !27
}

; Function Attrs: nofree nosync nounwind memory(none)
declare i64 @llvm.bpf.passthrough.i64.i64(i32, i64) #2

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.value(metadata, metadata, metadata) #3

attributes #0 = { "btf_type_id" }
attributes #1 = { nofree nounwind memory(readwrite, argmem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!9, !10, !11, !12}
!llvm.ident = !{!13}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "29efc9dba44aaba9e4b0c389bb8694ea")
!4 = !{!0}
!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
!6 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned)
!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !3, line: 3, elements: !8)
!8 = !{}
!9 = !{i32 7, !"Dwarf Version", i32 5}
!10 = !{i32 2, !"Debug Info Version", i32 3}
!11 = !{i32 1, !"wchar_size", i32 4}
!12 = !{i32 7, !"frame-pointer", i32 2}
!13 = !{!"clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)"}
!14 = distinct !DISubprogram(name: "root", scope: !3, file: !3, line: 5, type: !15, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !17)
!15 = !DISubroutineType(types: !16)
!16 = !{null}
!17 = !{!18}
!18 = !DILocalVariable(name: "bar", scope: !14, file: !3, line: 6, type: !19)
!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
!20 = !DILocation(line: 0, scope: !14)
!21 = !DILocation(line: 7, column: 5, scope: !14)
!22 = !{!23, !23, i64 0}
!23 = !{!"long", !24, i64 0}
!24 = !{!"omnipotent char", !25, i64 0}
!25 = !{!"Simple C/C++ TBAA"}
!26 = !DILocation(line: 8, column: 5, scope: !14)
!27 = !DILocation(line: 9, column: 1, scope: !14)
104 changes: 104 additions & 0 deletions llvm/test/tools/llvm-objdump/BPF/core-relo-type-info.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
; REQUIRES: bpf-registered-target

;; Verify that llvm-objdump can use .BTF.ext to show CO-RE relocation data.

; RUN: llc --mtriple bpfel %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

; RUN: llc --mtriple bpfeb %s --filetype=obj -o - | \
; RUN: llvm-objdump --no-addresses --no-show-raw-insn -dr - | \
; RUN: FileCheck %s

;; Input generated from the following C code:
;;
;; #define __pai __attribute__((preserve_access_index))
;;
;; struct bar { } __pai;
;; volatile unsigned long g;
;; void root(void) {
;; struct bar *bar = (void *)0;
;; g = __builtin_preserve_type_info(*bar, 0);
;; g = __builtin_preserve_type_info(*bar, 1);
;; g = __builtin_preserve_type_info(*bar, 2);
;; }
;;
;; Using the following command:
;;
;; clang --target=bpf -g -O2 -emit-llvm -S t.c

; CHECK: CO-RE <type_exists> [[[#]]] struct bar
; CHECK: CO-RE <type_size> [[[#]]] struct bar
; CHECK: CO-RE <type_matches> [[[#]]] struct bar

@g = dso_local global i64 0, align 8, !dbg !0
@"llvm.bar:8:1$0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:9:0$0" = external global i32, !llvm.preserve.access.index !7 #0
@"llvm.bar:12:1$0" = external global i32, !llvm.preserve.access.index !7 #0

; Function Attrs: nofree nounwind memory(readwrite, argmem: none)
define dso_local void @root() local_unnamed_addr #1 !dbg !14 {
entry:
call void @llvm.dbg.value(metadata ptr null, metadata !18, metadata !DIExpression()), !dbg !20
%0 = load i32, ptr @"llvm.bar:8:1$0", align 4
%1 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 0, i32 %0)
%conv = zext i32 %1 to i64, !dbg !21
store volatile i64 %conv, ptr @g, align 8, !dbg !22, !tbaa !23
%2 = load i32, ptr @"llvm.bar:9:0$0", align 4
%3 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 1, i32 %2)
%conv1 = zext i32 %3 to i64, !dbg !27
store volatile i64 %conv1, ptr @g, align 8, !dbg !28, !tbaa !23
%4 = load i32, ptr @"llvm.bar:12:1$0", align 4
%5 = tail call i32 @llvm.bpf.passthrough.i32.i32(i32 2, i32 %4)
%conv2 = zext i32 %5 to i64, !dbg !29
store volatile i64 %conv2, ptr @g, align 8, !dbg !30, !tbaa !23
ret void, !dbg !31
}

; Function Attrs: nofree nosync nounwind memory(none)
declare i32 @llvm.bpf.passthrough.i32.i32(i32, i32) #2

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare void @llvm.dbg.value(metadata, metadata, metadata) #3

attributes #0 = { "btf_ama" }
attributes #1 = { nofree nounwind memory(readwrite, argmem: none) "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
attributes #2 = { nofree nosync nounwind memory(none) }
attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!9, !10, !11, !12}
!llvm.ident = !{!13}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "g", scope: !2, file: !3, line: 4, type: !5, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
!3 = !DIFile(filename: "t.c", directory: "/home/eddy/work/tmp", checksumkind: CSK_MD5, checksum: "5bf218e82301e866fa302fd927913bcf")
!4 = !{!0}
!5 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !6)
!6 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned)
!7 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "bar", file: !3, line: 3, elements: !8)
!8 = !{}
!9 = !{i32 7, !"Dwarf Version", i32 5}
!10 = !{i32 2, !"Debug Info Version", i32 3}
!11 = !{i32 1, !"wchar_size", i32 4}
!12 = !{i32 7, !"frame-pointer", i32 2}
!13 = !{!"clang version 17.0.0 (/home/eddy/work/llvm-project/clang 2f8c5c0afd1d79a771dd74c8fb1e5bbae6d04eb7)"}
!14 = distinct !DISubprogram(name: "root", scope: !3, file: !3, line: 5, type: !15, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !17)
!15 = !DISubroutineType(types: !16)
!16 = !{null}
!17 = !{!18}
!18 = !DILocalVariable(name: "bar", scope: !14, file: !3, line: 6, type: !19)
!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64)
!20 = !DILocation(line: 0, scope: !14)
!21 = !DILocation(line: 7, column: 7, scope: !14)
!22 = !DILocation(line: 7, column: 5, scope: !14)
!23 = !{!24, !24, i64 0}
!24 = !{!"long", !25, i64 0}
!25 = !{!"omnipotent char", !26, i64 0}
!26 = !{!"Simple C/C++ TBAA"}
!27 = !DILocation(line: 8, column: 7, scope: !14)
!28 = !DILocation(line: 8, column: 5, scope: !14)
!29 = !DILocation(line: 9, column: 7, scope: !14)
!30 = !DILocation(line: 9, column: 5, scope: !14)
!31 = !DILocation(line: 10, column: 1, scope: !14)
1 change: 1 addition & 0 deletions llvm/tools/llvm-objdump/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
AllTargetsDisassemblers
AllTargetsInfos
BinaryFormat
DebugInfoBTF
DebugInfoDWARF
Demangle
MC
Expand Down
30 changes: 30 additions & 0 deletions llvm/tools/llvm-objdump/llvm-objdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Twine.h"
#include "llvm/DebugInfo/BTF/BTFParser.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
Expand Down Expand Up @@ -535,6 +536,22 @@ static void printRelocation(formatted_raw_ostream &OS, StringRef FileName,
OS << Name << "\t" << Val;
}

static void printBTFRelocation(formatted_raw_ostream &FOS, llvm::BTFParser &BTF,
object::SectionedAddress Address,
LiveVariablePrinter &LVP) {
const llvm::BTF::BPFFieldReloc *Reloc = BTF.findFieldReloc(Address);
if (!Reloc)
return;

SmallString<64> Val;
BTF.symbolize(Reloc, Val);
FOS << "\t\t";
if (LeadingAddr)
FOS << format("%016" PRIx64 ": ", Address.Address + AdjustVMA);
FOS << "CO-RE " << Val;
LVP.printAfterOtherLine(FOS, true);
}

class PrettyPrinter {
public:
virtual ~PrettyPrinter() = default;
Expand Down Expand Up @@ -1626,6 +1643,16 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
if (SymbolizeOperands && !Obj.isRelocatableObject())
ReadBBAddrMap();

std::optional<llvm::BTFParser> BTF;
if (InlineRelocs && BTFParser::hasBTFSections(Obj)) {
BTF.emplace();
BTFParser::ParseOptions Opts = {};
Opts.LoadTypes = true;
Opts.LoadRelocs = true;
if (Error E = BTF->parse(Obj, Opts))
WithColor::defaultErrorHandler(std::move(E));
}

for (const SectionRef &Section : ToolSectionFilter(Obj)) {
if (FilterSections.empty() && !DisassembleAll &&
(!Section.isText() || Section.isVirtual()))
Expand Down Expand Up @@ -2163,6 +2190,9 @@ disassembleObject(ObjectFile &Obj, const ObjectFile &DbgObj,
*DT->SubtargetInfo, CommentStream.str(), LVP);
Comments.clear();

if (BTF)
printBTFRelocation(FOS, *BTF, {Index, Section.getIndex()}, LVP);

// Hexagon does this in pretty printer
if (Obj.getArch() != Triple::hexagon) {
// Print relocation for instruction and data.
Expand Down
755 changes: 742 additions & 13 deletions llvm/unittests/DebugInfo/BTF/BTFParserTest.cpp

Large diffs are not rendered by default.