fpc/compiler/dbgcodeview.pas
2021-01-24 14:29:39 +00:00

284 lines
11 KiB
ObjectPascal

{
Copyright (c) 2018 by Nikolay Nikolov
This units contains support for Microsoft CodeView debug info generation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
{ documentation for the format, available on the internet:
earlier versions:
http://pagesperso-orange.fr/pierrelib/exec_formats/MS_Symbol_Type_v1.0.pdf
http://ftp.openwatcom.org/devel/docs/CodeView.pdf
modern versions:
https://llvm.org/docs/PDB/index.html
https://llvm.org/devmtg/2016-11/Slides/Kleckner-CodeViewInLLVM.pdf
}
unit dbgcodeview;
{$i fpcdefs.inc}
interface
uses
aasmdata,
dbgbase;
type
TSymbolIndex = (
S_COMPILE = $0001, { Compile flags symbol }
S_REGISTER = $0002, { Register variable }
S_CONSTANT = $0003, { Constant symbol }
S_UDT = $0004, { User-defined Type }
S_SSEARCH = $0005, { Start search }
S_END = $0006, { End block, procedure, with, or thunk }
S_SKIP = $0007, { Skip - Reserve symbol space }
S_CVRESERVE = $0008, { Reserved for internal use by the Microsoft debugger }
S_OBJNAME = $0009, { Specify name of object file }
S_ENDARG = $000a, { Specify end of arguments in function symbols }
S_COBOLUDT = $000b, { Microfocus COBOL user-defined type }
S_MANYREG = $000c, { Many register symbol }
S_RETURN = $000d, { Function return description }
S_ENTRYTHIS = $000e, { Description of this pointer at entry }
S_BPREL16 = $0100, { BP relative 16:16 }
S_LDATA16 = $0101, { Local data 16:16 }
S_GDATA16 = $0102, { Global data 16:16 }
S_PUB16 = $0103, { Public symbol 16:16 }
S_LPROC16 = $0104, { Local procedure start 16:16 }
S_GPROC16 = $0105, { Global procedure start 16:16 }
S_THUNK16 = $0106, { Thunk start 16:16 }
S_BLOCK16 = $0107, { Block start 16:16 }
S_WITH16 = $0108, { With start 16:16 }
S_LABEL16 = $0109, { Code label 16:16 }
S_CEXMODEL16 = $010a, { Change execution model 16:16 }
S_VFTPATH16 = $010b, { Virtual function table path descriptor 16:16 }
S_REGREL16 = $010c, { Specify 16:16 offset relative to arbitrary register }
S_BPREL32 = $0200, { BP relative 16:32 }
S_LDATA32 = $0201, { Local data 16:32 }
S_GDATA32 = $0202, { Global data 16:32 }
S_PUB32 = $0203, { Public symbol 16:32 }
S_LPROC32 = $0204, { Local procedure start 16:32 }
S_GPROC32 = $0205, { Global procedure start 16:32 }
S_THUNK32 = $0206, { Thunk start 16:32 }
S_BLOCK32 = $0207, { Block start 16:32 }
S_VFTPATH32 = $020b, { Virtual function table path descriptor 16:32 }
S_REGREL32 = $020c, { 16:32 offset relative to arbitrary register }
S_LTHREAD32 = $020d, { Local Thread Storage data }
S_GTHREAD32 = $020e, { Global Thread Storage data }
S_LPROCMIPS = $0300, { Local procedure start MIPS }
S_GPROCMIPS = $0301, { Global procedure start MIPS }
S_PROCREF = $0400, { Reference to a procedure }
S_DATAREF = $0401, { Reference to data }
S_ALIGN = $0402 { Page align symbols }
);
TLeafIndex=(
LF_MODIFIER = $0001, { Type Modifier (const, volatile, unaligned) }
LF_POINTER = $0002, { Pointer }
LF_ARRAY = $0003, { Simple Array }
LF_CLASS = $0004, { Class (C++ class declaration) }
LF_STRUCTURE = $0005, { Structure (C and C++ struct declaration) }
LF_UNION = $0006, { Union }
LF_ENUM = $0007, { Enumeration }
LF_PROCEDURE = $0008, { Procedure }
LF_MFUNCTION = $0009, { Member Function }
LF_VTSHAPE = $000a, { Virtual Function Table Shape }
LF_COBOL0 = $000b, { reserved for Microfocus COBOL }
LF_COBOL1 = $000c, { reserved for Microfocus COBOL }
LF_BARRAY = $000d, { Basic Array }
LF_LABEL = $000e, { Label }
LF_NULL = $000f, { Null }
LF_NOTTRAN = $0010, { Not Translated }
LF_DIMARRAY = $0011, { Multiply Dimensioned Array }
LF_VFTPATH = $0012, { Path to Virtual Function Table }
LF_PRECOMP = $0013, { Reference Precompiled Types }
LF_ENDPRECOMP = $0014, { End of Precompiled Types }
LF_OEM = $0015, { OEM Generic Type }
LF_Reserved = $0016, { Reserved }
LF_PAD0 = $f0,
LF_PAD1 = $f1,
LF_PAD2 = $f2,
LF_PAD3 = $f3,
LF_PAD4 = $f4,
LF_PAD5 = $f5,
LF_PAD6 = $f6,
LF_PAD7 = $f7,
LF_PAD8 = $f8,
LF_PAD9 = $f9,
LF_PAD10 = $fa,
LF_PAD11 = $fb,
LF_PAD12 = $fc,
LF_PAD13 = $fd,
LF_PAD14 = $fe,
LF_PAD15 = $ff,
LF_SKIP = $0200, { Skip (used by incremental compilers to reserve space for future indexes) }
LF_ARGLIST = $0201, { Argument List }
LF_DEFARG = $0202, { Default Argument }
LF_LIST = $0203, { Arbitrary List }
LF_FIELDLIST = $0204, { Field List }
LF_DERIVED = $0205, { Derived Classes }
LF_BITFIELD = $0206, { Bit Fields }
LF_METHODLIST = $0207, { Method List }
LF_DIMCONU = $0208, { Dimensioned Array with Constant Upper Bound }
LF_DIMCONLU = $0209, { Dimensioned Array with Constant Lower and Upper Bounds }
LF_DIMVARU = $020a, { Dimensioned Array with Variable Upper Bound }
LF_DIMVARLU = $020b, { Dimensioned Array with Variable Lower and Upper Bounds }
LF_REFSYM = $020c, { Referenced Symbol }
LF_BCLASS = $0400, { Real Base Class }
LF_VBCLASS = $0401, { Direct Virtual Base Class }
LF_IVBCLASS = $0402, { Indirect Virtual Base Class }
LF_ENUMERATE = $0403, { Enumeration Name and Value }
LF_FRIENDFCN = $0404, { Friend Function }
LF_INDEX = $0405, { Index to Another Type Record }
LF_MEMBER = $0406, { Data Member }
LF_STMEMBER = $0407, { Static Data Member }
LF_METHOD = $0408, { Method }
LF_NESTTYPE = $0409, { Nested Type Definition }
LF_VFUNCTAB = $040a, { Virtual Function Table Pointer }
LF_FRIENDCLS = $040b, { Friend Class }
LF_ONEMETHOD = $040c, { One Method }
LF_VFUNCOFF = $040d, { Virtual Function Offset }
LF_CHAR = $8000, { Signed Char (8-bit value) }
LF_SHORT = $8001, { Signed Short (16-bit signed value) }
LF_USHORT = $8002, { Unsigned Short (16-bit unsigned value) }
LF_LONG = $8003, { Signed Long (32-bit signed value) }
LF_ULONG = $8004, { Unsigned Long (32-bit unsigned value) }
LF_REAL32 = $8005, { 32-bit Float }
LF_REAL64 = $8006, { 64-bit Float }
LF_REAL80 = $8007, { 80-bit Float }
LF_REAL128 = $8008, { 128-bit Float }
LF_QUADWORD = $8009, { Signed Quad Word (64-bit signed value) }
LF_UQUADWORD = $800a, { Unsigned Quad Word (64-bit unsigned value) }
LF_REAL48 = $800b, { 48-bit Float }
LF_COMPLEX32 = $800c, { 32-bit Complex }
LF_COMPLEX64 = $800d, { 64-bit Complex }
LF_COMPLEX80 = $800e, { 80-bit Complex }
LF_COMPLEX128 = $800f, { 128-bit Complex }
LF_VARSTRING = $8010 { Variable-length String }
);
const
LF_NUMERIC = LF_CHAR;
type
{ TDebugInfoCodeView }
TDebugInfoCodeView = class(TDebugInfo)
public
procedure insertlineinfo(list:TAsmList);override;
end;
procedure InsertLineInfo_OMF_LINNUM_MsLink(list: TAsmList);
implementation
uses
globtype,
cutils,
aasmtai,
fmodule,
systems;
procedure InsertLineInfo_OMF_LINNUM_MsLink(list: TAsmList);
var
currfileinfo,
lastfileinfo : tfileposinfo;
nolineinfolevel : Integer;
currfuncname : pshortstring;
hp : tai;
begin
FillChar(lastfileinfo,sizeof(lastfileinfo),0);
hp:=Tai(list.first);
nolineinfolevel:=0;
while assigned(hp) do
begin
case hp.typ of
ait_function_name :
begin
currfuncname:=tai_function_name(hp).funcname;
list.concat(tai_comment.Create(strpnew('function: '+currfuncname^)));
end;
ait_force_line :
begin
lastfileinfo.line:=-1;
end;
ait_marker :
begin
case tai_marker(hp).kind of
mark_NoLineInfoStart:
inc(nolineinfolevel);
mark_NoLineInfoEnd:
dec(nolineinfolevel);
else
;
end;
end;
else
;
end;
{ OMF LINNUM records do not support multiple source files }
if (hp.typ=ait_instruction) and
(nolineinfolevel=0) and
(tailineinfo(hp).fileinfo.fileindex=main_module.unit_index) then
begin
currfileinfo:=tailineinfo(hp).fileinfo;
{ line changed ? }
if (lastfileinfo.line<>currfileinfo.line) and (currfileinfo.line<>0) then
begin
{ line directive }
list.insertbefore(tai_directive.Create(asd_omf_linnum_line,tostr(currfileinfo.line)),hp);
end;
lastfileinfo:=currfileinfo;
end;
hp:=tai(hp.next);
end;
end;
{****************************************************************************
TDebugInfoCodeView
****************************************************************************}
procedure TDebugInfoCodeView.insertlineinfo(list: TAsmList);
begin
InsertLineInfo_OMF_LINNUM_MsLink(list);
end;
{****************************************************************************
****************************************************************************}
const
dbg_codeview_info : tdbginfo =
(
id : dbg_codeview;
idtxt : 'CODEVIEW';
);
initialization
RegisterDebugInfo(dbg_codeview_info,TDebugInfoCodeView);
end.