Skip to content

Commit 94a195e

Browse files
authored
Add support for encoding location lists (#22)
* WIP: Add support for encoding location lists * Emit relocations for location lists * Fix writing base address with relocations * Add diagnostics and implement ToString on the new objects
1 parent f192089 commit 94a195e

15 files changed

+503
-38
lines changed

src/LibObjectFile.Tests/Dwarf/DwarfTests.cs

+25
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,31 @@ public void CreateDwarf()
459459
};
460460
rootDIE.AddChild(subProgram);
461461

462+
var locationList = new DwarfLocationList();
463+
var regExpression = new DwarfExpression();
464+
regExpression.AddOperation(new DwarfOperation { Kind = DwarfOperationKindEx.Reg0 });
465+
var regExpression2 = new DwarfExpression();
466+
regExpression2.AddOperation(new DwarfOperation { Kind = DwarfOperationKindEx.Reg2 });
467+
locationList.AddLocationListEntry(new DwarfLocationListEntry
468+
{
469+
Start = 0,
470+
End = 0x10,
471+
Expression = regExpression,
472+
});
473+
locationList.AddLocationListEntry(new DwarfLocationListEntry
474+
{
475+
Start = 0x10,
476+
End = 0x20,
477+
Expression = regExpression2,
478+
});
479+
var variable = new DwarfDIEVariable()
480+
{
481+
Name = "a",
482+
Location = locationList,
483+
};
484+
dwarfFile.LocationSection.AddLocationList(locationList);
485+
subProgram.AddChild(variable);
486+
462487
var cu = new DwarfCompilationUnit()
463488
{
464489
AddressSize = DwarfAddressSize.Bit64,

src/LibObjectFile/DiagnosticId.cs

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public enum DiagnosticId
110110
DWARF_ERR_InvalidParentUnitForAddressRangeTable = 2017,
111111
DWARF_ERR_InvalidParentForDIE = 2018,
112112
DWARF_WRN_InvalidExtendedOpCodeLength = 2019,
113+
DWARF_ERR_InvalidParentForLocationList = 2020,
113114

114115
}
115116
}

src/LibObjectFile/Dwarf/DwarfAttribute.cs

+45-2
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,23 @@ public override void Verify(DiagnosticBag diagnostics)
8888

8989
if (thisSection != attrSection)
9090
{
91-
diagnostics.Error(DiagnosticId.DWARF_ERR_InvalidParentForDIE, $"Invalid parent for the DIE {attrDIE} referenced by the attribute {this}. It must be within the same parent {attrSection.GetType()}.");
91+
diagnostics.Error(DiagnosticId.DWARF_ERR_InvalidParentForDIE, $"Invalid parent for the DIE {attrDIE} referenced by the attribute {this}. It must be within the same parent {thisSection.GetType()}.");
9292
}
9393
}
9494
else if (ValueAsObject is DwarfExpression expr)
9595
{
9696
expr.Verify(diagnostics);
9797
}
98+
else if (ValueAsObject is DwarfLocationList locationList)
99+
{
100+
var thisSection = this.GetParentFile();
101+
var locationListSection = locationList.GetParentFile();
102+
103+
if (thisSection != locationListSection)
104+
{
105+
diagnostics.Error(DiagnosticId.DWARF_ERR_InvalidParentForLocationList, $"Invalid parent for the LocationList {locationList} referenced by the attribute {this}. It must be within the same parent {thisSection.GetType()}.");
106+
}
107+
}
98108
}
99109

100110
public int CompareTo(DwarfAttribute other)
@@ -323,6 +333,23 @@ private void ResolveAttributeValue(DwarfReader reader)
323333
break;
324334

325335
}
336+
337+
case DwarfAttributeKind.Location:
338+
{
339+
if (Form == DwarfAttributeFormEx.SecOffset)
340+
{
341+
if (reader.OffsetToLocationList.TryGetValue(ValueAsU64, out var locationList))
342+
{
343+
ValueAsU64 = 0;
344+
ValueAsObject = locationList;
345+
}
346+
else
347+
{
348+
// Log and error
349+
}
350+
}
351+
break;
352+
}
326353
}
327354
}
328355

@@ -600,6 +627,15 @@ private DwarfAttributeForm ComputeAttributeForm(DwarfLayoutContext context)
600627

