[LLVM][CodeView] Add S_REGREL32_INDIR (#183172)
This adds `RegRelativeIndirSym` (`S_REGREL32_INDIR`) as a record, so we can emit and dump it (#34392). It encodes a variable at the location `*($Register+ Offset) + OffsetInUdt` and is used by MSVC in C++ 20 coroutines and C++ 17 structured bindings. Clang also needs this for coroutines (for `__promise` which has the location `DW_OP_deref, DW_OP_plus_uconst, 16`). For example: ```cpp struct Foo { int a, b; }; void fn() { Foo f = {1, 2}; // ╰─ S_REGREL32{ reg = rsp, offset = 0 } auto &[x, y] = f; // │ ╰─ S_REGREL32_INDIR{ reg = rsp, offset = 8, offset-in-udt = 4, type = int } // ╰─ S_REGREL32_INDIR{ reg = rsp, offset = 8, offset-in-udt = 0, type = int } } ``` The `S_REGREL32_INDIR` for `y` from above looks like this: ``` │ 08000000 │ 74000000 │ 04000000 │ 4F01 │ 7900 │ │ Offset │ Type │ OffInUdt │ Reg. │ Name │ ``` I prototyped support for this in LLDB's native PDB parser to check the assumption about the location (in a followup PR). I was wrong in #182743, thinking that the location was just `$Register + Offset + OffsetInUdt`. That could've been encoded as a `S_REGREL32`. Presumably, `S_BPREL32_INDIR` works similar, but I can't get MSVC to generate this.
This commit is contained in:
parent
5e887716b0
commit
cacf225ff3
@ -247,6 +247,42 @@ S_FASTLINK (0x1167)
|
||||
S_INLINEES (0x1168)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
S_REGREL32_INDIR (0x1171)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This encodes a variable at the location ``*($Register + Offset) + OffsetInUdt``.
|
||||
It's equivalent to the following DWARF location expression:
|
||||
|
||||
.. code::
|
||||
|
||||
DW_OP_breg{corresponding DWARF register} {Offset}
|
||||
DW_OP_deref
|
||||
DW_OP_plus_uconst {OffsetInUdt}
|
||||
|
||||
It's used in C++ 17 structured bindings for example:
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
struct Foo { int a, b; };
|
||||
|
||||
void fn() {
|
||||
Foo f = {1, 2};
|
||||
// ╰─ S_REGREL32{ reg = rsp, offset = 0 }
|
||||
auto &[x, y] = f;
|
||||
// │ ╰─ S_REGREL32_INDIR{ reg = rsp, offset = 8, offset-in-udt = 4, type = int }
|
||||
// ╰─ S_REGREL32_INDIR{ reg = rsp, offset = 8, offset-in-udt = 0, type = int }
|
||||
}
|
||||
|
||||
The ``S_REGREL32_INDIR`` symbol for ``y`` from above looks like this:
|
||||
|
||||
|
||||
============ ============ ============ ======== ========
|
||||
Offset Type OffsetInUdt Register Name
|
||||
============ ============ ============ ======== ========
|
||||
``08000000`` ``74000000`` ``04000000`` ``4F01`` ``7900``
|
||||
8 int 4 RSP "a"
|
||||
============ ============ ============ ======== ========
|
||||
|
||||
.. _module_and_global_symbols:
|
||||
|
||||
Symbols which can go in either/both of the module info stream & global stream
|
||||
|
||||
@ -185,7 +185,7 @@ CV_SYMBOL(S_FASTLINK, 0x1167) // Undocumented (also known to as S_REF_MINIPDB2)
|
||||
SYMBOL_RECORD_ALIAS(S_INLINEES, 0x1168, InlineesSym, CallerSym) // Undocumented
|
||||
|
||||
CV_SYMBOL(S_BPREL32_INDIR, 0x1170)
|
||||
CV_SYMBOL(S_REGREL32_INDIR, 0x1171)
|
||||
SYMBOL_RECORD(S_REGREL32_INDIR, 0x1171, RegRelativeIndirSym)
|
||||
CV_SYMBOL(S_GPROC32EX, 0x1172)
|
||||
CV_SYMBOL(S_LPROC32EX, 0x1173)
|
||||
CV_SYMBOL(S_GPROC32EX_ID, 0x1174)
|
||||
|
||||
@ -949,6 +949,26 @@ public:
|
||||
uint32_t RecordOffset = 0;
|
||||
};
|
||||
|
||||
/// S_REGREL32_INDIR
|
||||
///
|
||||
/// \p Name is located at `*($Register + Offset) + OffsetInUDT` with type
|
||||
/// \p Type.
|
||||
class RegRelativeIndirSym : public SymbolRecord {
|
||||
public:
|
||||
explicit RegRelativeIndirSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
|
||||
explicit RegRelativeIndirSym(uint32_t RecordOffset)
|
||||
: SymbolRecord(SymbolRecordKind::RegRelativeIndirSym),
|
||||
RecordOffset(RecordOffset) {}
|
||||
|
||||
uint32_t Offset = 0;
|
||||
TypeIndex Type;
|
||||
uint32_t OffsetInUdt = 0;
|
||||
RegisterId Register;
|
||||
StringRef Name;
|
||||
|
||||
uint32_t RecordOffset = 0;
|
||||
};
|
||||
|
||||
// S_CONSTANT, S_MANCONSTANT
|
||||
class ConstantSym : public SymbolRecord {
|
||||
public:
|
||||
|
||||
@ -220,6 +220,7 @@ public:
|
||||
Error visitKnownRecord(CVSymbol &Record, ObjNameSym &ObjName) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, ProcSym &Proc) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, RegRelativeSym &Local) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, RegRelativeIndirSym &Local) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, ScopeEndSym &ScopeEnd) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) override;
|
||||
Error visitKnownRecord(CVSymbol &Record, UDTSym &UDT) override;
|
||||
|
||||
@ -278,8 +278,9 @@ static int getSymbolNameOffset(CVSymbol Sym) {
|
||||
// See SectionSym
|
||||
case SymbolKind::S_SECTION:
|
||||
return 16;
|
||||
// See CoffGroupSym
|
||||
// See CoffGroupSym, RegRelativeIndirSym
|
||||
case SymbolKind::S_COFFGROUP:
|
||||
case SymbolKind::S_REGREL32_INDIR:
|
||||
return 14;
|
||||
// See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
|
||||
case SymbolKind::S_PUB32:
|
||||
|
||||
@ -620,6 +620,17 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
RegRelativeIndirSym &RegRelIndir) {
|
||||
W.printHex("Offset", RegRelIndir.Offset);
|
||||
printTypeIndex("Type", RegRelIndir.Type);
|
||||
W.printEnum("Register", uint16_t(RegRelIndir.Register),
|
||||
getRegisterNames(CompilationCPUType));
|
||||
W.printHex("OffsetInUdt", RegRelIndir.OffsetInUdt);
|
||||
W.printString("VarName", RegRelIndir.Name);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
ThreadLocalDataSym &Data) {
|
||||
StringRef LinkageName;
|
||||
|
||||
@ -444,6 +444,17 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
|
||||
RegRelativeIndirSym &RegRelIndir) {
|
||||
error(IO.mapInteger(RegRelIndir.Offset));
|
||||
error(IO.mapInteger(RegRelIndir.Type));
|
||||
error(IO.mapInteger(RegRelIndir.OffsetInUdt));
|
||||
error(IO.mapEnum(RegRelIndir.Register));
|
||||
error(IO.mapStringZ(RegRelIndir.Name));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
|
||||
ThreadLocalDataSym &Data) {
|
||||
|
||||
|
||||
@ -402,6 +402,7 @@ static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
|
||||
break;
|
||||
case SymbolKind::S_BPREL32:
|
||||
case SymbolKind::S_REGREL32:
|
||||
case SymbolKind::S_REGREL32_INDIR:
|
||||
Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
|
||||
break;
|
||||
case SymbolKind::S_CALLSITEINFO:
|
||||
|
||||
@ -906,6 +906,57 @@ Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// S_REGREL32_INDIR
|
||||
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
|
||||
RegRelativeIndirSym &Local) {
|
||||
LLVM_DEBUG({
|
||||
printTypeIndex("Type", Local.Type);
|
||||
W.printNumber("Offset", Local.Offset);
|
||||
W.printNumber("OffsetInUdt", Local.OffsetInUdt);
|
||||
W.printString("VarName", Local.Name);
|
||||
});
|
||||
|
||||
if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) {
|
||||
Symbol->setName(Local.Name);
|
||||
|
||||
// Symbol was created as 'variable'; determine its real kind.
|
||||
Symbol->resetIsVariable();
|
||||
|
||||
// Check for the 'this' symbol.
|
||||
if (Local.Name == "this") {
|
||||
Symbol->setIsArtificial();
|
||||
Symbol->setIsParameter();
|
||||
} else {
|
||||
// Determine symbol kind.
|
||||
determineSymbolKind(Symbol, Local.Register);
|
||||
}
|
||||
|
||||
// Update correct debug information tag.
|
||||
if (Symbol->getIsParameter())
|
||||
Symbol->setTag(dwarf::DW_TAG_formal_parameter);
|
||||
|
||||
LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type);
|
||||
if (Element && Element->getIsScoped()) {
|
||||
// We have a local type. Find its parent function.
|
||||
LVScope *Parent = Symbol->getFunctionParent();
|
||||
// The element representing the type has been already finalized. If
|
||||
// the type is an aggregate type, its members have been already added.
|
||||
// As the type is local, its level will be changed.
|
||||
|
||||
// FIXME: Currently the algorithm used to scope lambda functions is
|
||||
// incorrect. Before we allocate the type at this scope, check if is
|
||||
// already allocated in other scope.
|
||||
if (!Element->getParentScope()) {
|
||||
Parent->addElement(Element);
|
||||
Element->updateLevel(Parent);
|
||||
}
|
||||
}
|
||||
Symbol->setType(Element);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
// S_BUILDINFO
|
||||
Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR,
|
||||
BuildInfoSym &BuildInfo) {
|
||||
@ -3079,6 +3130,7 @@ LVElement *LVLogicalVisitor::createElement(SymbolKind Kind) {
|
||||
|
||||
case SymbolKind::S_BPREL32:
|
||||
case SymbolKind::S_REGREL32:
|
||||
case SymbolKind::S_REGREL32_INDIR:
|
||||
case SymbolKind::S_GDATA32:
|
||||
case SymbolKind::S_LDATA32:
|
||||
case SymbolKind::S_LOCAL:
|
||||
|
||||
@ -555,6 +555,14 @@ template <> void SymbolRecordImpl<RegRelativeSym>::map(IO &IO) {
|
||||
IO.mapRequired("VarName", Symbol.Name);
|
||||
}
|
||||
|
||||
template <> void SymbolRecordImpl<RegRelativeIndirSym>::map(IO &IO) {
|
||||
IO.mapRequired("Offset", Symbol.Offset);
|
||||
IO.mapRequired("Type", Symbol.Type);
|
||||
IO.mapRequired("Register", Symbol.Register);
|
||||
IO.mapRequired("OffsetInUdt", Symbol.OffsetInUdt);
|
||||
IO.mapRequired("VarName", Symbol.Name);
|
||||
}
|
||||
|
||||
template <> void SymbolRecordImpl<ConstantSym>::map(IO &IO) {
|
||||
IO.mapRequired("Type", Symbol.Type);
|
||||
IO.mapRequired("Value", Symbol.Value);
|
||||
|
||||
@ -18,4 +18,11 @@ DbiStream:
|
||||
Type: 4494
|
||||
Register: RSP
|
||||
VarName: this
|
||||
- Kind: S_REGREL32_INDIR
|
||||
RegRelativeIndirSym:
|
||||
Offset: 64
|
||||
Type: 116
|
||||
Register: RSP
|
||||
OffsetInUdt: 4
|
||||
VarName: a
|
||||
...
|
||||
|
||||
@ -9,6 +9,8 @@ CHECK_YAML2PDB: ============================================================
|
||||
CHECK_YAML2PDB: Mod 0000 | `/tmp/test.obj`:
|
||||
CHECK_YAML2PDB: 4 | S_REGREL32 [size = 20] `this`
|
||||
CHECK_YAML2PDB: type = 0x118E (<unknown UDT>), register = RSP, offset = 56
|
||||
CHECK_YAML2PDB: 24 | S_REGREL32_INDIR [size = 20] `a`
|
||||
CHECK_YAML2PDB: type = 0x0074 (int), register = RSP, offset = 64, offset-in-udt = 4
|
||||
|
||||
CHECK_PDB2YAML: - Kind: S_REGREL32
|
||||
CHECK_PDB2YAML: RegRelativeSym:
|
||||
@ -16,3 +18,10 @@ CHECK_PDB2YAML: Offset: 56
|
||||
CHECK_PDB2YAML: Type: 4494
|
||||
CHECK_PDB2YAML: Register: RSP
|
||||
CHECK_PDB2YAML: VarName: this
|
||||
CHECK_PDB2YAML: - Kind: S_REGREL32_INDIR
|
||||
CHECK_PDB2YAML: RegRelativeIndirSym:
|
||||
CHECK_PDB2YAML: Offset: 64
|
||||
CHECK_PDB2YAML: Type: 116
|
||||
CHECK_PDB2YAML: Register: RSP
|
||||
CHECK_PDB2YAML: OffsetInUdt: 4
|
||||
CHECK_PDB2YAML: VarName: a
|
||||
|
||||
@ -920,6 +920,17 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
RegRelativeIndirSym &RegRelIndir) {
|
||||
P.format(" `{0}`", RegRelIndir.Name);
|
||||
AutoIndent Indent(P, 7);
|
||||
P.formatLine("type = {0}, register = {1}, offset = {2}, offset-in-udt = {3}",
|
||||
typeIndex(RegRelIndir.Type),
|
||||
formatRegisterId(RegRelIndir.Register, CompilationCPU),
|
||||
RegRelIndir.Offset, RegRelIndir.OffsetInUdt);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
ThreadLocalDataSym &Data) {
|
||||
P.format(" `{0}`", Data.Name);
|
||||
|
||||
@ -606,3 +606,10 @@ TEST_F(TypeIndexIteratorTest, UsingNamespace) {
|
||||
writeSymbolRecords(UN);
|
||||
checkTypeReferences(0);
|
||||
}
|
||||
|
||||
TEST_F(TypeIndexIteratorTest, RegRelativeIndir) {
|
||||
RegRelativeIndirSym RR(SymbolRecordKind::RegRelativeIndirSym);
|
||||
RR.Type = TypeIndex::Int32();
|
||||
writeSymbolRecords(RR);
|
||||
checkTypeReferences(0, RR.Type);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user