via llvm-dev
2018-Jul-25 13:41 UTC
[llvm-dev] A question to the DWARF experts on symbol indirection
> -----Original Message----- > From: llvm-dev [mailto:llvm-dev-bounces at lists.llvm.org] On Behalf Of Tim > Northover via llvm-dev > Sent: Wednesday, July 25, 2018 3:07 AM > To: Nat! > Cc: LLVM Developers Mailing List > Subject: Re: [llvm-dev] A question to the DWARF experts on symbol > indirection > > Hi Nat!, > > On Wed, 25 Jul 2018 at 01:21, Nat! via llvm-dev <llvm-dev at lists.llvm.org> > 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.> > 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. 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. 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> 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
Nat! via llvm-dev
2018-Jul-26 17:38 UTC
[llvm-dev] A question to the DWARF experts on symbol indirection
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. > --paulrActually, 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 ```
via llvm-dev
2018-Jul-26 18:07 UTC
[llvm-dev] A question to the DWARF experts on symbol indirection
+ Adrian in case he might have insight into the dbg.value question.> -----Original Message----- > From: Nat! [mailto:nat at mulle-kybernetik.com] > Sent: Thursday, July 26, 2018 1:39 PM > To: Robinson, Paul; t.p.northover at gmail.com > Cc: llvm-dev at lists.llvm.org > Subject: Re: [llvm-dev] A question to the DWARF experts on symbol > indirection > > 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.I am pretty sure you are pushing the boundaries of what LLVM knows how to do. DWARF itself knows how to access a value at (pointer + offset), even if LLVM doesn't know how to generate such an expression (yet?). (This is definitely beyond the boundaries of what I personally know how to get LLVM to do. However I did pretty much exactly this in a previous compiler I worked on, so the DWARF part is certainly feasible.)> > 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:Yes, that would be a problem. :-)> > > ``` > <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 ?Sorry, I explained that poorly. I meant create local variables *in DWARF* (or metadata, in the frontend) whose storage locations work indirectly off the pointer. You seem to have been heading that direction with formal parameters instead of variables, which is the same idea; whether it will confuse the debugger is a different problem, but the concept is right. I think Tim's point was that, given you have metadata for the individual entities (params or vars) "a" and "b", you then need to emit an llvm.dbg.value intrinsic that can tie the metadata to the indirect location. If you do that, then the mechanism to translate that into a DWARF location expression should kick in and emit DW_AT_location for you. I honestly don't know whether LLVM can handle a location expression with this degree of complexity. However, definitely there is interest in getting it to handle that correctly, because handling more complex expressions is key to improving the availability of variables in more-optimized code, and there is a *lot* of interest in improving debugging of optimized code. HTH, --paulr