RFC: How to handle non-address bits in the output of "memory read"

(Peter and Stephen on CC since you've previously asked about this sort of thing)

This relates to ⚙ D103626 [lldb] Remove non address bits from memory read arguments and other recent
patches about non-address bits.

On AArch64 we've got a few extensions that use "non address bits".
These are bits beyond the (in most cases) 48 bit virtual address size.
Currently we have pointer authentication (armv8.3), memory tagging
(armv8.5) and top byte ignore (a feature of armv8.0-a).

This means we need to know about these bits when doing some
operations. One such time is when passing addresses to memory read.
Consider two pointers to the same location where the first one has a
greater memory tag (bits 56-60) than the second. This is what happens
if we don't remove the non-address bits:
(lldb) memory read mte_buf_alt_tag mte_buf+16
error: end address (0x900fffff7ff8010) must be greater than the start
address (0xa00fffff7ff8000).

A pure number comparison is going to think that end < begin address.
If we use the ABI plugin's FixDataAddress we can remove those bits and
read normally.

With one caveat. The output will not include those non address bits
unless we make special effort to do so, here's an example:
(lldb) p ptr1
(char *) $4 = 0x3400fffffffff140 "\x80\xf1\xff\xff\xff\xff"
(lldb) p ptr2
(char *) $5 = 0x5600fffffffff140 "\x80\xf1\xff\xff\xff\xff"
(lldb) memory read ptr1 ptr2+16
0xfffffffff140: 80 f1 ff ff ff ff 00 00 38 70 bc f7 ff ff 00 00
........8p......

My current opinion is that in this case the output should not include
the non address bits:
* The actual memory being read is not at the virtual address the raw
pointer value gives.
* Many, if not all, non address bits cannot be incremented as the
memory address we're showing is incremented. (not in a way that makes
sense if you think about how the core interprets them)

For example once you get into the next memory granule, the memory tag
attached to it in hardware may be different. (and FWIW I have a series
to show the actual memory tags ⚙ D107140 [lldb] Add option to show memory tags in memory read output)
You could perhaps argue that if the program itself used that pointer,
it would use those non address bits as well so show the user *how* it
would access the memory. However I don't think that justifies
complicating the implementation and output.

So what do people think of that direction? I've thought about this for
too long before asking for feedback, so I'm definitely missing some of
the wood for the trees.

Input/bug reports/complaints from anyone who (unlike me) has debugged
a large program that uses these non-address features is most welcome!

Thanks,
David Spickett.

Hi David,

Sending this message again as I’m now back from vacation (and I was finally able to subscribe to lldb-dev - non-subscribers are prevented from sending email to it).

(Peter and Stephen on CC since you’ve previously asked about this sort of thing)

This relates to https://reviews.llvm.org/D103626 and other recent
patches about non-address bits.

On AArch64 we’ve got a few extensions that use “non address bits”.
These are bits beyond the (in most cases) 48 bit virtual address size.
Currently we have pointer authentication (armv8.3), memory tagging
(armv8.5) and top byte ignore (a feature of armv8.0-a).

This means we need to know about these bits when doing some
operations. One such time is when passing addresses to memory read.
Consider two pointers to the same location where the first one has a
greater memory tag (bits 56-60) than the second. This is what happens
if we don’t remove the non-address bits:
(lldb) memory read mte_buf_alt_tag mte_buf+16
error: end address (0x900fffff7ff8010) must be greater than the start
address (0xa00fffff7ff8000).

A pure number comparison is going to think that end < begin address.
If we use the ABI plugin’s FixDataAddress we can remove those bits and
read normally.

With one caveat. The output will not include those non address bits
unless we make special effort to do so, here’s an example:
(lldb) p ptr1
(char *) $4 = 0x3400fffffffff140 “\x80\xf1\xff\xff\xff\xff”
(lldb) p ptr2
(char *) $5 = 0x5600fffffffff140 “\x80\xf1\xff\xff\xff\xff”
(lldb) memory read ptr1 ptr2+16
0xfffffffff140: 80 f1 ff ff ff ff 00 00 38 70 bc f7 ff ff 00 00
…8p…

My current opinion is that in this case the output should not include
the non address bits:

  • The actual memory being read is not at the virtual address the raw
    pointer value gives.
  • Many, if not all, non address bits cannot be incremented as the
    memory address we’re showing is incremented. (not in a way that makes
    sense if you think about how the core interprets them)

I agree that the printed addresses should not include any of the ignored top byte, because lldb is displaying what’s at the actual virtual address now, and not how we got there (i.e. the pointer).

For example once you get into the next memory granule, the memory tag
attached to it in hardware may be different. (and FWIW I have a series
to show the actual memory tags https://reviews.llvm.org/D107140)
You could perhaps argue that if the program itself used that pointer,
it would use those non address bits as well so show the user how it
would access the memory. However I don’t think that justifies
complicating the implementation and output.

So what do people think of that direction? I’ve thought about this for
too long before asking for feedback, so I’m definitely missing some of
the wood for the trees.

Input/bug reports/complaints from anyone who (unlike me) has debugged
a large program that uses these non-address features is most welcome!

Thanks,
David Spickett.

We have a customer who is encountering issues with this in LLDB today, so I asked them to comment on this thread (but I’m not sure if they will). The current behavior prevents them from using LLDB with their core dumps.

Thanks,
Steve