This PR replaces the Get*CallbackAtIndex pattern in the PluginManager
with returning a snapshot of callbacks that the caller can iterate over
using a range-based for loop. This is a continuation of #184452 which
added thread safety by using snapshots. However, that introduced a bunch
of unnecessary copies which are largely eliminated again by getting the
snapshot once when gather all the callbacks, rather than doing that on
each iteration when querying a plugin for a given index. It also
eliminates the possibility of the snapshot changing underneath you when
iterating over the plugins.
This change was largely mechanical and I used Claude to do the menial
work of updating the signatures and call sites.
## Description
Contribution to this topic [Rich Disassembler for
LLDB](https://discourse.llvm.org/t/rich-disassembler-for-lldb/76952),
this part.
```
The rich disassembler output should be exposed as structured data and made available through LLDB’s scripting API so more tooling could be built on top of this
```
----
This pr replaces #174847
As was suggested in [this
comment](https://github.com/llvm/llvm-project/pull/174847#issuecomment-3757015552),
implement access to variable annotations from `SBInstruction` class
itself.
Notes:
- ✅ did run black formatter on the python file;
## Testing
Run test with
```sh
./build/bin/lldb-dotest -v -p TestVariableAnnotationsDisassembler.py lldb/test/API/functionalities/disassembler-variables
```
all tests (9 existing + 1 newly added) are passing
<details>
<summary>screenshot 2026-01-23</summary>
build from the latest commit 08f00730b5768a8e3f7039d810084fabaaa24470
<img width="1506" height="562" alt="image"
src="https://github.com/user-attachments/assets/69516353-3432-47df-ae45-c40b51ec14c4"
/>
</details>
<details>
<summary>screenshot 2026-01-29</summary>
build from the latest commit f48a1a2c10f96a457ca6844be2ccc9406d3d57a0
<img width="1232" height="740" alt="image"
src="https://github.com/user-attachments/assets/9d104ce6-36c3-430b-98fe-f028f83a6b6d"
/>
</details>
---------
Signed-off-by: Nikita B <n2h9z4@gmail.com>
## Description
Contribution to this topic [Rich Disassembler for
LLDB](https://discourse.llvm.org/t/rich-disassembler-for-lldb/76952),
this part.
```
The rich disassembler output should be exposed as structured data and made available through LLDB’s scripting API so more tooling could be built on top of this
```
----
This pr introduces new method `AnnotateStructured` in
`VariableAnnotator` class, which returns the result as a vector of
`VariableAnnotation` structured data, compared to original `Annotate`.
Additionally structured data is enhanced with information inferred from
`DWARFExpressionEntry` and variable declaration data.
I have moved this part of functionality form a bigger pr
https://github.com/llvm/llvm-project/pull/165163 to make it easier to
review, deliver smaller chunk faster in an incremental way.
## Testing
Run test with
```sh
./build/bin/lldb-dotest -v -p TestVariableAnnotationsDisassembler.py lldb/test/API/functionalities/disassembler-variables
```
all tests (9 existing) are passing.
<details>
<summary>screenshot 2025-11-24</summary>
<img width="1344" height="875" alt="screenshot"
src="https://github.com/user-attachments/assets/863e0fca-1e3e-43dc-bfa3-4b78ce287ae6"
/>
</details>
<details>
<summary>screenshot 2025-11-26</summary>
<img width="1851" height="865" alt="image"
src="https://github.com/user-attachments/assets/d47dacee-a679-4a49-ab22-efb5a16fe29c"
/>
</details>
<details>
<summary>screenshot 2025-12-03</summary>
<img width="1592" height="922" alt="Screenshot From 2025-12-03 22-11-30"
src="https://github.com/user-attachments/assets/957ded3d-bea1-43d0-8241-d342dfc2c7b0"
/>
</details>
---------
Signed-off-by: Nikita B <n2h9z4@gmail.com>
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
This will allow the instruction emulation unwinder to reason about
instructions that prevent the subsequent instruction from executing.
Part of a sequence of PRs:
[lldb][NFCI] Rewrite UnwindAssemblyInstEmulation in terms of a CFG visit
#169630
[lldb][NFC] Rename forward_branch_offset to branch_offset in
UnwindAssemblyInstEmulation #169631
[lldb] Add DisassemblerLLVMC::IsBarrier API #169632
[lldb] Handle backwards branches in UnwindAssemblyInstEmulation #169633
commit-id:bb5df4aa
This patch fixes and eliminates the possibility of SupportFileSP ever
being nullptr. The support file was originally treated like a value
type, but became a polymorphic type and therefore has to be stored and
passed around as a pointer.
To avoid having all the callers check the validity of the pointer, I
introduced the invariant that SupportFileSP is never null and always
default constructed. However, without enforcement at the type level,
that's fragile and indeed, we already identified two crashes where
someone accidentally broke that invariant.
This PR introduces a NonNullSharedPtr to prevent that. NonNullSharedPtr
is a smart pointer wrapper around std::shared_ptr that guarantees the
pointer is never null. If default-constructed, it creates a
default-constructed instance of the contained type. Note that I'm using
private inheritance because you shouldn't inherit from standard library
classes due to the lack of virtual destructor. So while the new
abstraction looks like a `std::shared_ptr`, it is in fact **not** a
shared pointer. Given that our destructor is trivial, we could use
public inheritance, but currently there's no need for it.
rdar://164989579
This patch is a follow-up to
[#152887](https://github.com/llvm/llvm-project/pull/152887), addressing
review comments that came in after the original change was merged.
- Move `VarState` definition out of `PrintInstructions` into a private
helper, with member comments placed before fields.
- Introduce a `VariableAnnotator` helper class to encapsulate state and
logic for live variable tracking across instructions.
- Replace `seen_this_inst` flag with a map-diff approach: recompute the
current variable set per instruction and diff against the previous set.
- Use `nullptr` instead of an empty `ProcessSP` when calling
`ABI::FindPlugin`.
- Narrow `Block*` scope with `if (Block *B = ...)`.
- Set `DIDumpOptions::PrintRegisterOnly` directly from
`static_cast<bool>(abi_sp)`.
- Prefer `emplace_back` over `push_back` for event strings.
- General cleanup to match LLVM coding style and reviewer feedback.
This makes the annotation code easier to read and consistent with
LLVM/LLDB conventions while preserving functionality.
**Context**
Follow-up to
[#147460](https://github.com/llvm/llvm-project/pull/147460), which added
the ability to surface register-resident variable locations.
This PR moves the annotation logic out of `Instruction::Dump()` and into
`Disassembler::PrintInstructions()`, and adds lightweight state tracking
so we only print changes at range starts and when variables go out of
scope.
---
## What this does
While iterating the instructions for a function, we maintain a “live
variable map” keyed by `lldb::user_id_t` (the `Variable`’s ID) to
remember each variable’s last emitted location string. For each
instruction:
- **New (or newly visible) variable** → print `name = <location>` once
at the start of its DWARF location range, cache it.
- **Location changed** (e.g., DWARF range switched to a different
register/const) → print the updated mapping.
- **Out of scope** (was tracked previously but not found for the current
PC) → print `name = <undef>` and drop it.
This produces **concise, stateful annotations** that highlight variable
lifetime transitions without spamming every line.
---
## Why in `PrintInstructions()`?
- Keeps `Instruction` stateless and avoids changing the
`Instruction::Dump()` virtual API.
- Makes it straightforward to diff state across instructions (`prev →
current`) inside the single driver loop.
---
## How it works (high-level)
1. For the current PC, get in-scope variables via
`StackFrame::GetInScopeVariableList(/*get_parent=*/true)`.
2. For each `Variable`, query
`DWARFExpressionList::GetExpressionEntryAtAddress(func_load_addr,
current_pc)` (added in #144238).
3. If the entry exists, call `DumpLocation(..., eDescriptionLevelBrief,
abi)` to get a short, ABI-aware location string (e.g., `DW_OP_reg3 RBX →
RBX`).
4. Compare against the last emitted location in the live map:
- If not present → emit `name = <location>` and record it.
- If different → emit updated mapping and record it.
5. After processing current in-scope variables, compute the set
difference vs. the previous map and emit `name = <undef>` for any that
disappeared.
Internally:
- We respect file↔load address translation already provided by
`DWARFExpressionList`.
- We reuse the ABI to map LLVM register numbers to arch register names.
---
## Example output (x86_64, simplified)
```
-> 0x55c6f5f6a140 <+0>: cmpl $0x2, %edi ; argc = RDI, argv = RSI
0x55c6f5f6a143 <+3>: jl 0x55c6f5f6a176 ; <+54> at d_original_example.c:6:3
0x55c6f5f6a145 <+5>: pushq %r15
0x55c6f5f6a147 <+7>: pushq %r14
0x55c6f5f6a149 <+9>: pushq %rbx
0x55c6f5f6a14a <+10>: movq %rsi, %rbx
0x55c6f5f6a14d <+13>: movl %edi, %r14d
0x55c6f5f6a150 <+16>: movl $0x1, %r15d ; argc = R14
0x55c6f5f6a156 <+22>: nopw %cs:(%rax,%rax) ; i = R15, argv = RBX
0x55c6f5f6a160 <+32>: movq (%rbx,%r15,8), %rdi
0x55c6f5f6a164 <+36>: callq 0x55c6f5f6a030 ; symbol stub for: puts
0x55c6f5f6a169 <+41>: incq %r15
0x55c6f5f6a16c <+44>: cmpq %r15, %r14
0x55c6f5f6a16f <+47>: jne 0x55c6f5f6a160 ; <+32> at d_original_example.c:5:10
0x55c6f5f6a171 <+49>: popq %rbx ; i = <undef>
0x55c6f5f6a172 <+50>: popq %r14 ; argv = RSI
0x55c6f5f6a174 <+52>: popq %r15 ; argc = RDI
0x55c6f5f6a176 <+54>: xorl %eax, %eax
0x55c6f5f6a178 <+56>: retq
```
Only transitions are shown: the start of a location, changes, and
end-of-lifetime.
---
## Scope & limitations (by design)
- Handles **simple locations** first (registers, const-in-register cases
surfaced by `DumpLocation`).
- **Memory/composite locations** are out of scope for this PR.
- Annotations appear **only at range boundaries** (start/change/end) to
minimize noise.
- Output is **target-independent**; register names come from the target
ABI.
## Implementation notes
- All annotation printing now happens in
`Disassembler::PrintInstructions()`.
- Uses `std::unordered_map<lldb::user_id_t, std::string>` as the live
map.
- No persistent state across calls; the map is rebuilt while walking
instruction by instruction.
- **No changes** to the `Instruction` interface.
---
## Requested feedback
- Placement and wording of the `<undef>` marker.
- Whether we should optionally gate this behind a setting (currently
always on when disassembling with an `ExecutionContext`).
- Preference for immediate inclusion of tests vs. follow-up patch.
---
Thanks for reviewing! Happy to adjust behavior/format based on feedback.
---------
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
Co-authored-by: Adrian Prantl <adrian.prantl@gmail.com>
Resolves#141955
- Adds data to breakpoints `Source` object, in order for assembly
breakpoints, which rely on a temporary `sourceReference` value, to be
able to resolve in future sessions like normal path+line breakpoints
- Adds optional `instructions_offset` parameter to `BreakpointResolver`
LLDB uses the LLVM disassembler to determine the size of instructions and
to do the actual disassembly. Currently, if the LLVM disassembler can't
disassemble an instruction, LLDB will ignore the instruction size, assume
the instruction size is the minimum size for that device, print no useful
opcode, and print nothing for the instruction.
This patch changes this behavior to separate the instruction size and
"can't disassemble". If the LLVM disassembler knows the size, but can't
dissasemble the instruction, LLDB will use that size. It will print out
the opcode, and will print "<unknown>" for the instruction. This is much
more useful to both a user and a script.
The impetus behind this change is to clean up RISC-V disassembly when
the LLVM disassembler doesn't understand all of the instructions.
RISC-V supports proprietary extensions, where the TD files don't know
about certain instructions, and the disassembler can't disassemble them.
Internal users want to be able to disassemble these instructions.
With llvm-objdump, the solution is to pipe the output of the disassembly
through a filter program. This patch modifies LLDB's disassembly to look
more like llvm-objdump's, and includes an example python script that adds
a command "fdis" that will disassemble, then pipe the output through a
specified filter program. This has been tested with crustfilt, a sample
filter located at https://github.com/quic/crustfilt .
Changes in this PR:
- Decouple "can't disassemble" with "instruction size".
DisassemblerLLVMC::MCDisasmInstance::GetMCInst now returns a bool for
valid disassembly, and has the size as an out paramter.
Use the size even if the disassembly is invalid.
Disassemble if disassemby is valid.
- Always print out the opcode when -b is specified.
Previously it wouldn't print out the opcode if it couldn't disassemble.
- Print out RISC-V opcodes the way llvm-objdump does.
Code for the new Opcode Type eType16_32Tuples by Jason Molenda.
- Print <unknown> for instructions that can't be disassembled, matching
llvm-objdump, instead of printing nothing.
- Update max riscv32 and riscv64 instruction size to 8.
- Add example "fdis" command script.
- Added disassembly byte test for x86 with known and unknown instructions.
- Added disassembly byte test for riscv32 with known and unknown instructions,
with and without filtering.
- Added test from Jason Molenda to RISC-V disassembly unit tests.
This fixes a data race between the main thread and the default event
handler thread. The statusline format option value was protected by a
mutex, but it was returned as a pointer, allowing one thread to access
it while another was modifying it.
Avoid the data race by returning format values by value instead of by
pointer.
This overload is taking a StackFrame, so we just need to change how we
obtain the ranges out of it. A slightly fiddly aspect is the code which
tries to provide a default dissassembly range for the case where we
don't have a real one. I believe this case is only relevant for
symbol-based stack frames as debug info always has size/range for the
functions (if it didn't we wouldn't even resolve the stack frame to a
function), which is why I've split the handling of the two cases.
We already have a test case for disassembly of discontinuous functions
(in test/Shell/Commands/command-disassemble.s), so I'm not creating
another one as this is just a slightly different entry point into the
same code.
The main change is to permit the disassembler class to process/store
multiple (discontinuous) ranges of addresses. The result is not
ambiguous because each instruction knows its size (in addition to its
address), so we can check for discontinuity by looking at whether the
next instruction begins where the previous ends.
This patch doesn't handle the "disassemble" CLI command, which uses a
more elaborate mechanism for disassembling and printing instructions.
Lots of code around LLDB was directly accessing the target's section
load list. This NFC patch makes the section load list private so the
Target class can access it, but everyone else now uses accessor
functions. This allows us to control the resolving of addresses and will
allow for functionality in LLDB which can lazily resolve addresses in
JIT plug-ins with a future patch.
When retrieving the location of the function declaration, we were
dropping the file component on the floor, which resulted in an amusingly
confusing situation were we displayed the file containing the
implementation of the function, but used the line number of the
declaration. This patch fixes that.
It required a small refactor Function::GetStartLineSourceLineInfo to
return a SupportFile (instead of just the file spec), which in turn
necessitated changes in a couple of other places as well.
Add the ability to override the disassembly CPU and CPU features through
a target setting (`target.disassembly-cpu` and
`target.disassembly-features`) and a `disassemble` command option
(`--cpu` and `--features`).
This is especially relevant for architectures like RISC-V which relies
heavily on CPU extensions.
The majority of this patch is plumbing the options through. I recommend
looking at DisassemblerLLVMC and the test for the observable change in
behavior.
This member variable is completely unused. I also don't think it makes a
ton of sense since (1) The "base address" can be obtained from the first
Instruction in its InstructionList, and (2) InstructionLists may not be
a series of contiguous instructions (even though they are most of the
time).
This is another step towards supporting DWARF5 checksums and inline
source code in LLDB. This is a reland of #85468 but without the
functional change of storing the support file from the line table (yet).
Store a SupportFile, rather than a FileSpec, in LineEntry. This commit
works towards having the SourceManageroperate on SupportFiles so that it
can (1) validate the Checksum and (2) materialize the content of inline
source information.
Add support for syntax color highlighting disassembly in LLDB. This
patch relies on 77d1032516e7, which introduces support for syntax
highlighting in MC.
Currently only AArch64 and X86 have color support, but other interested
backends can adopt WithColor in their respective MCInstPrinter.
Differential revision: https://reviews.llvm.org/D159164
`Instruction::TestEmulation` takes a `Stream *` and checks it for validity.
However, this is unnecessary as we can always ensure that we never pass
`nullptr` for the `Stream` argument. The only use of
`Instruction::TestEmulation` currently is `SBInstruction::TestEmulation`
which gets the `Stream` from an `SBStream`, and `SBStream::ref` can
return a `Stream &` guaranteed.
Differential Revision: https://reviews.llvm.org/D154757
DissassemblerCreateInstance is a function pointer whos return type is
`Disassembler *`. But Disassembler::FindPlugin always returns a
DisassemblerSP, so there's no reason why we can't just create a
DisassemblerSP in the first place.
Differential Revision: https://reviews.llvm.org/D150235
Various OptionValue related classes are passing around will_modify but
the value is never used. This patch simplifies the interfaces by
removing the redundant argument.
Refactor OptionValue to return a std::optional instead of taking a fail
value. This allows the caller to handle situations where there's no
value, instead of being unable to distinguish between the absence of a
value and the value happening the match the fail value. When a fail
value is required, std::optional::value_or() provides the same
functionality.
llvm has a structure for maps where the key's type is a string. Using
that also means that the keys for OptionValueDictionary don't stick
around forever in ConstString's StringPool (even after they are gone).
The only thing we lose here is ordering: iterating over the map where the keys
are ConstStrings guarantees that we iterate in alphabetical order.
StringMap makes no guarantees about the ordering when you iterate over
the entire map.
Differential Revision: https://reviews.llvm.org/D149482
Refactor the string conversion of the `lldb::InstructionControlFlowKind` enum out
of `Instruction::Dump` to enable reuse of this logic by the
JSON TraceDumper (to be implemented in separate diff).
Will coordinate the landing of this change with D130320 since there will be a minor merge conflict between
these changes.
Test Plan:
Run unittests
```
> ninja check-lldb
[4/5] Running lldb unit test suite
Testing Time: 10.13s
Passed: 1084
```
Verify '-k' flag's output
```
(lldb) thread trace dump instructions -k
thread #1: tid = 1375377
libstdc++.so.6`std::ostream::flush() + 43
7048: 0x00007ffff7b54dab return retq
7047: 0x00007ffff7b54daa other popq %rbx
7046: 0x00007ffff7b54da7 other movq %rbx, %rax
7045: 0x00007ffff7b54da5 cond jump je 0x11adb0 ; <+48>
7044: 0x00007ffff7b54da2 other cmpl $-0x1, %eax
libc.so.6`_IO_fflush + 249
7043: 0x00007ffff7161729 return retq
7042: 0x00007ffff7161728 other popq %rbp
7041: 0x00007ffff7161727 other popq %rbx
7040: 0x00007ffff7161725 other movl %edx, %eax
7039: 0x00007ffff7161721 other addq $0x8, %rsp
7038: 0x00007ffff7161709 cond jump je 0x87721 ; <+241>
7037: 0x00007ffff7161707 other decl (%rsi)
7036: 0x00007ffff71616fe cond jump je 0x87707 ; <+215>
7035: 0x00007ffff71616f7 other cmpl $0x0, 0x33de92(%rip) ; __libc_multiple_threads
7034: 0x00007ffff71616ef other movq $0x0, 0x8(%rsi)
7033: 0x00007ffff71616ed cond jump jne 0x87721 ; <+241>
7032: 0x00007ffff71616e9 other subl $0x1, 0x4(%rsi)
7031: 0x00007ffff71616e2 other movq 0x88(%rbx), %rsi
7030: 0x00007ffff71616e0 cond jump jne 0x87721 ; <+241>
7029: 0x00007ffff71616da other testl $0x8000, (%rbx) ; imm = 0x8000
```
Differential Revision: https://reviews.llvm.org/D130580
This diff move the logic of `GetControlFlowKind()` from Disassembler.cpp to DisassemblerLLVMC.cpp.
Here's details:
- Actual logic of GetControlFlowKind() move to `DisassemblerLLVMC.cpp`, and we can check underlying architecture using `DisassemblerScope` there.
- With this change, passing 'triple' to `GetControlFlowKind()` is no more required.
Reviewed By: wallace
Differential Revision: https://reviews.llvm.org/D130320
The C headers are deprecated so as requested in D102845, this is replacing them
all with their (not deprecated) C++ equivalent.
Reviewed By: shafik
Differential Revision: https://reviews.llvm.org/D103084
Commiting this patch for Augusto Noronha who is getting set
up still.
This patch changes Target::ReadMemory so the default behavior
when a read is in a Section that is read-only is to fetch the
data from the local binary image, instead of reading it from
memory. Update all callers to use their old preferences
(the old prefer_file_cache bool) using the new API; we should
revisit these calls and see if they really intend to read
live memory, or if reading from a read-only Section would be
equivalent and important for performance-sensitive cases.
rdar://30634422
Differential revision: https://reviews.llvm.org/D100338
This patch introduces a LLDB_SCOPED_TIMER macro to hide the needlessly
repetitive creation of scoped timers in LLDB. It's similar to the
LLDB_LOG(F) macro.
Differential revision: https://reviews.llvm.org/D93663
Depends on D89408.
This diff finally implements trace decoding!
The current interface is
$ trace load /path/to/trace/session/file.json
$ thread trace dump instructions
thread #1: tid = 3842849, total instructions = 22
[ 0] 0x40052d
[ 1] 0x40052d
...
[19] 0x400521
$ # simply enter, which is a repeat command
[20] 0x40052d
[21] 0x400529
...
This doesn't do any disassembly, which will be done in the next diff.
Changes:
- Added an IntelPTDecoder class, that is a wrapper for libipt, which is the actual library that performs the decoding.
- Added TraceThreadDecoder class that decodes traces and memoizes the result to avoid repeating the decoding step.
- Added a DecodedThread class, which represents the output from decoding and that for the time being only stores the list of reconstructed instructions. Later it'll contain the function call hierarchy, which will enable reconstructing backtraces.
- Added basic APIs for accessing the trace in Trace.h:
- GetInstructionCount, which counts the number of instructions traced for a given thread
- IsTraceFailed, which returns an Error if decoding a thread failed
- ForEachInstruction, which iterates on the instructions traced for a given thread, concealing the internal storage of threads, as plug-ins can decide to generate the instructions on the fly or to store them all in a vector, like I do.
- DumpTraceInstructions was updated to print the instructions or show an error message if decoding was impossible.
- Tests included
Differential Revision: https://reviews.llvm.org/D89283
In a new Range class was introduced to simplify and the Disassembler API
and reduce duplication. It unintentionally broke the
SBFrame::Disassemble functionality because it unconditionally converts
the number of instructions to a Range{Limit::Instructions,
num_instructions}. This is subtly different from the previous behavior,
where now we're passing a Range and assume it's valid in the callee, the
original code would propagate num_instructions and the callee would
compare the value and decided between disassembling instructions or
bytes.
Unfortunately the existing tests was not particularly strict:
disassembly = frame.Disassemble()
self.assertNotEqual(len(disassembly), 0, "Disassembly was empty.")
This would pass because without this patch we'd disassemble zero
instructions, resulting in an error:
(lldb) script print(lldb.frame.Disassemble())
error: error reading data from section __text
Differential revision: https://reviews.llvm.org/D89925
On Hexagon, breakpoints need to be on the first instruction of a packet.
When the LLVM disassembler for Hexagon returned 32 bit instructions, we
needed code to find the start of the current packet. Now that the LLVM
disassembler for Hexagon returns packets instead of instructions, we always
have the first instruction of the packet. Remove the packet traversal code
because it can cause problems when the next packet has more than one
instruction.
Reviewed By: clayborg
Differential Revision: https://reviews.llvm.org/D84966
Summary:
The class has two pairs of functions whose functionalities differ in
only how one specifies how much he wants to disasseble. One limits the
process by the size of the input memory region. The other based on the
total amount of instructions disassembled. They also differ in various
features (like error reporting) that were only added to one of the
versions.
There are various ways in which this could be addressed. This patch
does it by introducing a helper struct called "Limit", which is
effectively a pair specifying the value that you want to limit, and the
actual limit itself.
Reviewers: JDevlieghere
Subscribers: sdardis, jrtc27, atanasyan, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D75730
The static Disassembler can be thought of as shorthands for three
operations:
- fetch an appropriate disassembler instance (FindPluginForTarget)
- ask it to dissassemble some bytes (ParseInstructions)
- ask it to dump the disassembled instructions (PrintInstructions)
The only thing that's standing in the way of this interpretation is that
the Disassemble function also does some address resolution before
calling ParseInstructions. This patch moves this functionality into
ParseInstructions so that it is available to users who call
ParseInstructions directly.