for example,here is the struct
typedef struct{
int loc_x;
int loc_y;
}Loc;
typedef struct{
char name[50];
int age;
Loc loc;
}Stu;
now give the location vector [2,1],2 means member loc, 1 means loc’s member loc_y
I want to get the member name “loc_y” by location vector [2,1], please help me.
You can’t, not at middle-end IR without hacky approaches like parsing debuginfo (will that even work?)
it’s generally lost during Clang’s AST CodeGen
yes, i get ll file using “-g”, look at the picture
; ModuleID = '/5g_build/5g_Main/DragonGlass/llvm/test/Transforms/StructInitCheck/check_scene/一级成员赋值点.c'
source_filename = "/5g_build/5g_Main/DragonGlass/llvm/test/Transforms/StructInitCheck/check_scene/\E4\B8\80\E7\BA\A7\E6\88\90\E5\91\98\E8\B5\8B\E5\80\BC\E7\82\B9.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
%struct._BTS_Node = type { i32, i8*, %struct._Attr, [5 x %struct._Board], %struct._Board, %struct._Board }
%struct._Attr = type { i32, i32, i32, i8*, %struct._Location }
%struct._Location = type { i32, i32, i32 }
%struct._Board = type { i32, i32, i32, [10 x %struct._Port] }
%struct._Port = type { i32, i32 }
; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @func_use_scene_011() #0 !dbg !7 {
entry:
%bb = alloca %struct._BTS_Node, align 8
call void @llvm.dbg.declare(metadata %struct._BTS_Node* %bb, metadata !11, metadata !DIExpression()), !dbg !57
%nodeId = getelementptr inbounds %struct._BTS_Node, %struct._BTS_Node* %bb, i32 0, i32 0, !dbg !58
store i32 1, i32* %nodeId, align 8, !dbg !59
ret void, !dbg !60
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone speculatable willreturn }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0 (https://szv-open.codehub.huawei.com/innersource/DragonGlass/DragonGlass.git 968b95cfc9d1727c0eb5a3bb2d122a1fa896ab5c)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
!1 = !DIFile(filename: "/5g_build/5g_Main/DragonGlass/llvm/test/Transforms/StructInitCheck/check_scene/\E4\B8\80\E7\BA\A7\E6\88\90\E5\91\98\E8\B5\8B\E5\80\BC\E7\82\B9.c", directory: "/5g_build/5g_Main/DragonGlass")
!2 = !{}
!3 = !{i32 7, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!7 = distinct !DISubprogram(name: "func_use_scene_011", scope: !8, file: !8, line: 10, type: !9, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2)
!8 = !DIFile(filename: "llvm/test/Transforms/StructInitCheck/check_scene/\E4\B8\80\E7\BA\A7\E6\88\90\E5\91\98\E8\B5\8B\E5\80\BC\E7\82\B9.c", directory: "/5g_build/5g_Main/DragonGlass")
!9 = !DISubroutineType(types: !10)
!10 = !{null}
!11 = !DILocalVariable(name: "bb", scope: !7, file: !8, line: 11, type: !12)
!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "_BTS_Node", file: !13, line: 43, baseType: !14)
!13 = !DIFile(filename: "llvm/test/Transforms/StructInitCheck/check_scene/../commom.h", directory: "/5g_build/5g_Main/DragonGlass")
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 36, size: 5632, elements: !15)
!15 = !{!16, !18, !21, !36, !55, !56}
!16 = !DIDerivedType(tag: DW_TAG_member, name: "nodeId", scope: !14, file: !13, line: 37, baseType: !17, size: 32)
!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!18 = !DIDerivedType(tag: DW_TAG_member, name: "nodeName", scope: !14, file: !13, line: 38, baseType: !19, size: 64, offset: 64)
!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64)
!20 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
!21 = !DIDerivedType(tag: DW_TAG_member, name: "attribute", scope: !14, file: !13, line: 39, baseType: !22, size: 320, offset: 128)
!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Attr", file: !13, line: 22, baseType: !23)
!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 16, size: 320, elements: !24)
!24 = !{!25, !26, !27, !28, !29}
!25 = !DIDerivedType(tag: DW_TAG_member, name: "r", scope: !23, file: !13, line: 17, baseType: !17, size: 32)
!26 = !DIDerivedType(tag: DW_TAG_member, name: "g", scope: !23, file: !13, line: 18, baseType: !17, size: 32, offset: 32)
!27 = !DIDerivedType(tag: DW_TAG_member, name: "b", scope: !23, file: !13, line: 19, baseType: !17, size: 32, offset: 64)
!28 = !DIDerivedType(tag: DW_TAG_member, name: "attrId", scope: !23, file: !13, line: 20, baseType: !19, size: 64, offset: 128)
!29 = !DIDerivedType(tag: DW_TAG_member, name: "loc", scope: !23, file: !13, line: 21, baseType: !30, size: 96, offset: 192)
!30 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Location", file: !13, line: 15, baseType: !31)
!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 11, size: 96, elements: !32)
!32 = !{!33, !34, !35}
!33 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !31, file: !13, line: 12, baseType: !17, size: 32)
!34 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !31, file: !13, line: 13, baseType: !17, size: 32, offset: 32)
!35 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !31, file: !13, line: 14, baseType: !17, size: 32, offset: 64)
!36 = !DIDerivedType(tag: DW_TAG_member, name: "boardList", scope: !14, file: !13, line: 40, baseType: !37, size: 3680, offset: 448)
!37 = !DICompositeType(tag: DW_TAG_array_type, baseType: !38, size: 3680, elements: !53)
!38 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Board", file: !13, line: 34, baseType: !39)
!39 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 29, size: 736, elements: !40)
!40 = !{!41, !42, !43, !44}
!41 = !DIDerivedType(tag: DW_TAG_member, name: "sn", scope: !39, file: !13, line: 30, baseType: !17, size: 32)
!42 = !DIDerivedType(tag: DW_TAG_member, name: "srn", scope: !39, file: !13, line: 31, baseType: !17, size: 32, offset: 32)
!43 = !DIDerivedType(tag: DW_TAG_member, name: "cn", scope: !39, file: !13, line: 32, baseType: !17, size: 32, offset: 64)
!44 = !DIDerivedType(tag: DW_TAG_member, name: "portList", scope: !39, file: !13, line: 33, baseType: !45, size: 640, offset: 96)
!45 = !DICompositeType(tag: DW_TAG_array_type, baseType: !46, size: 640, elements: !51)
!46 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Port", file: !13, line: 27, baseType: !47)
!47 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 24, size: 64, elements: !48)
!48 = !{!49, !50}
!49 = !DIDerivedType(tag: DW_TAG_member, name: "portNo", scope: !47, file: !13, line: 25, baseType: !17, size: 32)
!50 = !DIDerivedType(tag: DW_TAG_member, name: "speed", scope: !47, file: !13, line: 26, baseType: !17, size: 32, offset: 32)
!51 = !{!52}
!52 = !DISubrange(count: 10)
!53 = !{!54}
!54 = !DISubrange(count: 5)
!55 = !DIDerivedType(tag: DW_TAG_member, name: "myBoard", scope: !14, file: !13, line: 41, baseType: !38, size: 736, offset: 4128)
!56 = !DIDerivedType(tag: DW_TAG_member, name: "myBoard1", scope: !14, file: !13, line: 42, baseType: !38, size: 736, offset: 4864)
!57 = !DILocation(line: 11, column: 15, scope: !7)
!58 = !DILocation(line: 12, column: 8, scope: !7)
!59 = !DILocation(line: 12, column: 15, scope: !7)
!60 = !DILocation(line: 13, column: 1, scope: !7)
it seems these infomation can be extracted, but I don’t know how to implement the code
https://llvm.org/doxygen/classllvm_1_1DebugInfoFinder.html
blah blah finding the DIType which in turn has the name. Not sure how it works beyond that though
thanks for your reply.I want to find some example.The use of these interfaces has left me extremely confused and frustrated.
Could you give a bit more of the context in which you’re trying to find the struct member’s name? As mentioned already, the debug info metadata is what you need. Technically there is not a direct link between an LLVM type definition (e.g. %struct._BTS_Node = type ...
) and a source type definition (e.g. struct _BTS_Node {...}
). However, if you either know the name of the source type already (which you may be able to guess from the LLVM type name) or if you have a reference to a variable of that type then you can find it through that.
In your example ll file, there is a call void @llvm.dbg.declare
instruction; the second argument of that (!11
) refers to the variable being declared. From there we can follow through the debug info metadata tree:
!11 = !DILocalVariable(name: "bb", scope: !7, file: !8, line: 11, type: !12)
; The variable "bb" has type !12...
!12 = !DIDerivedType(tag: DW_TAG_typedef, name: "_BTS_Node", file: !13, line: 43, baseType: !14)
; Type !12 is a typedef called "_BTS_Node" whose base type is !14...
!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 36, size: 5632, elements: !15)
; Type !14 is a composite type with a list of elements given in !15...
!15 = !{!16, !18, !21, !36, !55, !56}
; This is just a list of the struct's elements - we want element index 2 = !21
!21 = !DIDerivedType(tag: DW_TAG_member, name: "attribute", scope: !14, file: !13, line: 39, baseType: !22, size: 320, offset: 128)
; Follow the base type field again...
!22 = !DIDerivedType(tag: DW_TAG_typedef, name: "_Attr", file: !13, line: 22, baseType: !23)
!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !13, line: 16, size: 320, elements: !24)
; Now we can look at the elements list and find element index 1...
!24 = !{!25, !26, !27, !28, !29}
!26 = !DIDerivedType(tag: DW_TAG_member, name: "g", scope: !23, file: !13, line: 18, baseType: !17, size: 32, offset: 32)
; Finally we have the metadata for the member, whose name is "g"
This traversal is quite long-winded due to the way LLVM represents debug information with metadata, but if you are trying to do this programmatically it should not be too complicated.
I am currently using IR for static code analysis, and my pass is able to obtain the coordinates of the specific members of the structures I need to find. For example, coordinate 1 represents the second member of the structure, and so on. However, presenting these coordinates directly to the user is not user-friendly. Therefore, I would like to convert these coordinates into the specific member names of the structures so that users can quickly locate the positions of the structure members. This is my goal.
As you described above, finding the desired struct member name can be achieved by manually searching through each level. However, I am unsure of how to design a more generic functionality method that can retrieve the name of this member based on my target struct’s debug information.
There are two halves to the problem - finding the DIType
that corresponds to the struct you’re interested in, and finding the name of the member from that DIType. The former depends on how you’re determining which structs you’re looking at - it’s not trivial because as mentioned earlier, I don’t believe there’s any strict guarantee that there is any explicit link between an LLVM type and a DIType
, so you may need to find some way to link them using an llvm.dbg.declare
or llvm.dbg.value
. Once you have that DIType though, you’ll want code that looks something like this:
StringRef getMemberName(Metadata *Type, ArrayRef<int> Coordinates) {
for (int Coordinate : Coordinates) {
// Iterate through derived types...
while (auto DerivedType = dyn_cast<DIDerivedType>(Type))
Type = DerivedType->getBaseType();
assert(isa<DICompositeType>(Type) && "Should derive from a struct type!");
// Find the type at index `Coordinate`
Type = cast<DICompositeType>(Type)->getElements()[Coordinate];
}
auto MemberType = cast<DIDerivedType>(Type);
assert(MemberType .getTag() == dwarf::DW_TAG_member && "Should have gotten a member type");
return MemberType->getName();
}
This code was hastily scribbled out so I can’t guarantee it works as written - for example it will probably fail if it has to work with arrays rather than purely nested structs - but this would be the general idea to shoot for.