This is an archive of the discontinued LLVM Phabricator instance.

[lldb][AArch64] Fix corefile memory reads when there are non-address bits
ClosedPublic

Authored by DavidSpickett on Mar 24 2022, 9:45 AM.

Details

Summary

Previously if you read a code/data mask before there was a valid thread
you would get the top byte mask. This meant the value was "valid" as in,
don't read it again.

When using a corefile we ask for the data mask very early on and this
meant that later once you did have a thread it wouldn't read the
register to get the rest of the mask.

This fixes that and adds a corefile test generated from the same program
as in my previous change on this theme.

Depends on D118794

Diff Detail

Event Timeline

DavidSpickett created this revision.Mar 24 2022, 9:45 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 24 2022, 9:45 AM
DavidSpickett requested review of this revision.Mar 24 2022, 9:45 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 24 2022, 9:45 AM

This smells a little bit like a hack but in some ways it makes sense that an address mask value couldn't possibly be valid until we have a thread setup.

labath added a subscriber: labath.Mar 25 2022, 4:38 AM

Can we make the core file smaller? Since it's essentially static data, do you really need all the mmap, debug info and everything? Could you just take an address that is known to be in the core file (smallest you can make), and then do a memory read 0xwhatever ?

lldb/test/API/linux/aarch64/non_address_bit_memory_access/TestAArch64LinuxNonAddressBitMemoryAccess.py
191

even for a core file?

  • Don't require pointer auth hardware for the corefile test.
  • Remove the program file since all we need to do is read memory from the corefile.
DavidSpickett marked an inline comment as done.Mar 25 2022, 7:54 AM

Can we make the core file smaller?

Yes we can.

I need to find a good way to do that, my first instinct was to strip segments from it but perhaps I'm barking up the wrong tree there. Is there a usual way to make a minimal core?

DavidSpickett updated this revision to Diff 418246.EditedMar 25 2022, 9:02 AM
  • Corefile down to 24k with some tweaking of coredump_filter
  • Add some prints so when you generate the corefile you know what addresses to test

I also found another bug testing this where memory read works but printing
doesnt, like:

(lldb) p (char*)0x0000ffff90027000
(char *) $1 = 0x0000ffff90027000 "LLDB"
(lldb) p (char*)0xff0afffff7ff9000
(char *) $2 = 0xff0afffff7ff9000 ""

I think this may use the number of addressable bits setting (as opposed to the masks), that could be missing
in a corefile. Planning changes to work on that and add tests for it.

DavidSpickett planned changes to this revision.Mar 25 2022, 9:03 AM
  • Corefile down to 24k with some tweaking of coredump_filter

24k is pretty good. At this point, if you wanted to go down further, you'd probably have to ditch libc, which may not be as hard if you don't need mmap (the comment indicates that is because of lldb reading globals eagerly, but it can't read globals without having access to the exe file).

Fix "expression"/"p" result by removing non-address bits in processElfCore::ReadMemory.
I missed that it overrides this. (it was nothing to do with the target addressable bits setting)

Add tests for that and process/target API use with the corefile.

I did try to avoid the mmap call to reduce the corefile further but couldn't find
any corefile filter that would still include the buffer without being > 300k.

Very corner case but Is there a possibility of masks changing positions during the life-time of an inferior ? So this makes me think that code/data masks are per process and cant be changes once set. Should we worry about it?AFAIK this is fine but just asking to clear any ambiguities.

The current assumption is that once you've got a valid (currently anything non-zero) mask then that's it, it's not going to change. I think a future extension could change the meaning of the existing non-address bits at runtime, but that wouldn't be a problem unless you're something like the tagging commands. 99% of the time we want to remove all non-address bits no matter what they mean.

Changing the virtual address size is the real problem if it ever happens but given that the stack is assumed to be at the top of memory, it would be difficult. Shrinking means cutting off/moving the stack down (with some kind of position independent stack?) and growing it means you can't make top of stack == end of memory assumptions. You could do it with some kind of fork or restart but I think lldb would just handle that fine like it normally does.

Side note: the "0 means not read yet" pattern seems like it could lead to some waste with a target that genuinely has no mask but that's not relevant to this change.

There's some argument that the thing asking for the mask shouldn't ask so early but I think the logic here is still an improvement regardless. If we don't have a thread yet we can't have a mask.

If we don't have a thread yet we can't have a mask.

Though this isn't a watertight argument since I think Mach corefiles can have a note that tells you the number of addressable bits. In our case there's nothing like that.

omjavaid accepted this revision.Apr 26 2022, 3:29 AM

LGTM. With a minor nit fix about FixAnyAddress vs FixDataAddress if required.

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
288

Is this a candidate for FixAnyAddress ?

This revision is now accepted and ready to land.Apr 26 2022, 3:29 AM
DavidSpickett added inline comments.Apr 26 2022, 3:40 AM
lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
288

Absolutely. I intend to get FixAny in first, then update this and the stacked patch to use it.

Use FixAnyAddress.

DavidSpickett marked an inline comment as done.Apr 28 2022, 7:50 AM