[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