601628
encoding = DwarfAttributeEncoding.ExpressionLocation;
602629
}
630+
else if (this.ValueAsObject is DwarfLocationList)
631+
{
632+
if ((encoding & DwarfAttributeEncoding.LocationList) == 0)
633+
{
634+
context.Diagnostics.Error(DiagnosticId.DWARF_ERR_InvalidData, $"The expression value of attribute {this} from DIE {this.Parent} is not valid for supported attribute encoding {encoding}. Expecting LocationList.");
635+
}
636+
637+
encoding = DwarfAttributeEncoding.LocationList;
638+
}
603639
else if ((encoding & DwarfAttributeEncoding.Address) != 0)
604640
{
605641
if (this.ValueAsObject != null)
@@ -896,7 +932,14 @@ protected override void Write(DwarfWriter writer)
896932
// stroffsetsptr
897933
case DwarfAttributeForm.SecOffset:
898934
{
899-
writer.WriteUIntFromEncoding(ValueAsU64);
935+
if (ValueAsObject != null)
936+
{
937+
writer.WriteUIntFromEncoding(((DwarfObject) ValueAsObject).Offset);
938+
}
939+
else
940+
{
941+
writer.WriteUIntFromEncoding(ValueAsU64);
942+
}
900943
break;
901944
}
902945

src/LibObjectFile/Dwarf/DwarfDIE.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ protected void SetAttributeLocationOpt(DwarfAttributeKind kind, DwarfLocation? c
247247
{
248248
var value = cst.Value;
249249
attr.ValueAsU64 = value.AsValue.U64;
250-
attr.ValueAsObject = value.AsExpression;
250+
attr.ValueAsObject = value.AsObject;
251251
}
252252
return;
253253
}
@@ -260,7 +260,7 @@ protected void SetAttributeLocationOpt(DwarfAttributeKind kind, DwarfLocation? c
260260
{
261261
Kind = kind,
262262
ValueAsU64 = value.AsValue.U64,
263-
ValueAsObject = value.AsExpression
263+
ValueAsObject = value.AsObject
264264
});
265265
}
266266
}

src/LibObjectFile/Dwarf/DwarfElfContext.cs

+48-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class DwarfElfContext
1717
private int _abbreviationTableSymbolIndex;
1818
private int _lineTableSymbolIndex;
1919
private int _stringTableSymbolIndex;
20+
private int _locationSectionSymbolIndex;
2021
private readonly ElfSymbolTable _symbolTable;
2122

2223
public DwarfElfContext(ElfObjectFile elf)
@@ -78,6 +79,10 @@ public DwarfElfContext(ElfObjectFile elf)
7879
LineTable = ((ElfBinarySection)section);
7980
mapSectionToSymbolIndex.TryGetValue(LineTable, out _lineTableSymbolIndex);
8081
break;
82+
case ".debug_loc":
83+
LocationSection = ((ElfBinarySection)section);
84+
mapSectionToSymbolIndex.TryGetValue(LocationSection, out _locationSectionSymbolIndex);
85+
break;
8186

8287
case ".rela.debug_aranges":
8388
case ".rel.debug_aranges":
@@ -96,6 +101,12 @@ public DwarfElfContext(ElfObjectFile elf)
96101
RelocInfoSection = (ElfRelocationTable)section;
97102
RelocInfoSection.Relocate(relocContext);
98103
break;
104+
105+
case ".rela.debug_loc":
106+
case ".rel.debug_loc":
107+
RelocLocationSection = (ElfRelocationTable)section;
108+
RelocLocationSection.Relocate(relocContext);
109+
break;
99110
}
100111
}
101112
}
@@ -119,9 +130,13 @@ public DwarfElfContext(ElfObjectFile elf)
119130
public ElfBinarySection StringTable { get; set; }
120131

121132
public ElfBinarySection LineTable { get; set; }
122-
133+
123134
public ElfRelocationTable RelocLineTable { get; set; }
124135

136+
public ElfBinarySection LocationSection { get; private set; }
137+
138+
public ElfRelocationTable RelocLocationSection { get; set; }
139+
125140
public int CodeSectionSymbolIndex => _codeSectionSymbolIndex;
126141

127142
public int InfoSectionSymbolIndex => _infoSectionSymbolIndex;
@@ -132,6 +147,8 @@ public DwarfElfContext(ElfObjectFile elf)
132147

133148
public int LineTableSymbolIndex => _lineTableSymbolIndex;
134149

150+
public int LocationSectionSymbolIndex => _locationSectionSymbolIndex;
151+
135152
public ElfBinarySection GetOrCreateInfoSection()
136153
{
137154
return InfoSection ??= GetOrCreateDebugSection(".debug_info", true, out _infoSectionSymbolIndex);
@@ -172,6 +189,16 @@ public ElfBinarySection GetOrCreateStringTable()
172189
return StringTable ??= GetOrCreateDebugSection(".debug_str", true, out _stringTableSymbolIndex);
173190
}
174191

192+
public ElfBinarySection GetOrCreateLocationSection()
193+
{
194+
return LocationSection ??= GetOrCreateDebugSection(".debug_loc", true, out _locationSectionSymbolIndex);
195+
}
196+
197+
public ElfRelocationTable GetOrCreateRelocLocationSection()
198+
{
199+
return RelocLocationSection ??= GetOrCreateRelocationTable(LocationSection);
200+
}
201+
175202
public void RemoveStringTable()
176203
{
177204
if (StringTable != null)
@@ -250,6 +277,26 @@ public void RemoveRelocInfoSection()
250277
}
251278
}
252279

