[llvm-dev] A question to the DWARF experts on symbol indirection
Nat! via llvm-dev
llvm-dev at lists.llvm.org
Thu Jul 26 10:38:38 PDT 2018
On 25.07.2018 15:41, paul.robinson at sony.com wrote:Is it possible to emit
DWARF statements, so that in the debugger the
>>> parameter _param is hidden and the visibility is a and b, without a
>> _param-> prefix ?
>>
>> It's certainly possible in LLVM IR. @llvm.dbg.declare and so on can
>> associate arbitrary Values in a function with whatever name you want.
> DWARF expressions are certainly powerful enough to describe this.
I am not so sure about this now, after I tried this today and yesterday
with limited success.
The main problem I think is, that_param-> points to a location, that
isn't a fixed offset relative to the stack pointer.
When I run my IR code through llc, llc was unable to provide a location
for the debugger. This might be more a limitation of llvm than of DWARF
though.
Here is part of a DWARF dump with my two fake formal parameters. But as
you can see the DW_AT_location is missing, which leads to problems in
gdb and lldb:
```
<2><74>: Abbrev Number: 6 (DW_TAG_formal_parameter)
<75> DW_AT_location : 2 byte block: 91 68 (DW_OP_fbreg: -24)
<78> DW_AT_name : (indirect string, offset: 0xfd): _param
<7c> DW_AT_type : <0xf5>
<80> DW_AT_artificial : 1
<2><80>: Abbrev Number: 7 (DW_TAG_formal_parameter)
<81> DW_AT_name : (indirect string, offset: 0x104): name
<85> DW_AT_decl_file : 2
<86> DW_AT_decl_line : 16
<87> DW_AT_type : <0x11b>
<8b> DW_AT_artificial : 1
<2><8b>: Abbrev Number: 7 (DW_TAG_formal_parameter)
<8c> DW_AT_name : (indirect string, offset: 0x112): version
<90> DW_AT_decl_file : 2
<91> DW_AT_decl_line : 17
<92> DW_AT_type : <0x130>
<96> DW_AT_artificial : 1
```
This information relates to this .ll snippet created from my compiler
(see below for full glory IR):
```
%_param.addr = alloca %"struct.Hello::p.printName:version:"*, align 8
%0 = getelementptr inbounds %"struct.Hello::p.printName:version:",
%"struct.Hello::p.printName:version:"* %_param,
i32 0, i32 0
call void @llvm.dbg.declare(metadata i8** %0, metadata !32, metadata
!DIExpression()), !dbg !34
%1 = getelementptr inbounds %"struct.Hello::p.printName:version:",
%"struct.Hello::p.printName:version:"* %_param,
i32 0, i32 1
call void @llvm.dbg.declare(metadata i32* %1, metadata !33, metadata
!DIExpression()), !dbg !35
```
```
!32 = !DILocalVariable(name: "name", arg: 4, scope: !21, file: !3, line:
22, type: !29)
!33 = !DILocalVariable(name: "version", arg: 5, scope: !21, file: !3,
line: 23, type: !11)
!34 = !DILocation(line: 22, column: 29, scope: !21)
!35 = !DILocation(line: 23, column: 35, scope: !21)
```
I am not sure, if I can compute the DW_AT_location for llvm, but I guess
that's probably what I will try to do next.
>> But it looks like you're trying to convince Clang itself to do that.
>> That's likely to be harder since it's not exactly a natural C mapping;
>> I suspect a lot depends on just where you're doing your ABI lowering.
> Also depends on whether you want your debugger to be able to call these
> functions.
Until recently I believed, that because lldb uses clang JIT to evaluate
expressions, that when lldb uses my clang to evaluate "a", the code
would be generated for "_param->a" and that lldb would access the
correct value. I lost a little confidence in this though.
>
> My guess is that you want to describe the formal parameter as artificial,
> using the proper struct description, so that calls work correctly.
> Then create local variables whose storage locations work indirectly off
> the (described as artificial) pointer parameter.
If I create local storage locations, then wouldn't the debugger see
stale copied information in cases where the function code modifies an
argument ?
```
foo( int a)
{
++a;
}
```
is really
```
foo( struct { int a; } *_param)
{
++_param->a;
}
```
but with alloca:
```
foo( struct { int a; } *_param)
{
int a;
a = _param->a;
++_param->a;
// debug: p a gives ???
}
```
Seeing stale information would be bad.
>
> Whether you get your modified front-end to do this, or hack up the
> backend, up to you. The question was *can* it be done, and the answer
> to that is clearly yes.
> --paulr
Actually, currently I am doing both. :)
Ciao
Nat!
>> Either way you're probably more likely to get a good response if you
>> ask the question on the cfe-dev mailing list.
>>
>> Cheers.
>>
>> Tim.
>> _______________________________________________
>> LLVM Developers mailing list
>> llvm-dev at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
```
; ModuleID = 'reduced.m'
source_filename = "reduced.m"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
%struct.anon = type { i32, i32 }
%struct._mulle_objc_method = type { i32, i8*, i8*, i32, i8* }
%struct._mulle_objc_loadclass = type { i32, i8*, i32, i32, i8*, i32,
i32, i32, %struct._mulle_objc_ivarlist*,
%struct._mulle_objc_methodlist*, %struct._mulle_objc_methodlist*,
%struct._mulle_objc_propertylist*, %struct._mulle_objc_protocollist*,
i32*, i8* }
%struct._mulle_objc_ivarlist = type opaque
%struct._mulle_objc_methodlist = type opaque
%struct._mulle_objc_propertylist = type { i32, [0 x
%struct._mulle_objc_property] }
%struct._mulle_objc_property = type { i32, i32, i8*, i8*, i32, i32, i32 }
%struct._mulle_objc_protocollist = type {
%struct._mulle_objc_protocollist*, i64, [0 x %struct._mulle_objc_protocol] }
%struct._mulle_objc_protocol = type { i32, i8* }
%"struct.Hello::p.printName:version:" = type { i8*, i32 }
@__mulle_objc_objccompilerinfo = global %struct.anon { i32 12, i32 0 },
align 4, !dbg !0
@OBJC_METH_VAR_NAME_ = private unnamed_addr constant [19 x i8]
c"printName:version:\00", align 1
@OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [14 x i8]
c"v28 at 0:8*16I24\00", align 1
@OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Hello\00",
align 1
@OBJC_CLASS_METHODS_Hello = private global { i32, i8*, [1 x
%struct._mulle_objc_method] } { i32 1, i8* null, [1 x
%struct._mulle_objc_method] [%struct._mulle_objc_method { i32
-1285604266, i8* getelementptr inbounds ([19 x i8], [19 x i8]*
@OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([14 x
i8], [14 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i32 0, i8* bitcast
(void (i8*, i32, %"struct.Hello::p.printName:version:"*)* @"+[Hello
printName:version:]" to i8*) }] }, section
"_DATA,__cls_meth,regular,no_dead_strip", align 4
@OBJC_DEBUG_INFO_ = private unnamed_addr constant [10 x i8]
c"reduced.m\00", align 1
@OBJC_CLASS_Hello = private global %struct._mulle_objc_loadclass { i32
1438848191, i8* getelementptr inbounds ([6 x i8], [6 x i8]*
@OBJC_CLASS_NAME_, i32 0, i32 0), i32 298441816, i32 0, i8* null, i32 0,
i32 -1, i32 0, %struct._mulle_objc_ivarlist* null,
%struct._mulle_objc_methodlist* bitcast ({ i32, i8*, [1 x
%struct._mulle_objc_method] }* @OBJC_CLASS_METHODS_Hello to
%struct._mulle_objc_methodlist*), %struct._mulle_objc_methodlist* null,
%struct._mulle_objc_propertylist* null,
%struct._mulle_objc_protocollist* null, i32* null, i8* getelementptr
inbounds ([10 x i8], [10 x i8]* @OBJC_DEBUG_INFO_, i32 0, i32 0) },
section "__DATA,__class,regular,no_dead_strip", align 4
@OBJC_HASHNAME_ = private global [1 x i8] zeroinitializer, section
"__DATA,__module_info,regular,no_dead_strip", align 4
@OBJC_HASHNAME_Hello = private global [6 x i8] c"Hello\00", section
"__DATA,__module_info,regular,no_dead_strip", align 4
@"OBJC_HASHNAME_printName:version:" = private global [19 x i8]
c"printName:version:\00", section
"__DATA,__module_info,regular,no_dead_strip", align 4
@llvm.compiler.used = appending global [9 x i8*] [i8* getelementptr
inbounds ([19 x i8], [19 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8*
getelementptr inbounds ([14 x i8], [14 x i8]* @OBJC_METH_VAR_TYPE_, i32
0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]*
@OBJC_CLASS_NAME_, i32 0, i32 0), i8* bitcast ({ i32, i8*, [1 x
%struct._mulle_objc_method] }* @OBJC_CLASS_METHODS_Hello to i8*), i8*
getelementptr inbounds ([10 x i8], [10 x i8]* @OBJC_DEBUG_INFO_, i32 0,
i32 0), i8* bitcast (%struct._mulle_objc_loadclass* @OBJC_CLASS_Hello to
i8*), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @OBJC_HASHNAME_,
i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]*
@OBJC_HASHNAME_Hello, i32 0, i32 0), i8* getelementptr inbounds ([19 x
i8], [19 x i8]* @"OBJC_HASHNAME_printName:version:", i32 0, i32 0)],
section "llvm.metadata"
; Function Attrs: noinline nounwind optnone uwtable
define internal void @"+[Hello printName:version:]"(i8* nonnull %self,
i32 zeroext %_cmd, %"struct.Hello::p.printName:version:"* %_param) #0
!dbg !21 {
entry:
%self.addr = alloca i8*, align 8
%_cmd.addr = alloca i32, align 4
%_param.addr = alloca %"struct.Hello::p.printName:version:"*, align 8
%0 = getelementptr inbounds %"struct.Hello::p.printName:version:",
%"struct.Hello::p.printName:version:"* %_param, i32 0, i32 0
call void @llvm.dbg.declare(metadata i8** %0, metadata !32, metadata
!DIExpression()), !dbg !34
%1 = getelementptr inbounds %"struct.Hello::p.printName:version:",
%"struct.Hello::p.printName:version:"* %_param, i32 0, i32 1
call void @llvm.dbg.declare(metadata i32* %1, metadata !33, metadata
!DIExpression()), !dbg !35
store i8* %self, i8** %self.addr, align 8
call void @llvm.dbg.declare(metadata i8** %self.addr, metadata !36,
metadata !DIExpression()), !dbg !38
store i32 %_cmd, i32* %_cmd.addr, align 4
call void @llvm.dbg.declare(metadata i32* %_cmd.addr, metadata !39,
metadata !DIExpression()), !dbg !38
store %"struct.Hello::p.printName:version:"* %_param,
%"struct.Hello::p.printName:version:"** %_param.addr, align 8
call void @llvm.dbg.declare(metadata
%"struct.Hello::p.printName:version:"** %_param.addr, metadata !41,
metadata !DIExpression()), !dbg !38
ret void, !dbg !47
}
; Function Attrs: nounwind readnone speculatable
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" "less-precise-fpmad"="false"
"no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf"
"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"="+fxsr,+mmx,+sse,+sse2,+x87"
"unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readnone speculatable }
!llvm.module.flags = !{!13, !14, !15, !16, !17, !18, !19}
!llvm.dbg.cu = !{!2}
!llvm.ident = !{!20}
!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "__mulle_objc_objccompilerinfo",
scope: !2, file: !3, line: 5, type: !8, isLocal: false, isDefinition: true)
!2 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !3, producer:
"mulle-clang 6.0.0.4 (runtime-load-version: 12) clang version 6.0.0
(based on LLVM 6.0.0)", isOptimized: false, runtimeVersion: 1848,
emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !7)
!3 = !DIFile(filename: "reduced.m", directory: "/tmp/yyy")
!4 = !{}
!5 = !{!6}
!6 = !DICompositeType(tag: DW_TAG_structure_type, name: "Hello", scope:
!3, file: !3, line: 12, flags: DIFlagObjcClassComplete, elements: !4,
runtimeLang: DW_LANG_ObjC)
!7 = !{!0}
!8 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3,
line: 1, size: 64, elements: !9)
!9 = !{!10, !12}
!10 = !DIDerivedType(tag: DW_TAG_member, name: "load", scope: !8, file:
!3, line: 3, baseType: !11, size: 32)
!11 = !DIBasicType(name: "unsigned int", size: 32, encoding:
DW_ATE_unsigned)
!12 = !DIDerivedType(tag: DW_TAG_member, name: "runtime", scope: !8,
file: !3, line: 4, baseType: !11, size: 32, offset: 32)
!13 = !{i32 1, !"Objective-C Version", i32 1848}
!14 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!15 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,
__image_info,regular,no_dead_strip"}
!16 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
!17 = !{i32 2, !"Dwarf Version", i32 4}
!18 = !{i32 2, !"Debug Info Version", i32 3}
!19 = !{i32 1, !"wchar_size", i32 4}
!20 = !{!"mulle-clang 6.0.0.4 (runtime-load-version: 12) clang version
6.0.0 (based on LLVM 6.0.0)"}
!21 = distinct !DISubprogram(name: "+[Hello printName:version:]", scope:
!3, file: !3, line: 22, type: !22, isLocal: true, isDefinition: true,
scopeLine: 22, flags: DIFlagPrototyped, isOptimized: false, unit: !2,
variables: !31)
!22 = !DISubroutineType(types: !23)
!23 = !{null, !24, !27, !29, !11}
!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "Class", file: !3, line:
5, baseType: !25, flags: DIFlagArtificial | DIFlagObjectPointer)
!25 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !26, size: 64)
!26 = !DICompositeType(tag: DW_TAG_structure_type, name: "objc_class",
file: !3, flags: DIFlagFwdDecl)
!27 = !DIDerivedType(tag: DW_TAG_typedef, name: "SEL", file: !3, line:
5, baseType: !28, flags: DIFlagArtificial)
!28 = !DICompositeType(tag: DW_TAG_structure_type, name:
"objc_selector", file: !3, flags: DIFlagFwdDecl)
!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64)
!30 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
!31 = !{!32, !33}
!32 = !DILocalVariable(name: "name", arg: 4, scope: !21, file: !3, line:
22, type: !29)
!33 = !DILocalVariable(name: "version", arg: 5, scope: !21, file: !3,
line: 23, type: !11)
!34 = !DILocation(line: 22, column: 29, scope: !21)
!35 = !DILocation(line: 23, column: 35, scope: !21)
!36 = !DILocalVariable(name: "self", arg: 1, scope: !21, type: !37,
flags: DIFlagArtificial | DIFlagObjectPointer)
!37 = !DIDerivedType(tag: DW_TAG_typedef, name: "Class", file: !3, line:
5, baseType: !25)
!38 = !DILocation(line: 0, scope: !21)
!39 = !DILocalVariable(name: "_cmd", arg: 2, scope: !21, type: !40,
flags: DIFlagArtificial)
!40 = !DIDerivedType(tag: DW_TAG_typedef, name: "SEL", file: !3, line:
5, baseType: !28)
!41 = !DILocalVariable(name: "_param", arg: 3, scope: !21, type: !42,
flags: DIFlagArtificial)
!42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !43, size: 64)
!43 = distinct !DICompositeType(tag: DW_TAG_structure_type, name:
"p.printName:version:", file: !3, line: 22, size: 128, elements: !44)
!44 = !{!45, !46}
!45 = !DIDerivedType(tag: DW_TAG_member, name: "name", scope: !43, file:
!3, line: 22, baseType: !29, size: 64)
!46 = !DIDerivedType(tag: DW_TAG_member, name: "version", scope: !43,
file: !3, line: 23, baseType: !11, size: 32, offset: 64)
!47 = !DILocation(line: 25, column: 1, scope: !21)
```
Original .m
```
struct
{
unsigned int load;
unsigned int runtime;
} __mulle_objc_objccompilerinfo =
{
12,
0
};
@interface Hello
+ (void) printName:(char *) name
version:(unsigned int) version;
@end
@implementation Hello
+ (void) printName:(char *) name
version:(unsigned int) version;
{
}
@end
```
More information about the llvm-dev
mailing list