This is an archive of the discontinued LLVM Phabricator instance.

[lldb][AArch64] Add class for managing memory tags
ClosedPublic

Authored by DavidSpickett on Feb 23 2021, 6:25 AM.

Details

Summary

This adds the MemoryTagManager class and a specialisation
of that class for AArch64 MTE tags. It provides a generic
interface for various tagging operations.
Adding/removing tags, diffing tagged pointers, etc.

Later patches will use this manager to handle memory tags
in generic code in both lldb and lldb-server.
Since it will be used in both, the base class header is in
lldb/Target.
(MemoryRegionInfo is another example of this pattern)

Diff Detail

Event Timeline

DavidSpickett created this revision.Feb 23 2021, 6:25 AM
DavidSpickett requested review of this revision.Feb 23 2021, 6:25 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 23 2021, 6:25 AM

Omair, I've taken one of your suggestions on the class name from the other review.

The MTE RFC gives some background on why we need such a class (https://lists.llvm.org/pipermail/lldb-dev/2020-August/016402.html).

Some of the operations map to the intrinsics provided by the ACLE:
https://developer.arm.com/documentation/101028/0012/10--Memory-tagging-intrinsics

This looks good overall except for one comment inline.

lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
44

I am a little apprehensive about this AddressDiff function. AArch64 virtual address is either 48 bits or 52 bits. MTE start from 56th bit and I believe bits (48 - 55) will be either set zero (for user address) and set to one for kernel addresses.
I am not sure if there is an interface available for us to know if VA is 48 or 52 bits. What do you think how should we manage this here.

DavidSpickett added inline comments.Mar 1 2021, 3:34 AM
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
44

I looked at this a while back and there is no user space way to tell what size virtual address you have. You can assume at least 48 but then the rest I think is handled by some backwards compatibility stuff that means you don't have to care.

What is an issue is this only ignores the tag bits, not the whole top byte. This is the instruction the ptrdiff intrinsic emits:

C6.2.317 SUBPS
Subtract Pointer, setting Flags subtracts the 56-bit address held in the second source register from the 56-bit address
held in the first source register, sign-extends the result to 64-bits, and writes the result to the destination register. It
updates the condition flags based on the result of the subtraction.

That assumes top byte ignore, so I should be doing the same here along with the sign extension to handle the 0/1 fill.
(this might apply to a lot more than just this diff call too)

omjavaid added inline comments.Mar 2 2021, 4:28 AM
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
44

hmm .. yes GDB also assumes 52 bit address for AArch64. Did you try reading kenel space address during testing and see what you get in that case may be stepping into a syscall (never tried it with LLDB) not sure if this is a must have for LLDB as its currently a user application debugger as far as AArch64 is concerned.

Even if this is 52 bits VA this function assumes bit 52-55 set to zero? This can also mean that by the time we get this address TBI interface would have cleaned it up for us?

I think we should have a way to figure out significant address bits and clean up the rest. For now this needs no change but I guess I ll have to manage this in TBI support and provided and interface for significant address bit for a process.

DavidSpickett added inline comments.Mar 2 2021, 5:43 AM
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
44

I wasn't aware stepping into a syscall was a thing for lldb but I'll see what I can find.

General TBI handling would solve some of this, still need to sign extend based on bit 55 I think.

I'm going to change this to ignore the top byte always, so it'll work on a PAC+MTE system. Then later we can make it use the "proper" TBI hooks.

  • Add RemoveNonAddressBits which will remove the entire top byte not just tags
  • Remove SetLogicalTag/RemoveLogicalTag/CopyLogicalTag which are now unused in the proceeding patches

@labath Could you comment on the overall strategy that I'm going for?

I'll summarise my intention, the rest of the review stack here implements that if you have time/want to dig into the details.

  • Tag managers provide utilities to handle tags without knowing the details of each tagging scheme
  • lldb commands can get one by asking the current process, which looks for an architecture plugin, which can then provide a tag manager or not
  • lldb uses the "mt" flag of memory regions to precheck reads before sending them
  • lldb-server will ask the native register context for a manager, which can provide one or not based on the target and what it's being asked to do

It would be great to get agreement on those key points since it forms the basis of the new commands.

FWIW I have implemented "memory tag write" based on this and it works quite well, but I can put that up too if you feel the context would help. (another 4/5 patches)

@omjavaid The tag manager AddressDiff is currently removing the whole top byte. I think eventually we'll want to go back to removing just the tag bits and let your non address bits handle the rest but for now it's working ok.

  • Rebase onto main

Rebase onto main.

This looks ok to me apart from some cosmetic nits. Also you may figure out a way to clean up the whole address including pauth now after D99944 is merged.

lldb/include/lldb/Target/MemoryTagManager.h
73

Bytes per tag conveys a different message like "No of bytes of memory this tag corresponds to"
It could GetTagByteSize or something.

80

This might also be renamed to UnpackTagsData because input is not guaranteed to be tags unless their byte size is 1.

lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
29

This function need to take care of Pointer Auth mask which could be living in bits 48:54

62

May be consider doing something like below to avoid calculating mod twice.

lldb::addr_t align_up_amount = new_len % granule;
if (align_up_amount)
....
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
25

All functions below have no spacing between them may be consider adding a few spaces while combining declaration of setter/getter or other similar function in consecutive lines.

lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp
74

This is confusing // Reading less than 1 granule, rounds up to 1 granule
May be reword a little like "No of bytes being read are less than bytes per granule"

101

This should be able to remove pointer auth mask so fix this test accordingly.

117

likewise.

Address all comments apart from address handling that I need
to spend some time thinking about.

It may end up that the best way to do this is have the tag manager
provide a way to remove only the tags and let the other parts
of lldb deal with addresses using the ABI methods you're adding.

DavidSpickett marked 7 inline comments as done.May 13 2021, 5:21 AM

@DavidSpickett Do you have any further plans for this and other patches in the series. I was wondering if there is nothing to add we can go ahead and merge this series.

I am going to go over them this afternoon. I'm about to land some lldb patches that allow some easy refactoring, and your ABI patch might be useable too. If using the ABI method is better as a follow up then we can get started landing them.

Rebase onto main.

@omjavaid As it stands, RemoveNonAddressBits here removes the top byte unconditionally.

You asked for pointer signatures to be removed as well, which would be neatly solved by using the ABI plugin. Ok to land this as is, then write a follow up to migrate to using the ABI plugin?

omjavaid accepted this revision.Jun 21 2021, 5:30 AM

@omjavaid As it stands, RemoveNonAddressBits here removes the top byte unconditionally.

You asked for pointer signatures to be removed as well, which would be neatly solved by using the ABI plugin. Ok to land this as is, then write a follow up to migrate to using the ABI plugin?

Yes I think this is LGTM.

This revision is now accepted and ready to land.Jun 21 2021, 5:30 AM
This revision was landed with ongoing or failed builds.Jun 24 2021, 7:10 AM
This revision was automatically updated to reflect the committed changes.