1 {
2     Copyright (c) 2018 by Nikolay Nikolov
3 
4     This units contains support for Microsoft CodeView debug info generation
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 { documentation for the format, available on the internet:
23 
24   earlier versions:
25     http://pagesperso-orange.fr/pierrelib/exec_formats/MS_Symbol_Type_v1.0.pdf
26     http://ftp.openwatcom.org/devel/docs/CodeView.pdf
27 
28   modern versions:
29     https://llvm.org/docs/PDB/index.html
30     https://llvm.org/devmtg/2016-11/Slides/Kleckner-CodeViewInLLVM.pdf
31 }
32 
33 unit dbgcodeview;
34 
35 {$i fpcdefs.inc}
36 
37 interface
38 
39     uses
40       aasmdata,
41       dbgbase;
42 
43     type
44       TSymbolIndex = (
45         S_COMPILE    = $0001, { Compile flags symbol }
46         S_REGISTER   = $0002, { Register variable }
47         S_CONSTANT   = $0003, { Constant symbol }
48         S_UDT        = $0004, { User-defined Type }
49         S_SSEARCH    = $0005, { Start search }
50         S_END        = $0006, { End block, procedure, with, or thunk }
51         S_SKIP       = $0007, { Skip - Reserve symbol space }
52         S_CVRESERVE  = $0008, { Reserved for internal use by the Microsoft debugger }
53         S_OBJNAME    = $0009, { Specify name of object file }
54         S_ENDARG     = $000a, { Specify end of arguments in function symbols }
55         S_COBOLUDT   = $000b, { Microfocus COBOL user-defined type }
56         S_MANYREG    = $000c, { Many register symbol }
57         S_RETURN     = $000d, { Function return description }
58         S_ENTRYTHIS  = $000e, { Description of this pointer at entry }
59         S_BPREL16    = $0100, { BP relative 16:16 }
60         S_LDATA16    = $0101, { Local data 16:16 }
61         S_GDATA16    = $0102, { Global data 16:16 }
62         S_PUB16      = $0103, { Public symbol 16:16 }
63         S_LPROC16    = $0104, { Local procedure start 16:16 }
64         S_GPROC16    = $0105, { Global procedure start 16:16 }
65         S_THUNK16    = $0106, { Thunk start 16:16 }
66         S_BLOCK16    = $0107, { Block start 16:16 }
67         S_WITH16     = $0108, { With start 16:16 }
68         S_LABEL16    = $0109, { Code label 16:16 }
69         S_CEXMODEL16 = $010a, { Change execution model 16:16 }
70         S_VFTPATH16  = $010b, { Virtual function table path descriptor 16:16 }
71         S_REGREL16   = $010c, { Specify 16:16 offset relative to arbitrary register }
72         S_BPREL32    = $0200, { BP relative 16:32 }
73         S_LDATA32    = $0201, { Local data 16:32 }
74         S_GDATA32    = $0202, { Global data 16:32 }
75         S_PUB32      = $0203, { Public symbol 16:32 }
76         S_LPROC32    = $0204, { Local procedure start 16:32 }
77         S_GPROC32    = $0205, { Global procedure start 16:32 }
78         S_THUNK32    = $0206, { Thunk start 16:32 }
79         S_BLOCK32    = $0207, { Block start 16:32 }
80         S_VFTPATH32  = $020b, { Virtual function table path descriptor 16:32 }
81         S_REGREL32   = $020c, { 16:32 offset relative to arbitrary register }
82         S_LTHREAD32  = $020d, { Local Thread Storage data }
83         S_GTHREAD32  = $020e, { Global Thread Storage data }
84         S_LPROCMIPS  = $0300, { Local procedure start MIPS }
85         S_GPROCMIPS  = $0301, { Global procedure start MIPS }
86         S_PROCREF    = $0400, { Reference to a procedure }
87         S_DATAREF    = $0401, { Reference to data }
88         S_ALIGN      = $0402  { Page align symbols }
89       );
90       TLeafIndex=(
91         LF_MODIFIER   = $0001, { Type Modifier (const, volatile, unaligned) }
92         LF_POINTER    = $0002, { Pointer }
93         LF_ARRAY      = $0003, { Simple Array }
94         LF_CLASS      = $0004, { Class (C++ class declaration) }
95         LF_STRUCTURE  = $0005, { Structure (C and C++ struct declaration) }
96         LF_UNION      = $0006, { Union }
97         LF_ENUM       = $0007, { Enumeration }
98         LF_PROCEDURE  = $0008, { Procedure }
99         LF_MFUNCTION  = $0009, { Member Function }
100         LF_VTSHAPE    = $000a, { Virtual Function Table Shape }
101         LF_COBOL0     = $000b, { reserved for Microfocus COBOL }
102         LF_COBOL1     = $000c, { reserved for Microfocus COBOL }
103         LF_BARRAY     = $000d, { Basic Array }
104         LF_LABEL      = $000e, { Label }
105         LF_NULL       = $000f, { Null }
106         LF_NOTTRAN    = $0010, { Not Translated }
107         LF_DIMARRAY   = $0011, { Multiply Dimensioned Array }
108         LF_VFTPATH    = $0012, { Path to Virtual Function Table }
109         LF_PRECOMP    = $0013, { Reference Precompiled Types }
110         LF_ENDPRECOMP = $0014, { End of Precompiled Types }
111         LF_OEM        = $0015, { OEM Generic Type }
112         LF_Reserved   = $0016, { Reserved }
113 
114         LF_PAD0       = $f0,
115         LF_PAD1       = $f1,
116         LF_PAD2       = $f2,
117         LF_PAD3       = $f3,
118         LF_PAD4       = $f4,
119         LF_PAD5       = $f5,
120         LF_PAD6       = $f6,
121         LF_PAD7       = $f7,
122         LF_PAD8       = $f8,
123         LF_PAD9       = $f9,
124         LF_PAD10      = $fa,
125         LF_PAD11      = $fb,
126         LF_PAD12      = $fc,
127         LF_PAD13      = $fc,
128         LF_PAD14      = $fe,
129         LF_PAD15      = $ff,
130 
131         LF_SKIP       = $0200, { Skip (used by incremental compilers to reserve space for future indexes) }
132         LF_ARGLIST    = $0201, { Argument List }
133         LF_DEFARG     = $0202, { Default Argument }
134         LF_LIST       = $0203, { Arbitrary List }
135         LF_FIELDLIST  = $0204, { Field List }
136         LF_DERIVED    = $0205, { Derived Classes }
137         LF_BITFIELD   = $0206, { Bit Fields }
138         LF_METHODLIST = $0207, { Method List }
139         LF_DIMCONU    = $0208, { Dimensioned Array with Constant Upper Bound }
140         LF_DIMCONLU   = $0209, { Dimensioned Array with Constant Lower and Upper Bounds }
141         LF_DIMVARU    = $020a, { Dimensioned Array with Variable Upper Bound }
142         LF_DIMVARLU   = $020b, { Dimensioned Array with Variable Lower and Upper Bounds }
143         LF_REFSYM     = $020c, { Referenced Symbol }
144 
145         LF_BCLASS     = $0400, { Real Base Class }
146         LF_VBCLASS    = $0401, { Direct Virtual Base Class }
147         LF_IVBCLASS   = $0402, { Indirect Virtual Base Class }
148         LF_ENUMERATE  = $0403, { Enumeration Name and Value }
149         LF_FRIENDFCN  = $0404, { Friend Function }
150         LF_INDEX      = $0405, { Index to Another Type Record }
151         LF_MEMBER     = $0406, { Data Member }
152         LF_STMEMBER   = $0407, { Static Data Member }
153         LF_METHOD     = $0408, { Method }
154         LF_NESTTYPE   = $0409, { Nested Type Definition }
155         LF_VFUNCTAB   = $040a, { Virtual Function Table Pointer }
156         LF_FRIENDCLS  = $040b, { Friend Class }
157         LF_ONEMETHOD  = $040c, { One Method }
158         LF_VFUNCOFF   = $040d, { Virtual Function Offset }
159 
160         LF_CHAR       = $8000, { Signed Char (8-bit value) }
161         LF_SHORT      = $8001, { Signed Short (16-bit signed value) }
162         LF_USHORT     = $8002, { Unsigned Short (16-bit unsigned value) }
163         LF_LONG       = $8003, { Signed Long (32-bit signed value) }
164         LF_ULONG      = $8004, { Unsigned Long (32-bit unsigned value) }
165         LF_REAL32     = $8005, { 32-bit Float }
166         LF_REAL64     = $8006, { 64-bit Float }
167         LF_REAL80     = $8007, { 80-bit Float }
168         LF_REAL128    = $8008, { 128-bit Float }
169         LF_QUADWORD   = $8009, { Signed Quad Word (64-bit signed value) }
170         LF_UQUADWORD  = $800a, { Unsigned Quad Word (64-bit unsigned value) }
171         LF_REAL48     = $800b, { 48-bit Float }
172         LF_COMPLEX32  = $800c, { 32-bit Complex }
173         LF_COMPLEX64  = $800d, { 64-bit Complex }
174         LF_COMPLEX80  = $800e, { 80-bit Complex }
175         LF_COMPLEX128 = $800f, { 128-bit Complex }
176         LF_VARSTRING  = $8010  { Variable-length String }
177       );
178 
179     const
180       LF_NUMERIC = LF_CHAR;
181 
182     type
183 
184       { TDebugInfoCodeView }
185 
186       TDebugInfoCodeView = class(TDebugInfo)
187       public
188         procedure insertlineinfo(list:TAsmList);override;
189       end;
190 
191     procedure InsertLineInfo_OMF_LINNUM_MsLink(list: TAsmList);
192 
193 implementation
194 
195     uses
196       globtype,
197       cutils,
198       aasmtai,
199       fmodule,
200       systems;
201 
202     procedure InsertLineInfo_OMF_LINNUM_MsLink(list: TAsmList);
203       var
204         currfileinfo,
205         lastfileinfo : tfileposinfo;
206         nolineinfolevel : Integer;
207         currfuncname : pshortstring;
208         hp : tai;
209       begin
210         FillChar(lastfileinfo,sizeof(lastfileinfo),0);
211         hp:=Tai(list.first);
212         nolineinfolevel:=0;
213         while assigned(hp) do
214           begin
215             case hp.typ of
216               ait_function_name :
217                 begin
218                   currfuncname:=tai_function_name(hp).funcname;
219                   list.concat(tai_comment.Create(strpnew('function: '+currfuncname^)));
220                 end;
221               ait_force_line :
222                 begin
223                   lastfileinfo.line:=-1;
224                 end;
225               ait_marker :
226                 begin
227                   case tai_marker(hp).kind of
228                     mark_NoLineInfoStart:
229                       inc(nolineinfolevel);
230                     mark_NoLineInfoEnd:
231                       dec(nolineinfolevel);
232                   end;
233                 end;
234             end;
235 
236             { OMF LINNUM records do not support multiple source files }
237             if (hp.typ=ait_instruction) and
238                (nolineinfolevel=0) and
239                (tailineinfo(hp).fileinfo.fileindex=main_module.unit_index) then
240               begin
241                 currfileinfo:=tailineinfo(hp).fileinfo;
242 
243                 { line changed ? }
244                 if (lastfileinfo.line<>currfileinfo.line) and (currfileinfo.line<>0) then
245                   begin
246                     { line directive }
247                     list.insertbefore(tai_directive.Create(asd_omf_linnum_line,tostr(currfileinfo.line)),hp);
248                   end;
249                 lastfileinfo:=currfileinfo;
250               end;
251 
252             hp:=tai(hp.next);
253           end;
254       end;
255 
256 
257 {****************************************************************************
258                              TDebugInfoCodeView
259 ****************************************************************************}
260 
261     procedure TDebugInfoCodeView.insertlineinfo(list: TAsmList);
262       begin
263         InsertLineInfo_OMF_LINNUM_MsLink(list);
264       end;
265 
266 {****************************************************************************
267 ****************************************************************************}
268     const
269       dbg_codeview_info : tdbginfo =
270          (
271            id     : dbg_codeview;
272            idtxt  : 'CODEVIEW';
273          );
274 
275 initialization
276   RegisterDebugInfo(dbg_codeview_info,TDebugInfoCodeView);
277 
278 end.
279 
280