This is an archive of the discontinued LLVM Phabricator instance.

Change UnwindAssemblyInstEmulation to remove a register location instead of marking it as IsSame()
Needs ReviewPublic

Authored by jasonmolenda on Nov 3 2016, 9:06 PM.

Details

Summary

This is a minor change and maybe more of a personal preference, but UnwindAssemblyInstEmulation marks registers that have been restored to their original values as "IsSame" - which is equivalent to the UnwindPlan not mentioning a location for the register at all. When I look at an unwind plan while a function is executing it's epilogue, the output looks like

row[14]: 520: CFA=sp+320 => x8=[CFA-240] x19= <same> x20= <same> x21= <same> x22= <same> x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] fp= <same> lr= <same>
row[15]: 524: CFA=sp+320 => x8=[CFA-240] x19= <same> x20= <same> x21= <same> x22= <same> x23= <same> x24= <same> x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96] fp= <same> lr= <same>
row[16]: 528: CFA=sp+320 => x8=[CFA-240] x19= <same> x20= <same> x21= <same> x22= <same> x23= <same> x24= <same> x25= <same> x26= <same> x27=[CFA-88] x28=[CFA-96] fp= <same> lr= <same>
row[17]: 532: CFA=sp +0 => x8=[CFA-240] x19= <same> x20= <same> x21= <same> x22= <same> x23= <same> x24= <same> x25= <same> x26= <same> x27= <same> x28= <same> fp= <same> lr= <same>

etc. If we remove the registers from the row, the unwind dump will read like

row[14]: 516: CFA=sp+96 => x8=[CFA-240] x21=[CFA-40] x22=[CFA-48] x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
row[15]: 520: CFA=sp+96 => x8=[CFA-240] x23=[CFA-56] x24=[CFA-64] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
row[16]: 524: CFA=sp+96 => x8=[CFA-240] x25=[CFA-72] x26=[CFA-80] x27=[CFA-88] x28=[CFA-96]
row[17]: 528: CFA=sp+96 => x8=[CFA-240] x27=[CFA-88] x28=[CFA-96]

There's no functional difference between the two (there SHOULD be no functional difference) - but I think it's a bit easier to read without the IsSame's. Does anyone care one way or the other?

Diff Detail

Repository
rL LLVM

Event Timeline

jasonmolenda retitled this revision from to Change UnwindAssemblyInstEmulation to remove a register location instead of marking it as IsSame() .
jasonmolenda updated this object.
jasonmolenda added reviewers: labath, tberghammer.
jasonmolenda set the repository for this revision to rL LLVM.
jasonmolenda added a subscriber: lldb-commits.
tberghammer edited edge metadata.Nov 4 2016, 4:10 AM

My understanding (can be wrong) is that there IS a difference between not specifying a register in the unwind info versus specifying it as "is same" for volatile (caller saved) registers. I think for volatile registers not specifying them means that we can't access their current value in the parent frame (because they are lost) while specifying them as "is same" means we know that their value in the parent frame is the same as in the current one so we can display them.

If "is same" and "not specified" would be equivalent then we should just completely get rid of the "is same" case (as it is useless) but as far as I know they have subtle differences.

Ah, interesting point, I didn't think of that. However, this touches on another thing I've been thinking about as I look at the assembly inspection unwind plan generators. In the x86 unwind inspector, I've hardcoded the SysV-x86_64 ABI and the unwind plan generator ignores any saves/restores of volatile registers. It's a poor choice and it's the kind of thing that surely won't be correct when a Windows port is up & running.

I'm thinking the unwind plan generators should treat all registers as non-volatile. When UnwindLLDB / RegisterContextLLDB run the UnwindPlan, they can ask the ABI if a register is volatile or not - and refuse to retrieve a volatile register for a stack frame in the middle of the stack. (it SHOULD be doing that already)

The problem with tracking a register that is volatile is that as soon as the function makes a call into another function, we have to assume the register value is overwritten. So if we have

0xfffffff021f7bd80 <+0>:    stp    x28, x27, [sp, #-0x60]!
0xfffffff021f7bd84 <+4>:    stp    x26, x25, [sp, #0x10]
0xfffffff021f7bd88 <+8>:    stp    x24, x23, [sp, #0x20]
0xfffffff021f7bd8c <+12>:   stp    x22, x21, [sp, #0x30]
0xfffffff021f7bd90 <+16>:   stp    x20, x19, [sp, #0x40]
0xfffffff021f7bd94 <+20>:   stp    x29, x30, [sp, #0x50]
0xfffffff021f7bd98 <+24>:   add    x29, sp, #0x50            ; =0x50 
0xfffffff021f7bd9c <+28>:   sub    sp, sp, #0xe0             ; =0xe0 
0xfffffff021f7bdd4 <+84>:   bl     0xfffffff021f8af70  

0xfffffff021f7c334 <+1460>: str    w9, [sp, #0x60]

x9 is volatile in the AAPCS64 ABI, so at this offset in the assembly the value has already been overwritten by the call instruction at +84. If I later see a load of x9 and mark the register as "IsSame", now we've got a problem because we're saying it has the original value.

If we were going to follow the IsSame-means-unmodified thinking through, we'd want to mark every register as IsSame on function entry and only remove that markup when the register is modified.

I guess I'm trying to say two things. (1) I'd really like to get rid of IsSame so that the unwind plan dumps are easier for me to read ;) and (2) I think the instruction profiler unwind plan generators should track all registers without knowledge of the ABI, and leave it to the runtime code to decide which registers we will allow to be looked up.

labath resigned from this revision.Jan 21 2019, 4:49 PM