forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change-Id: I7987a7bb8c9f5efadab3abc4bbe3133914ce6a00
- Loading branch information
Showing
93 changed files
with
1,202 additions
and
2,119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
# Adding Programming Language Support | ||
|
||
LLDB has been architected to make it straightforward to add support for a | ||
programming language. Only a small enum in core LLDB needs to be modified to | ||
make LLDB aware of a new programming language. Everything else can be supplied | ||
in derived classes that need not even be present in the core LLDB repository. | ||
This makes it convenient for developers adding language support in downstream | ||
repositories since it practically eliminates the potential for merge conflicts. | ||
|
||
The basic steps are: | ||
* Add the language to the `LanguageType` enum. | ||
* Add a `TypeSystem` for the language. | ||
* Add expression evaluation support. | ||
|
||
Additionally, you may want to create a `Language` and `LanguageRuntime` plugin | ||
for your language, which enables support for advanced features like dynamic | ||
typing and data formatting. | ||
|
||
## Add the Language to the LanguageType enum | ||
|
||
The `LanguageType` enum | ||
(see [lldb-enumerations.h](https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/lldb-enumerations.h)) | ||
contains a list of every language known to LLDB. It is the one place where | ||
support for a language must live that will need to merge cleanly with upstream | ||
LLDB if you are developing your language support in a separate branch. When | ||
adding support for a language previously unknown to LLDB, start by adding an | ||
enumeration entry to `LanguageType`. | ||
|
||
## Add a TypeSystem for the Language | ||
|
||
Both [Module](https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Core/Module.h) | ||
and [Target](https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Target/Target.h) | ||
support the retrieval of a `TypeSystem` instance via `GetTypeSystemForLanguage()`. | ||
For `Module`, this method is directly on the `Module` instance. For `Target`, | ||
this is retrieved indirectly via the `TypeSystemMap` for the `Target` instance. | ||
|
||
The `TypeSystem` instance returned by the `Target` is expected to be capable of | ||
evaluating expressions, while the `TypeSystem` instance returned by the `Module` | ||
is not. If you want to support expression evaluation for your language, you could | ||
consider one of the following approaches: | ||
* Implement a single `TypeSystem` class that supports evaluation when given an | ||
optional `Target`, implementing all the expression evaluation methods on the | ||
`TypeSystem`. | ||
* Create multiple `TypeSystem` classes, one for evaluation and one for static | ||
`Module` usage. | ||
|
||
For clang and Swift, the latter approach was chosen. Primarily to make it | ||
clearer that evaluation with the static `Module`-returned `TypeSystem` instances | ||
make no sense, and have them error out on those calls. But either approach is | ||
fine. | ||
|
||
# Creating Types | ||
|
||
Your `TypeSystem` will need an approach for creating types based on a set of | ||
`Module`s. If your type info is going to come from DWARF info, you will want to | ||
subclass [DWARFASTParser](https://github.com/llvm/llvm-project/blob/main/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h). | ||
|
||
|
||
# Add Expression Evaluation Support | ||
|
||
Expression Evaluation support is enabled by implementing the relevant methods on | ||
a `TypeSystem`-derived class. Search for `Expression` in the | ||
[TypeSystem header](https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Symbol/TypeSystem.h) | ||
to find the methods to implement. | ||
|
||
# Type Completion | ||
|
||
There are three levels of type completion, each requiring more type information: | ||
1. Pointer size: When you have a forward decl or a reference, and that's all you | ||
need. At this stage, the pointer size is all you need. | ||
2. Layout info: You need the size of an instance of the type, but you still don't | ||
need to know all the guts of the type. | ||
3. Full type info: Here you need everything, because you're playing with | ||
internals of it, such as modifying a member variable. | ||
|
||
Ensure you never complete more of a type than is needed for a given situation. | ||
This will keep your type system from doing more work than necessary. | ||
|
||
# Language and LanguageRuntime Plugins | ||
|
||
If you followed the steps outlined above, you already have taught LLDB a great | ||
deal about your language. If your language's runtime model and fundamental data | ||
types don't differ much from the C model, you are pretty much done. | ||
|
||
However it is likely that your language offers its own data types for things | ||
like strings and arrays, and probably has a notion of dynamic types, where the | ||
effective type of a variable can only be known at runtime. | ||
|
||
These tasks are covered by two plugins: | ||
* a `LanguageRuntime` plugin, which provides LLDB with a dynamic view of your | ||
language; this plugin answers questions that require a live process to acquire | ||
information (for example dynamic type resolution). | ||
* a `Language` plugin, which provides LLDB with a static view of your language; | ||
questions that are statically knowable and do not require a process are | ||
answered by this plugin (for example data formatters). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
lldb/test/API/functionalities/gdb_remote_client/TestAArch64XMLRegistersSVEOnly.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
""" Check that when a debug server provides XML that only defines SVE Z registers, | ||
and does not include Neon V registers, lldb creates sub-registers to represent | ||
the V registers as the bottom 128 bits of the Z registers. | ||
qemu-aarch64 is one such debug server. | ||
This also doubles as a test that lldb has a fallback path for registers of | ||
unknown type that are > 128 bits, as the SVE registers are here. | ||
""" | ||
|
||
from textwrap import dedent | ||
import lldb | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test.decorators import * | ||
from lldbsuite.test.gdbclientutils import * | ||
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase | ||
|
||
|
||
class Responder(MockGDBServerResponder): | ||
def __init__(self): | ||
super().__init__() | ||
self.vg = 4 | ||
self.pc = 0xA0A0A0A0A0A0A0A0 | ||
|
||
def qXferRead(self, obj, annex, offset, length): | ||
if annex == "target.xml": | ||
# Note that QEMU sends the current SVE size in XML and the debugger | ||
# then reads vg to know the latest size. | ||
return ( | ||
dedent( | ||
"""\ | ||
<?xml version="1.0"?> | ||
<target version="1.0"> | ||
<architecture>aarch64</architecture> | ||
<feature name="org.gnu.gdb.aarch64.core"> | ||
<reg name="pc" regnum="0" bitsize="64"/> | ||
<reg name="vg" regnum="1" bitsize="64"/> | ||
<reg name="z0" regnum="2" bitsize="2048" type="not_a_type"/> | ||
</feature> | ||
</target>""" | ||
), | ||
False, | ||
) | ||
|
||
return (None,) | ||
|
||
def readRegister(self, regnum): | ||
return "E01" | ||
|
||
def readRegisters(self): | ||
return "".join( | ||
[ | ||
# 64 bit PC. | ||
f"{self.pc:x}", | ||
# 64 bit vg | ||
f"0{self.vg}00000000000000", | ||
# Enough data for 256 and 512 bit SVE. | ||
"".join([f"{n:02x}" * 4 for n in range(1, 17)]), | ||
] | ||
) | ||
|
||
def cont(self): | ||
# vg is expedited so that lldb can resize the SVE registers. | ||
return f"T02thread:1ff0d;threads:1ff0d;thread-pcs:{self.pc};01:0{self.vg}00000000000000;" | ||
|
||
def writeRegisters(self, registers_hex): | ||
# We get a block of data containing values in regnum order. | ||
self.vg = int(registers_hex[16:18]) | ||
return "OK" | ||
|
||
|
||
class TestXMLRegisterFlags(GDBRemoteTestBase): | ||
def check_regs(self, vg): | ||
# Each 32 bit chunk repeats n. | ||
z0_value = " ".join( | ||
[" ".join([f"0x{n:02x}"] * 4) for n in range(1, (vg * 2) + 1)] | ||
) | ||
|
||
self.expect( | ||
"register read vg z0 v0 s0 d0", | ||
substrs=[ | ||
f" vg = 0x000000000000000{vg}\n" | ||
" z0 = {" + z0_value + "}\n" | ||
" v0 = {0x01 0x01 0x01 0x01 0x02 0x02 0x02 0x02 0x03 0x03 0x03 0x03 0x04 0x04 0x04 0x04}\n" | ||
" s0 = 2.36942783E-38\n" | ||
" d0 = 5.3779407333977203E-299\n" | ||
], | ||
) | ||
|
||
self.expect("register read s0 --format uint32", substrs=["s0 = {0x01010101}"]) | ||
self.expect( | ||
"register read d0 --format uint64", | ||
substrs=["d0 = {0x0202020201010101}"], | ||
) | ||
|
||
@skipIfXmlSupportMissing | ||
@skipIfRemote | ||
@skipIfLLVMTargetMissing("AArch64") | ||
def test_v_sub_registers(self): | ||
self.server.responder = Responder() | ||
target = self.dbg.CreateTarget("") | ||
|
||
if self.TraceOn(): | ||
self.runCmd("log enable gdb-remote packets") | ||
self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets")) | ||
|
||
process = self.connect(target) | ||
lldbutil.expect_state_changes( | ||
self, self.dbg.GetListener(), process, [lldb.eStateStopped] | ||
) | ||
|
||
self.check_regs(4) | ||
|
||
# Now increase the SVE length and continue. The mock will respond with a new | ||
# vg and lldb will reconfigure the register defs. This should not break the | ||
# sub-registers. | ||
|
||
self.runCmd("register write vg 8") | ||
self.expect("continue", substrs=["stop reason = signal SIGINT"]) | ||
|
||
self.check_regs(8) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.