[Lldb-commits] [lldb] [lldb][docs] Add hardware feature considerations to target doc (PR #211213)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 27 08:55:32 PDT 2026
https://github.com/DavidSpickett updated https://github.com/llvm/llvm-project/pull/211213
>From b77aced563dc3f62115931a78d37266cc15212ea Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Tue, 21 Jul 2026 14:27:15 +0000
Subject: [PATCH 01/10] [lldb][docs] Add hardware feature considerations to
target doc
As requested on #207166, this change adds information about
hardware features that can help or hinder porting LLDB.
I decided not to add an explicit "help" or "hinder" tag
to them because the descriptions are pretty general and
I'd rather people took them as starting points to think
for themselves.
Debugging is a pile of things working together, so it's
hard to say that lack of one thing is "bad" without
seeing it in context. Hopefully by thinking about all
these items for their target, developers will be able
to do that.
---
lldb/docs/resources/addingtargetsupport.md | 148 +++++++++++++++++++++
1 file changed, 148 insertions(+)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index f4e1f2d07166b..7f7d9abf2e820 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -298,3 +298,151 @@ As you have seen above, there are a lot of moving parts to a debugger. So
having some set of results to measure progress is very important.
Sometimes a change will get one test to pass, sometimes hundreds, and it
is easy to regress if you are not careful.
+
+## Target Hardware Features
+
+Some hardware features can make porting easier or harder. Below is a
+non-exhaustive list of features and their impacts on porting LLDB.
+
+### Hardware Single Step
+
+If the target lacks this feature, you will have to implement software single
+stepping. Which is much more complex and involves emulating any instruction that
+could modify the program counter.
+
+### Instruction Bundles and Sequences
+
+This is any situation where to resume the program you have to replay some
+previous instructions. LLDB needs to know the extent of the sequence.
+
+For example, an atomic sequence may implement an atomic operation by looping
+until success. When stepping through the sequence normally, this check will
+always fail (due to the debug exceptions) and cause it to loop forever.
+
+You can teach LLDB to find the sequence start point, and replay the whole thing
+as if it were one step.
+
+If you have instruction bundles, check how breakpoints behave and where in the
+bundles they can be placed.
+
+### Single Instruction Equivalents of Sequences
+
+The opposite of the previous point. If your target has single instructions
+for what is normally a sequence, this reduces the work needed in LLDB. Single
+instruction atomics are a common example.
+
+### Runtime Register Resizing
+
+Anything like AArch64's Scalable Vector Extension (SVE) registers. At each stop
+event the registers may have a different size.
+
+Support for this is currently SVE specific as it requires `lldb` to know which
+registers scale and what to derive their size from.
+
+### Registers That Come And Go At Runtime
+
+Anything like AArch64's Scalable Matrix Extension (SME) `ZA` register. This
+register can be switched off when not in use. At the moment we do not show
+this accurately. When the register is off, we show the user a fake zero
+value instead of hiding the register.
+
+### Execution Modes That Change Instruction Encoding
+
+Arm (meaning Armv7 and prior) has 2 execution modes: Arm and Thumb. If you
+attempt to execute Thumb mode code in Arm mode, it will not work. Programs can
+mix the two modes by using special mode switching branches.
+
+The debugger has to be aware of what mode the inferior is in so that it can
+correctly compare addresses, place breakpoints and use the correct breakpoint
+instruction encoding.
+
+In Arm's case, the information comes from markers in the program file, and the
+bottom bit of the program counter. This is often a source of bugs because many
+parts of the debugger have to know that this bit is not part of the instruction
+address.
+
+### Variable Length Instruction Encoding
+
+LLDB already supports a wide variety of encoding strategies, so variable length
+encoding is not much more work than fixed length.
+
+Of the current targets we have:
+* Intel which is variable length.
+* Arm (Armv7 and prior) with Arm (32-bit), Thumb 1 (16-bit) and Thumb 2
+ (a mix of 16 and 32-bit).
+* RISC-V which is variable, usually 32-bit or the 16-bit compressed
+ instructions.
+* AArch64 which is fixed length, always 32-bit.
+
+### Hardware Breakpoints and Watchpoints
+
+Breakpoints can be implemented in software by replacing an instruction with a
+software breakpoint instruction.
+
+However, if you want to only stop in certain situations (a single address space,
+a single execution mode, and so on), hardware breakpoints will be much faster.
+
+Doing this in software means you have to return into the debugger to filter
+every stop event. Which is slow even when locally debugging. Put the debug
+server on the end of a high latency connection and the slow down is multiplied.
+
+In addition, hardware breakpoints can be set in read-only memory. Which is
+important for code executing out of ROM, common on embedded targets.
+
+:::{note}
+LLDB still has to be taught how to program hardware breakpoints, and this work
+has not been done completely for all targets. This generally comes down to
+demand. If it would be faster but the use case is rare, it is unlikely to be
+supported.
+:::
+
+Watchpoints pretty much have to be implemented in hardware because the software
+equivalent is much more invasive. For example you could unmap the memory
+containing the watched location, then filter the memory faults to find the ones
+you care about.
+
+However this requires a lot of traffic between debugger and debug server, and
+needs to be implemented for every supported operating system.
+
+### Accurate Breakpoints and Watchpoints
+
+Ideally your break and watchpoint exceptions contain enough information to
+know exactly what caused them. Which seems obvious from a software level, but
+if you check the architecture specifications you will find that they often allow
+a range of behaviours.
+
+For instance, if you watch a 4 byte chunk of memory and an instruction writes 8
+bytes over it, is the hardware required to report an address in the watched 4
+bytes? Or can it report an address in the second 4 bytes, because it is still
+part of the write that triggered the watchpoint?
+
+LLDB will assume accuracy unless told otherwise, and if there are untraceable
+situations users will have to figure out which watch or breakpoints to manually
+disable so that they can continue.
+
+### Addresses That Are More Than Just Numbers
+
+Though many programming languages have rules that prevent the use of pointers
+in some integer-like ways, the reality is that a lot of hardware treats them
+as numbers.
+
+This changes with capabilities (for example CHERI), mode bits (Arm's Thumb) and
+re-use of non-address bits (AArch64's TBI, MTE and PAC). A pointer is no longer
+just a number that refers to a memory location, it contains extra information.
+
+Where the size of the pointer is equal to the bit width of the architecture
+(64-bit pointers on AArch64 for example), LLDB can probably handle it. LLDB
+already has the concept of "non-address bits" that must be removed to get the
+memory address from a pointer.
+
+If pointers are like capabilities where their size is greater than that of
+a memory address, you will need to change the type LLDB uses to store addresses
+which is a lot more work.
+
+### Multiple Address Spaces
+
+At this time LLDB does not support multiple address spaces. Work is ongoing to
+add them, with WASM and GPU targets as the main motivation.
+
+Like anything that changes what an "address" consists of, it has a big impact
+on LLDB.
>From d9c8fdfef9ae85c363412c2cdb80f001778dde65 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:24:37 +0100
Subject: [PATCH 02/10] clean up register bit
---
lldb/docs/resources/addingtargetsupport.md | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index 7f7d9abf2e820..d3f2bf7c064e1 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -307,7 +307,7 @@ non-exhaustive list of features and their impacts on porting LLDB.
### Hardware Single Step
If the target lacks this feature, you will have to implement software single
-stepping. Which is much more complex and involves emulating any instruction that
+stepping. This is much more complex and involves emulating any instruction that
could modify the program counter.
### Instruction Bundles and Sequences
@@ -341,10 +341,18 @@ registers scale and what to derive their size from.
### Registers That Come And Go At Runtime
-Anything like AArch64's Scalable Matrix Extension (SME) `ZA` register. This
-register can be switched off when not in use. At the moment we do not show
-this accurately. When the register is off, we show the user a fake zero
-value instead of hiding the register.
+If you have registers that are not present for the entire program runtime you
+will need to decide how to present that.
+
+The one example we support right now is AArch64's Scalable Matrix Extension
+(SME) `ZA` register. This register can be switched off when not in use.
+We handle this by showing a fake zero value at these times, with a separate
+mode bit in another register so users can tell a real zero from a fake zero.
+
+The more fundemental and the more numerous the registers are, the more
+likely you are to confuse users by showing them even when they are unusable.
+For instance if you have two execution modes that use separate register sets,
+showing both all the time makes it hard to tell what mode you are in.
### Execution Modes That Change Instruction Encoding
>From 37e291c8359477786fafb0c99c232b50e3e5fb08 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:34:00 +0100
Subject: [PATCH 03/10] add register name overlap
---
lldb/docs/resources/addingtargetsupport.md | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index d3f2bf7c064e1..2729e81685e94 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -354,6 +354,22 @@ likely you are to confuse users by showing them even when they are unusable.
For instance if you have two execution modes that use separate register sets,
showing both all the time makes it hard to tell what mode you are in.
+### Registers With The Same Name In Different Contexts
+
+When you have banked registers or a copy of a register for each execution mode,
+it usually only has one name. You need to decide if it makes sense to
+allow users to access each one separately.
+
+For example, AArch64's SME extension adds a "streaming mode". SVE registers
+exist in the normal mode and the streaming mode. However programs only ever use
+one or the other, and the values are cleared when the mode is switched. So there
+is no reason to let users write to the inactive mode's registers, and so we just
+present 1 set with the normal naming.
+
+However if you have overlapping sets that can hold their own values, you may
+want to make the normal register name the active set, and have a way to address
+the other sets.
+
### Execution Modes That Change Instruction Encoding
Arm (meaning Armv7 and prior) has 2 execution modes: Arm and Thumb. If you
>From 9d15a09a045d569e570beb5085e2baa2e4a4163a Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:35:10 +0100
Subject: [PATCH 04/10] wip
---
lldb/docs/resources/addingtargetsupport.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index 2729e81685e94..a2d7590c56206 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -352,7 +352,7 @@ mode bit in another register so users can tell a real zero from a fake zero.
The more fundemental and the more numerous the registers are, the more
likely you are to confuse users by showing them even when they are unusable.
For instance if you have two execution modes that use separate register sets,
-showing both all the time makes it hard to tell what mode you are in.
+showing both all the time may be confusing for users.
### Registers With The Same Name In Different Contexts
>From 8399c5e1038f1795dc9cb6a31c0c396e84b09255 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:46:54 +0100
Subject: [PATCH 05/10] cleannup breakpoint section
---
lldb/docs/resources/addingtargetsupport.md | 41 ++++++++++++----------
1 file changed, 23 insertions(+), 18 deletions(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index a2d7590c56206..98f66fe0bda13 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -400,33 +400,38 @@ Of the current targets we have:
### Hardware Breakpoints and Watchpoints
-Breakpoints can be implemented in software by replacing an instruction with a
-software breakpoint instruction.
+Code breakpoints can be implemented in software by replacing an instruction with
+a software breakpoint instruction.
However, if you want to only stop in certain situations (a single address space,
-a single execution mode, and so on), hardware breakpoints will be much faster.
+a single execution mode, and so on), code breakpoints implemented in hardware
+will be much faster.
-Doing this in software means you have to return into the debugger to filter
+Doing it in software means you have to return into the debugger to filter
every stop event. Which is slow even when locally debugging. Put the debug
server on the end of a high latency connection and the slow down is multiplied.
-In addition, hardware breakpoints can be set in read-only memory. Which is
-important for code executing out of ROM, common on embedded targets.
+In addition, hardware code breakpoints can be set in read-only memory. Which is
+important for code executing out of ROM, which is common on embedded targets.
-:::{note}
-LLDB still has to be taught how to program hardware breakpoints, and this work
-has not been done completely for all targets. This generally comes down to
-demand. If it would be faster but the use case is rare, it is unlikely to be
-supported.
-:::
+Watchpoints are used to wait for a specific type of access to a specific range
+of memory. Doing this in software is possible but very invasive so use hardware
+watchpoints if you can.
+
+For comparison, one way to implement a software watchpoint is to unmap the
+memory around a location and then filter the memory faults to find the access
+you are looking for. This requires a lot of traffic between debugger and debug
+server, and needs to be implemented for every supported operating system.
-Watchpoints pretty much have to be implemented in hardware because the software
-equivalent is much more invasive. For example you could unmap the memory
-containing the watched location, then filter the memory faults to find the ones
-you care about.
+Whereas a hardware watchpoint is usually a few registers programmed with
+hardware specific values, and most operating systems expose those registers
+directly to userspace.
-However this requires a lot of traffic between debugger and debug server, and
-needs to be implemented for every supported operating system.
+:::{note}
+Hardware often has many more features than LLDB makes use of. What we make use
+of is decided by how useful it will be to how many users and how understandable
+it will be presented in the LLDB interface.
+:::
### Accurate Breakpoints and Watchpoints
>From 2e6309536a468e00e1a86acd5a4144d87edda71c Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:47:36 +0100
Subject: [PATCH 06/10] remove address spaces
this will get solved and it'll just be out of date
---
lldb/docs/resources/addingtargetsupport.md | 8 --------
1 file changed, 8 deletions(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index 98f66fe0bda13..92fdb53dc1e15 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -467,11 +467,3 @@ memory address from a pointer.
If pointers are like capabilities where their size is greater than that of
a memory address, you will need to change the type LLDB uses to store addresses
which is a lot more work.
-
-### Multiple Address Spaces
-
-At this time LLDB does not support multiple address spaces. Work is ongoing to
-add them, with WASM and GPU targets as the main motivation.
-
-Like anything that changes what an "address" consists of, it has a big impact
-on LLDB.
>From 20d9a2dfe5a10b02b15ef4c21a843d16480b4cf5 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 14:49:16 +0100
Subject: [PATCH 07/10] misc
---
lldb/docs/resources/addingtargetsupport.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index 92fdb53dc1e15..f81173bd2ba0a 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -363,8 +363,8 @@ allow users to access each one separately.
For example, AArch64's SME extension adds a "streaming mode". SVE registers
exist in the normal mode and the streaming mode. However programs only ever use
one or the other, and the values are cleared when the mode is switched. So there
-is no reason to let users write to the inactive mode's registers, and so we just
-present 1 set with the normal naming.
+is no reason to let users write to the inactive mode's registers and we just
+show 1 set with the normal naming. That set always refers to the active mode.
However if you have overlapping sets that can hold their own values, you may
want to make the normal register name the active set, and have a way to address
>From 57e55ed4a64e72c3dd1f404c891030509d683b44 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 23 Jul 2026 15:28:38 +0100
Subject: [PATCH 08/10] address review comment
---
lldb/docs/resources/addingtargetsupport.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index f81173bd2ba0a..f5fb34623ce4c 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -407,9 +407,10 @@ However, if you want to only stop in certain situations (a single address space,
a single execution mode, and so on), code breakpoints implemented in hardware
will be much faster.
-Doing it in software means you have to return into the debugger to filter
-every stop event. Which is slow even when locally debugging. Put the debug
-server on the end of a high latency connection and the slow down is multiplied.
+Doing it in software means you have to context switch between the debug stub and
+the debugger to filter every stop event. Which is slow even when locally
+debugging. Put the debug server on the end of a high latency connection and the
+slow down is multiplied.
In addition, hardware code breakpoints can be set in read-only memory. Which is
important for code executing out of ROM, which is common on embedded targets.
>From 8b077b0ab38be37f934ecc92cd0ff582393e8780 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Mon, 27 Jul 2026 15:49:50 +0000
Subject: [PATCH 09/10] missing word
---
lldb/docs/resources/addingtargetsupport.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index f5fb34623ce4c..9b9b80f09926f 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -431,7 +431,7 @@ directly to userspace.
:::{note}
Hardware often has many more features than LLDB makes use of. What we make use
of is decided by how useful it will be to how many users and how understandable
-it will be presented in the LLDB interface.
+it will be when presented in the LLDB interface.
:::
### Accurate Breakpoints and Watchpoints
>From 9c29416c1f357de4b2871e47e158d52fc79cae56 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Mon, 27 Jul 2026 15:55:07 +0000
Subject: [PATCH 10/10] fix spelling
---
lldb/docs/resources/addingtargetsupport.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/docs/resources/addingtargetsupport.md b/lldb/docs/resources/addingtargetsupport.md
index 9b9b80f09926f..424d3d68da7ad 100644
--- a/lldb/docs/resources/addingtargetsupport.md
+++ b/lldb/docs/resources/addingtargetsupport.md
@@ -349,7 +349,7 @@ The one example we support right now is AArch64's Scalable Matrix Extension
We handle this by showing a fake zero value at these times, with a separate
mode bit in another register so users can tell a real zero from a fake zero.
-The more fundemental and the more numerous the registers are, the more
+The more fundamental and the more numerous the registers are, the more
likely you are to confuse users by showing them even when they are unusable.
For instance if you have two execution modes that use separate register sets,
showing both all the time may be confusing for users.
More information about the lldb-commits
mailing list