280+
public void RemoveLocationSection()
281+
{
282+
if (LocationSection != null)
283+
{
284+
Elf.RemoveSection(LocationSection);
285+
LocationSection = null;
286+
}
287+
288+
RemoveRelocLocationSection();
289+
}
290+
291+
public void RemoveRelocLocationSection()
292+
{
293+
if (RelocLocationSection != null)
294+
{
295+
Elf.RemoveSection(RelocLocationSection);
296+
RelocLocationSection = null;
297+
}
298+
}
299+
253300
private ElfBinarySection GetOrCreateDebugSection(string name, bool createSymbol, out int symbolIndex)
254301
{
255302
var newSection = new ElfBinarySection()

src/LibObjectFile/Dwarf/DwarfExpression.cs

+50-26
Original file line numberDiff line numberDiff line change
@@ -51,32 +51,10 @@ public override void Verify(DiagnosticBag diagnostics)
5151
}
5252
}
5353

54-
protected override void UpdateLayout(DwarfLayoutContext layoutContext)
55-
{
56-
var endOffset = Offset;
57-
foreach (var op in _operations)
58-
{
59-
op.Offset = endOffset;
60-
op.UpdateLayoutInternal(layoutContext);
61-
endOffset += op.Size;
62-
}
63-
64-
OperationLengthInBytes = endOffset - Offset;
65-
66-
// We need to shift the expression which is prefixed by its size encoded in LEB128
67-
var deltaLength = DwarfHelper.SizeOfULEB128(Size);
68-
foreach (var op in InternalOperations)
69-
{
70-
op.Offset += deltaLength;
71-
}
72-
73-
Size = OperationLengthInBytes + deltaLength;
74-
}
75-
76-
protected override void Read(DwarfReader reader)
54+
internal void ReadInternal(DwarfReader reader, bool inLocationSection = false)
7755
{
7856
Offset = reader.Offset;
79-
var size = reader.ReadULEB128();
57+
var size = inLocationSection ? reader.ReadU16() : reader.ReadULEB128();
8058
OperationLengthInBytes = size;
8159
var endPosition = reader.Offset + size;
8260

@@ -90,12 +68,20 @@ protected override void Read(DwarfReader reader)
9068
Size = reader.Offset - Offset;
9169
}
9270

93-
protected override void Write(DwarfWriter writer)
71+
internal void WriteInternal(DwarfWriter writer, bool inLocationSection = false)
9472
{
9573
Debug.Assert(Offset == writer.Offset);
74+
Debug.Assert(!inLocationSection || OperationLengthInBytes <= ushort.MaxValue);
9675

9776
var startExpressionOffset = writer.Offset;
98-
writer.WriteULEB128(OperationLengthInBytes);
77+
if (inLocationSection)
78+
{
79+
writer.WriteU16((ushort)OperationLengthInBytes);
80+
}
81+
else
82+
{
83+
writer.WriteULEB128(OperationLengthInBytes);
84+
}
9985

10086
foreach (var op in Operations)
10187
{
@@ -104,5 +90,43 @@ protected override void Write(DwarfWriter writer)
10490

10591
Debug.Assert(writer.Offset - startExpressionOffset == Size);
10692
}
93+
94+
internal void UpdateLayoutInternal(DwarfLayoutContext layoutContext, bool inLocationSection = false)
95+
{
96+
var endOffset = Offset;
97+
foreach (var op in _operations)
98+
{
99+
op.Offset = endOffset;
100+
op.UpdateLayoutInternal(layoutContext);
101+
endOffset += op.Size;
102+
}
103+
104+
OperationLengthInBytes = endOffset - Offset;
105+
106+
// We need to shift the expression which is prefixed by its size encoded in LEB128,
107+
// or fixed-size U2 in .debug_loc section
108+
var deltaLength = inLocationSection ? sizeof(ushort) : DwarfHelper.SizeOfULEB128(Size);
109+
foreach (var op in InternalOperations)
110+
{
111+
op.Offset += deltaLength;
112+
}
113+
114+
Size = OperationLengthInBytes + deltaLength;
115+
}
116+
117+
protected override void UpdateLayout(DwarfLayoutContext layoutContext)
118+
{
119+
UpdateLayoutInternal(layoutContext, inLocationSection: false);
120+
}
121+
122+
protected override void Read(DwarfReader reader)
123+
{
124+
ReadInternal(reader, inLocationSection: false);
125+
}
126+
127+
protected override void Write(DwarfWriter writer)
128+
{
129+
WriteInternal(writer, inLocationSection: false);
130+
}
107131
}
108132
}

0 commit comments

Comments
 (0)