Skip to content

Commit f789e23

Browse files
Improved handling of C++ Builder map files.
Overlapping modules are now handling as a warning instead of a fatal error; The module is simply dropped. Fixes #12 Parsing of segment and module list has been made more strict to better detect errors. Bumped version.
1 parent 91d5412 commit f789e23

File tree

3 files changed

+108
-37
lines changed

3 files changed

+108
-37
lines changed

Source/debug.info.reader.map.pas

Lines changed: 92 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,18 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
341341
LineLogger.Error(Reader.LineNumber, 'Invalid integer number: "%s"', [Copy(s, Offset+1, MaxInt)]);
342342
end;
343343

344+
function RequiredPos(const SubStr, Str: string; Offset: integer; const ErrorMsg: string): integer; overload;
345+
begin
346+
Result := Pos(SubStr, Str, Offset);
347+
if (Result = 0) then
348+
LineLogger.Error(Reader.LineNumber, ErrorMsg+#13#10+Reader.LineBuffer);
349+
end;
350+
351+
function RequiredPos(const SubStr: string; Offset: integer; const ErrorMsg: string): integer; overload;
352+
begin
353+
Result := RequiredPos(SubStr, Reader.LineBuffer, Offset, ErrorMsg);
354+
end;
355+
344356
begin
345357
Logger.Info('Reading MAP file');
346358

@@ -362,22 +374,32 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
362374

363375
var LegacyMapFile := False;
364376

377+
// Delphi:
365378
// " 0001:00401000 000F47FCH .text CODE"
379+
// " 0001:0000000000301000 001FD57CH .text CODE"
380+
//
381+
// C++ Builder:
382+
// " 0001:00401000 000212EF0H _TEXT CODE"
366383
while (not Reader.CurrentLine.IsEmpty) do
367384
begin
368385
var n: integer := 0;
369386
var SegmentID: Cardinal := DecToInt32(Reader.LineBuffer, n);
370387

371-
n := Pos(':', Reader.LineBuffer, n+1);
388+
n := RequiredPos(':', n+1, 'Missing address/segment separator');
372389
var Offset: TDebugInfoOffset := HexToInt64(Reader.LineBuffer, n);
373390

374-
n := Pos(' ', Reader.LineBuffer, n+1);
391+
n := RequiredPos(' ', n+1, 'Missing address/segment delimiter');
375392
var Size: TDebugInfoOffset := HexToInt32(Reader.LineBuffer, n);
376393

377-
n := Pos('.', Reader.LineBuffer, n+1);
378-
var n2 := Pos(' ', Reader.LineBuffer, n+1);
379-
var Name := Copy(Reader.LineBuffer, n, n2-n);
380-
if (Name.IsEmpty) then
394+
var n2 := Pos('.', Reader.LineBuffer, n+1);
395+
if (n2 = 0) then
396+
n2 := Pos('_', Reader.LineBuffer, n+1);
397+
if (n2 = 0) then
398+
LineLogger.Error(Reader.LineNumber, 'Missing segment name'#13#10'%s', [Reader.LineBuffer]);
399+
n := n2;
400+
n2 := RequiredPos(' ', n+1, 'Missing segment delimiter');
401+
var SegmentName := Copy(Reader.LineBuffer, n, n2-n);
402+
if (SegmentName.IsEmpty) then
381403
LineLogger.Error(Reader.LineNumber, 'Invalid segment name'#13#10'%s', [Reader.LineBuffer]);
382404

383405
var ClassName := Copy(Reader.LineBuffer, n2+1, MaxInt).Trim;
@@ -398,29 +420,29 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
398420
if (ConflictingSegment <> nil) then
399421
begin
400422
LineLogger.Warning(Reader.LineNumber, 'Overlapping segments: %s [%.4X:%.16X] and %s [%.4X:%.16X]',
401-
[Name, SegmentID, Offset, ConflictingSegment.Name, ConflictingSegment.Index, ConflictingSegment.Offset]);
423+
[SegmentName, SegmentID, Offset, ConflictingSegment.Name, ConflictingSegment.Index, ConflictingSegment.Offset]);
402424
// Calculate a bogus offset so we can get on with it
403425
for var Segment in DebugInfo.Segments do
404426
Offset := Max(Offset, Segment.Offset + Segment.Size);
405427
// Align to $1000
406428
Offset := (Offset + $0FFF) and (not $0FFF);
407-
LineLogger.Warning(Reader.LineNumber, 'Calculated segment offset assigned: %s [%.4X:%.16X]', [Name, SegmentID, Offset]);
429+
LineLogger.Warning(Reader.LineNumber, 'Calculated segment offset assigned: %s [%.4X:%.16X]', [SegmentName, SegmentID, Offset]);
408430
end;
409431

410432
ConflictingSegment := DebugInfo.Segments.FindByIndex(SegmentID);
411433
if (ConflictingSegment <> nil) then
412434
begin
413435
LineLogger.Warning(Reader.LineNumber, 'Duplicate segment index: %s [%.4X:%.16X] and %s [%.4X:%.16X]',
414-
[Name, SegmentID, Offset, ConflictingSegment.Name, ConflictingSegment.Index, ConflictingSegment.Offset]);
436+
[SegmentName, SegmentID, Offset, ConflictingSegment.Name, ConflictingSegment.Index, ConflictingSegment.Offset]);
415437
// Calculate a bogus index
416438
for var Segment in DebugInfo.Segments do
417439
SegmentID := Max(SegmentID, Segment.Index+1);
418-
LineLogger.Warning(Reader.LineNumber, 'Calculated segment index assigned: %s [%.4X:%.16X]', [Name, SegmentID, Offset]);
440+
LineLogger.Warning(Reader.LineNumber, 'Calculated segment index assigned: %s [%.4X:%.16X]', [SegmentName, SegmentID, Offset]);
419441
end;
420442
end;
421443

422444
var SegmentClass := TDebugInfoSegment.GuessClassType(ClassName);
423-
var Segment := DebugInfo.Segments.Add(SegmentID, Name, SegmentClass);
445+
var Segment := DebugInfo.Segments.Add(SegmentID, SegmentName, SegmentClass);
424446

425447
Segment.Offset := Offset;
426448
Segment.Size := Size;
@@ -433,7 +455,7 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
433455
// "0005:00000000 OtlCommon.Utils.LastThreadName"
434456
// "0005:00000100 SysInit.TlsLast"
435457
if (Size = 0) then
436-
LineLogger.Warning(Reader.LineNumber, 'Empty segment: %s [%.4d:%.16X]', [Name, SegmentID, Segment.Offset]);
458+
LineLogger.Warning(Reader.LineNumber, 'Empty segment: %s [%.4d:%.16X]', [SegmentName, SegmentID, Segment.Offset]);
437459

438460
// Check for non-fatal overlapping segments (specifically .tls):
439461
// "0001:0000000000401000 006CD7B8H .text CODE"
@@ -462,25 +484,65 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
462484
if (Reader.NextLine(True).IsEmpty) then
463485
Exit;
464486

487+
// Delphi:
465488
// " 0001:00000000 0000F684 C=CODE S=.text G=(none) M=System ACBP=A9"
489+
// " 0001:00000000 0001640C C=CODE S=.text G=(none) M=System ALIGN=4"
490+
//
491+
// C++ Builder:
492+
// " 0001:000035F4 0000014D C=CODE S=_TEXT G=(none) M=C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\23.0\LIB\WIN32C\DEBUG\C0W32W.OBJ ACBP=A9"
493+
// " 0001:00003741 00000713 C=CODE S=_TEXT G=(none) M=C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\23.0\LIB\WIN32\DEBUG\RTL.BPI|Winapi.Windows.pas ACBP=A9"
466494
while (not Reader.CurrentLine.IsEmpty) do
467495
begin
468-
var n := Pos(' C=', Reader.LineBuffer);
469-
var ClassName := Copy(Reader.LineBuffer, n+2, Pos(' ', Reader.LineBuffer, n+2)-n-2);
496+
var n := RequiredPos(' C=', 1, 'Missing class name marker');
497+
var n2 := RequiredPos(' ', n+2, 'Missing segment type separator');
498+
var ClassName := Copy(Reader.LineBuffer, n+2, n2-n-2);
470499
var Address := Copy(Reader.LineBuffer, 1, n-1);
471500

472-
n := Pos('M=', Reader.LineBuffer);
473-
var Name := Copy(Reader.LineBuffer, n+2, Pos(' ', Reader.LineBuffer, n+2)-n-2);
501+
n := RequiredPos('M=', n+3, 'Missing module name marker');
502+
var StartOfName := n+2;
503+
// Find last ' ALIGN=' on line
504+
n2 := StartOfName;
505+
var EndOfName: integer;
506+
repeat
507+
EndOfName := n2;
508+
n2 := Pos(' ALIGN=', Reader.LineBuffer, n2+1);
509+
until (n2 = 0);
510+
// No "ALIGN"? Find last ' ACBP' on line instead
511+
if (EndOfName = StartOfName) then
512+
begin
513+
n2 := StartOfName;
514+
repeat
515+
EndOfName := n2;
516+
n2 := Pos(' ACBP=', Reader.LineBuffer, n2+1);
517+
until (n2 = 0);
518+
end;
519+
if (EndOfName = StartOfName) then
520+
LineLogger.Error(Reader.LineNumber, 'Missing module ALIGN/ACBP marker'#13#10'%s', [Reader.LineBuffer]);
521+
522+
// Trim trailing space
523+
while (EndOfName > StartOfName) and (Reader.LineBuffer[EndOfName] = ' ') do
524+
Dec(EndOfName);
525+
// Trim leading path
526+
n2 := EndOfName;
527+
n := StartOfName;
528+
while (n2 >= StartOfName) and (not CharInSet(Reader.LineBuffer[n2], ['\', '/', '|'])) do
529+
begin
530+
n := n2;
531+
Dec(n2);
532+
end;
533+
StartOfName := n;
534+
535+
var Name := Copy(Reader.LineBuffer, StartOfName, EndOfName-StartOfName+1);
474536
if (Name.IsEmpty) then
475537
LineLogger.Error(Reader.LineNumber, 'Invalid module name'#13#10'%s', [Reader.LineBuffer]);
476538

477539
n := 0;
478540
var SegmentID: Cardinal := DecToInt32(Address, n);
479541

480-
n := Pos(':', Address, n+1);
542+
n := RequiredPos(':', Address, n+1, 'Malformed module address');
481543
var Offset: TDebugInfoOffset := HexToInt64(Address, n);
482544

483-
n := Pos(' ', Address, n+1);
545+
n := RequiredPos(' ', Address, n+1, 'Missing module size separator');
484546
var Size: TDebugInfoOffset := HexToInt32(Address, n);
485547
if (Size = 0) then
486548
LineLogger.Error(Reader.LineNumber, 'Invalid module size'#13#10'%s', [Reader.LineBuffer]);
@@ -498,14 +560,15 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
498560

499561
// Look for existing module
500562
var Module := DebugInfo.Modules.FindOverlap(Segment, Offset, Size);
501-
if (Module <> nil) then
502-
LineLogger.Error(Reader.LineNumber, 'Modules overlap: %s, %s'#13#10'%s', [Module.Name, Name, Reader.LineBuffer]);
503-
504-
// Add new module
505-
if (Offset + Size <= Segment.Size) then
506-
DebugInfo.Modules.Add(Name, Segment, Offset, Size)
507-
else
508-
LineLogger.Warning(Reader.LineNumber, 'Module exceed segment bounds - ignored: %s [%.4d:%.16X+%d]', [Name, SegmentID, Offset, Size]);
563+
if (Module = nil) then
564+
begin
565+
// Add new module
566+
if (Offset + Size <= Segment.Size) then
567+
DebugInfo.Modules.Add(Name, Segment, Offset, Size)
568+
else
569+
LineLogger.Warning(Reader.LineNumber, 'Module exceed segment bounds - ignored: %s [%.4d:%.16X+%d]', [Name, SegmentID, Offset, Size]);
570+
end else
571+
LineLogger.Warning(Reader.LineNumber, 'Modules overlap: %s, %s'#13#10'%s', [Module.Name, Name, Reader.LineBuffer]);
509572

510573
Reader.NextLine;
511574
end;
@@ -610,19 +673,13 @@ procedure TDebugInfoMapReader.LoadFromStream(Stream: TStream; DebugInfo: TDebugI
610673
if (not Reader.HasData) then
611674
break;
612675

613-
var n := Pos('(', Reader.LineBuffer);
614-
if (n = 0) then
615-
LineLogger.Error(Reader.LineNumber, 'Source file start marker "(" not found'#13#10'%s', [Reader.LineBuffer]);
676+
var n := RequiredPos('(', 1, 'Source file start marker "(" not found');
616677
var ModuleName := Copy(Reader.LineBuffer, Length(sPrefix)+1, n-1-Length(sPrefix));
617678

618-
var n2 := Pos(')', Reader.LineBuffer, n+1);
619-
if (n2 = 0) then
620-
LineLogger.Error(Reader.LineNumber, 'Source file end marker ")" not found'#13#10'%s', [Reader.LineBuffer]);
679+
var n2 := RequiredPos(')', n+1, 'Source file end marker ")" not found');
621680
var Filename := Copy(Reader.LineBuffer, n+1, n2-n-1);
622681

623-
n := Pos('segment', Reader.LineBuffer, n2+1);
624-
if (n = 0) then
625-
LineLogger.Error(Reader.LineNumber, 'Source file segment marker "segment" not found'#13#10'%s', [Reader.LineBuffer]);
682+
n := RequiredPos('segment', n2+1, 'Source file segment marker "segment" not found');
626683
Inc(n, 7);
627684
while (Reader.LineBuffer[n] = ' ') do
628685
Inc(n);

Source/map2pdb.dproj

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@
5656
<Cfg_2>true</Cfg_2>
5757
<Base>true</Base>
5858
</PropertyGroup>
59+
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''">
60+
<Cfg_2_Win64>true</Cfg_2_Win64>
61+
<CfgParent>Cfg_2</CfgParent>
62+
<Cfg_2>true</Cfg_2>
63+
<Base>true</Base>
64+
</PropertyGroup>
5965
<PropertyGroup Condition="'$(Base)'!=''">
6066
<DCC_DcuOutput>..\Lib\$(Platform)\$(Config)</DCC_DcuOutput>
6167
<DCC_ExeOutput>..\Bin\$(Platform)\$(Config)</DCC_ExeOutput>
@@ -67,11 +73,11 @@
6773
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace>
6874
<SanitizedProjectName>map2pdb</SanitizedProjectName>
6975
<VerInfo_Locale>1033</VerInfo_Locale>
70-
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=3.2.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
76+
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=3.3.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
7177
<DCC_MapFile>3</DCC_MapFile>
7278
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
7379
<VerInfo_MajorVer>3</VerInfo_MajorVer>
74-
<VerInfo_MinorVer>2</VerInfo_MinorVer>
80+
<VerInfo_MinorVer>3</VerInfo_MinorVer>
7581
<VerInfo_AutoGenVersion>true</VerInfo_AutoGenVersion>
7682
</PropertyGroup>
7783
<PropertyGroup Condition="'$(Base_Android)'!=''">
@@ -116,6 +122,7 @@
116122
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
117123
<DCC_RangeChecking>true</DCC_RangeChecking>
118124
<DCC_UnitSearchPath>.\Externals\JEDI;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
125+
<DCC_Define>madExcept;$(DCC_Define)</DCC_Define>
119126
</PropertyGroup>
120127
<PropertyGroup Condition="'$(Cfg_2)'!=''">
121128
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
@@ -128,6 +135,13 @@
128135
<DCC_DebugInformation>2</DCC_DebugInformation>
129136
<DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols>
130137
<DCC_Define>madExcept;$(DCC_Define)</DCC_Define>
138+
<Debugger_RunParams>map2pdb.map -pause -v</Debugger_RunParams>
139+
</PropertyGroup>
140+
<PropertyGroup Condition="'$(Cfg_2_Win64)'!=''">
141+
<Debugger_RunParams>map2pdb.map -pause -v</Debugger_RunParams>
142+
<DCC_Define>madExcept;$(DCC_Define)</DCC_Define>
143+
<DCC_DebugInformation>2</DCC_DebugInformation>
144+
<DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols>
131145
</PropertyGroup>
132146
<ItemGroup>
133147
<DelphiCompile Include="$(MainSource)">

Source/map2pdb.res

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)