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