JclTD32.pas 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762
  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is JclTD32.pas. }
  14. { }
  15. { The Initial Developer of the Original Code is Flier Lu (<flier_lu att yahoo dott com dott cn>). }
  16. { Portions created by Flier Lu are Copyright (C) Flier Lu. All Rights Reserved. }
  17. { }
  18. { Contributors: }
  19. { Flier Lu (flier) }
  20. { Olivier Sannier (obones) }
  21. { Petr Vones (pvones) }
  22. { Heinz Zastrau (heinzz) }
  23. { Andreas Hausladen (ahuser) }
  24. { }
  25. {**************************************************************************************************}
  26. { }
  27. { Borland TD32 symbolic debugging information support routines and classes. }
  28. { }
  29. {**************************************************************************************************}
  30. { }
  31. { Last modified: $Date:: $ }
  32. { Revision: $Rev:: $ }
  33. { Author: $Author:: $ }
  34. { }
  35. {**************************************************************************************************}
  36. unit JclTD32;
  37. interface
  38. {$I jcl.inc}
  39. {$I windowsonly.inc}
  40. uses
  41. {$IFDEF UNITVERSIONING}
  42. JclUnitVersioning,
  43. {$ENDIF UNITVERSIONING}
  44. {$IFDEF HAS_UNITSCOPE}
  45. {$IFDEF MSWINDOWS}
  46. Winapi.Windows,
  47. {$ENDIF MSWINDOWS}
  48. System.Classes, System.SysUtils, System.Contnrs,
  49. {$ELSE ~HAS_UNITSCOPE}
  50. {$IFDEF MSWINDOWS}
  51. Windows,
  52. {$ENDIF MSWINDOWS}
  53. Classes, SysUtils, Contnrs,
  54. {$ENDIF ~HAS_UNITSCOPE}
  55. JclBase,
  56. {$IFDEF BORLAND}
  57. JclPeImage,
  58. {$ENDIF BORLAND}
  59. JclFileUtils;
  60. { TODO -cDOC : Original code: "Flier Lu" <flier_lu att yahoo dott com dott cn> }
  61. // TD32 constants and structures
  62. {*******************************************************************************
  63. [-----------------------------------------------------------------------]
  64. [ Symbol and Type OMF Format Borland Executable Files ]
  65. [-----------------------------------------------------------------------]
  66. Introduction
  67. This section describes the format used to embed debugging information into
  68. the executable file.
  69. Debug Information Format
  70. The format encompasses a block of data which goes at the end of the .EXE
  71. file, i.e., after the header plus load image, overlays, and
  72. Windows/Presentation Manager resource compiler information. The lower
  73. portion of the file is unaffected by the additional data.
  74. The last eight bytes of the file contain a signature and a long file offset
  75. from the end of the file (lfoBase). The signature is FBxx, where xx is the
  76. version number. The long offset indicates the position in the file
  77. (relative to the end of the file) of the base address. For the LX format
  78. executables, the base address is determined by looking at the executable
  79. header.
  80. The signatures have the following meanings:
  81. FB09 The signature for a Borland 32 bit symbol file.
  82. The value
  83. lfaBase=length of the file - lfoBase
  84. gives the base address of the start of the Symbol and Type OMF information
  85. relative to the beginning of the file. All other file offsets in the
  86. Symbol and Type OMF are relative to the lfaBase. At the base address the
  87. signature is repeated, followed by the long displacement to the subsection
  88. directory (lfoDir). All subsections start on a long word boundary and are
  89. designed to maintain natural alignment internally in each subsection and
  90. within the subsection directory.
  91. Subsection Directory
  92. The subsection directory has the format
  93. Directory header
  94. Directory entry 0
  95. Directory entry 1
  96. .
  97. .
  98. .
  99. Directory entry n
  100. There is no requirement for a particular subsection of a particular module to exist.
  101. The following is the layout of the FB09 debug information in the image:
  102. FB09 Header
  103. sstModule [1]
  104. .
  105. .
  106. .
  107. sstModule [n]
  108. sstAlignSym [1]
  109. sstSrcModule [1]
  110. .
  111. .
  112. .
  113. sstAlignSym [n]
  114. sstSrcModule [n]
  115. sstGlobalSym
  116. sstGlobalTypes
  117. sstNames
  118. SubSection Directory
  119. FB09 Trailer
  120. *******************************************************************************}
  121. const
  122. Borland32BitSymbolFileSignatureForDelphi = $39304246; // 'FB09'
  123. Borland32BitSymbolFileSignatureForBCB = $41304246; // 'FB0A'
  124. type
  125. { Signature structure }
  126. PJclTD32FileSignature = ^TJclTD32FileSignature;
  127. TJclTD32FileSignature = packed record
  128. Signature: DWORD;
  129. Offset: DWORD;
  130. end;
  131. const
  132. { Subsection Types }
  133. SUBSECTION_TYPE_MODULE = $120;
  134. SUBSECTION_TYPE_TYPES = $121;
  135. SUBSECTION_TYPE_SYMBOLS = $124;
  136. SUBSECTION_TYPE_ALIGN_SYMBOLS = $125;
  137. SUBSECTION_TYPE_SOURCE_MODULE = $127;
  138. SUBSECTION_TYPE_GLOBAL_SYMBOLS = $129;
  139. SUBSECTION_TYPE_GLOBAL_TYPES = $12B;
  140. SUBSECTION_TYPE_NAMES = $130;
  141. type
  142. { Subsection directory header structure }
  143. { The directory header structure is followed by the directory entries
  144. which specify the subsection type, module index, file offset, and size.
  145. The subsection directory gives the location (LFO) and size of each subsection,
  146. as well as its type and module number if applicable. }
  147. PDirectoryEntry = ^TDirectoryEntry;
  148. TDirectoryEntry = packed record
  149. SubsectionType: Word; // Subdirectory type
  150. ModuleIndex: Word; // Module index
  151. Offset: DWORD; // Offset from the base offset lfoBase
  152. Size: DWORD; // Number of bytes in subsection
  153. end;
  154. { The subsection directory is prefixed with a directory header structure
  155. indicating size and number of subsection directory entries that follow. }
  156. PDirectoryHeader = ^TDirectoryHeader;
  157. TDirectoryHeader = packed record
  158. Size: Word; // Length of this structure
  159. DirEntrySize: Word; // Length of each directory entry
  160. DirEntryCount: DWORD; // Number of directory entries
  161. lfoNextDir: DWORD; // Offset from lfoBase of next directory.
  162. Flags: DWORD; // Flags describing directory and subsection tables.
  163. DirEntries: array [0..0] of TDirectoryEntry;
  164. end;
  165. {*******************************************************************************
  166. SUBSECTION_TYPE_MODULE $120
  167. This describes the basic information about an object module including code
  168. segments, module name, and the number of segments for the modules that
  169. follow. Directory entries for sstModules precede all other subsection
  170. directory entries.
  171. *******************************************************************************}
  172. type
  173. PSegmentInfo = ^TSegmentInfo;
  174. TSegmentInfo = packed record
  175. Segment: Word; // Segment that this structure describes
  176. Flags: Word; // Attributes for the logical segment.
  177. // The following attributes are defined:
  178. // $0000 Data segment
  179. // $0001 Code segment
  180. Offset: DWORD; // Offset in segment where the code starts
  181. Size: DWORD; // Count of the number of bytes of code in the segment
  182. end;
  183. PSegmentInfoArray = ^TSegmentInfoArray;
  184. TSegmentInfoArray = array [0..32767] of TSegmentInfo;
  185. PModuleInfo = ^TModuleInfo;
  186. TModuleInfo = packed record
  187. OverlayNumber: Word; // Overlay number
  188. LibraryIndex: Word; // Index into sstLibraries subsection
  189. // if this module was linked from a library
  190. SegmentCount: Word; // Count of the number of code segments
  191. // this module contributes to
  192. DebuggingStyle: Word; // Debugging style for this module.
  193. NameIndex: DWORD; // Name index of module.
  194. TimeStamp: DWORD; // Time stamp from the OBJ file.
  195. Reserved: array [0..2] of DWORD; // Set to 0.
  196. Segments: array [0..0] of TSegmentInfo;
  197. // Detailed information about each segment
  198. // that code is contributed to.
  199. // This is an array of cSeg count segment
  200. // information descriptor structures.
  201. end;
  202. {*******************************************************************************
  203. SUBSECTION_TYPE_SOURCE_MODULE $0127
  204. This table describes the source line number to addressing mapping
  205. information for a module. The table permits the description of a module
  206. containing multiple source files with each source file contributing code to
  207. one or more code segments. The base addresses of the tables described
  208. below are all relative to the beginning of the sstSrcModule table.
  209. Module header
  210. Information for source file 1
  211. Information for segment 1
  212. .
  213. .
  214. .
  215. Information for segment n
  216. .
  217. .
  218. .
  219. Information for source file n
  220. Information for segment 1
  221. .
  222. .
  223. .
  224. Information for segment n
  225. *******************************************************************************}
  226. type
  227. { The line number to address mapping information is contained in a table with
  228. the following format: }
  229. PLineMappingEntry = ^TLineMappingEntry;
  230. TLineMappingEntry = packed record
  231. SegmentIndex: Word; // Segment index for this table
  232. PairCount: Word; // Count of the number of source line pairs to follow
  233. Offsets: array [0..0] of DWORD;
  234. // An array of 32-bit offsets for the offset
  235. // within the code segment ofthe start of ine contained
  236. // in the parallel array linenumber.
  237. (*
  238. { This is an array of 16-bit line numbers of the lines in the source file
  239. that cause code to be emitted to the code segment.
  240. This array is parallel to the offset array.
  241. If cPair is not even, then a zero word is emitted to
  242. maintain natural alignment in the sstSrcModule table. }
  243. LineNumbers: array [0..PairCount - 1] of Word;
  244. *)
  245. end;
  246. TOffsetPair = packed record
  247. StartOffset: DWORD;
  248. EndOffset: DWORD;
  249. end;
  250. POffsetPairArray = ^TOffsetPairArray;
  251. TOffsetPairArray = array [0..32767] of TOffsetPair;
  252. { The file table describes the code segments that receive code from this
  253. source file. Source file entries have the following format: }
  254. PSourceFileEntry = ^TSourceFileEntry;
  255. TSourceFileEntry = packed record
  256. SegmentCount: Word; // Number of segments that receive code from this source file.
  257. NameIndex: DWORD; // Name index of Source file name.
  258. BaseSrcLines: array [0..0] of DWORD;
  259. // An array of offsets for the line/address mapping
  260. // tables for each of the segments that receive code
  261. // from this source file.
  262. (*
  263. { An array of two 32-bit offsets per segment that
  264. receives code from this module. The first offset
  265. is the offset within the segment of the first byte
  266. of code from this module. The second offset is the
  267. ending address of the code from this module. The
  268. order of these pairs corresponds to the ordering of
  269. the segments in the seg array. Zeros in these
  270. entries means that the information is not known and
  271. the file and line tables described below need to be
  272. examined to determine if an address of interest is
  273. contained within the code from this module. }
  274. SegmentAddress: array [0..SegmentCount - 1] of TOffsetPair;
  275. Name: ShortString; // Count of the number of bytes in source file name
  276. *)
  277. end;
  278. { The module header structure describes the source file and code segment
  279. organization of the module. Each module header has the following format: }
  280. PSourceModuleInfo = ^TSourceModuleInfo;
  281. TSourceModuleInfo = packed record
  282. FileCount: Word; // The number of source file scontributing code to segments
  283. SegmentCount: Word; // The number of code segments receiving code from this module
  284. BaseSrcFiles: array [0..0] of DWORD;
  285. (*
  286. // This is an array of base offsets from the beginning of the sstSrcModule table
  287. BaseSrcFiles: array [0..FileCount - 1] of DWORD;
  288. { An array of two 32-bit offsets per segment that
  289. receives code from this module. The first offset
  290. is the offset within the segment of the first byte
  291. of code from this module. The second offset is the
  292. ending address of the code from this module. The
  293. order of these pairs corresponds to the ordering of
  294. the segments in the seg array. Zeros in these
  295. entries means that the information is not known and
  296. the file and line tables described below need to be
  297. examined to determine if an address of interest is
  298. contained within the code from this module. }
  299. SegmentAddress: array [0..SegmentCount - 1] of TOffsetPair;
  300. { An array of segment indices that receive code from
  301. this module. If the number of segments is not
  302. even, a pad word is inserted to maintain natural
  303. alignment. }
  304. SegmentIndexes: array [0..SegmentCount - 1] of Word;
  305. *)
  306. end;
  307. {*******************************************************************************
  308. SUBSECTION_TYPE_GLOBAL_TYPES $12b
  309. This subsection contains the packed type records for the executable file.
  310. The first long word of the subsection contains the number of types in the
  311. table. This count is followed by a count-sized array of long offsets to
  312. the corresponding type record. As the sstGlobalTypes subsection is
  313. written, each type record is forced to start on a long word boundary.
  314. However, the length of the type string is NOT adjusted by the pad count.
  315. The remainder of the subsection contains the type records.
  316. *******************************************************************************}
  317. type
  318. PGlobalTypeInfo = ^TGlobalTypeInfo;
  319. TGlobalTypeInfo = packed record
  320. Count: DWORD; // count of the number of types
  321. // offset of each type string from the beginning of table
  322. Offsets: array [0..0] of DWORD;
  323. end;
  324. const
  325. { Symbol type defines }
  326. SYMBOL_TYPE_COMPILE = $0001; // Compile flags symbol
  327. SYMBOL_TYPE_REGISTER = $0002; // Register variable
  328. SYMBOL_TYPE_CONST = $0003; // Constant symbol
  329. SYMBOL_TYPE_UDT = $0004; // User-defined Type
  330. SYMBOL_TYPE_SSEARCH = $0005; // Start search
  331. SYMBOL_TYPE_END = $0006; // End block, procedure, with, or thunk
  332. SYMBOL_TYPE_SKIP = $0007; // Skip - Reserve symbol space
  333. SYMBOL_TYPE_CVRESERVE = $0008; // Reserved for Code View internal use
  334. SYMBOL_TYPE_OBJNAME = $0009; // Specify name of object file
  335. SYMBOL_TYPE_BPREL16 = $0100; // BP relative 16:16
  336. SYMBOL_TYPE_LDATA16 = $0101; // Local data 16:16
  337. SYMBOL_TYPE_GDATA16 = $0102; // Global data 16:16
  338. SYMBOL_TYPE_PUB16 = $0103; // Public symbol 16:16
  339. SYMBOL_TYPE_LPROC16 = $0104; // Local procedure start 16:16
  340. SYMBOL_TYPE_GPROC16 = $0105; // Global procedure start 16:16
  341. SYMBOL_TYPE_THUNK16 = $0106; // Thunk start 16:16
  342. SYMBOL_TYPE_BLOCK16 = $0107; // Block start 16:16
  343. SYMBOL_TYPE_WITH16 = $0108; // With start 16:16
  344. SYMBOL_TYPE_LABEL16 = $0109; // Code label 16:16
  345. SYMBOL_TYPE_CEXMODEL16 = $010A; // Change execution model 16:16
  346. SYMBOL_TYPE_VFTPATH16 = $010B; // Virtual function table path descriptor 16:16
  347. SYMBOL_TYPE_BPREL32 = $0200; // BP relative 16:32
  348. SYMBOL_TYPE_LDATA32 = $0201; // Local data 16:32
  349. SYMBOL_TYPE_GDATA32 = $0202; // Global data 16:32
  350. SYMBOL_TYPE_PUB32 = $0203; // Public symbol 16:32
  351. SYMBOL_TYPE_LPROC32 = $0204; // Local procedure start 16:32
  352. SYMBOL_TYPE_GPROC32 = $0205; // Global procedure start 16:32
  353. SYMBOL_TYPE_THUNK32 = $0206; // Thunk start 16:32
  354. SYMBOL_TYPE_BLOCK32 = $0207; // Block start 16:32
  355. SYMBOL_TYPE_WITH32 = $0208; // With start 16:32
  356. SYMBOL_TYPE_LABEL32 = $0209; // Label 16:32
  357. SYMBOL_TYPE_CEXMODEL32 = $020A; // Change execution model 16:32
  358. SYMBOL_TYPE_VFTPATH32 = $020B; // Virtual function table path descriptor 16:32
  359. {*******************************************************************************
  360. Global and Local Procedure Start 16:32
  361. SYMBOL_TYPE_LPROC32 $0204
  362. SYMBOL_TYPE_GPROC32 $0205
  363. The symbol records define local (file static) and global procedure
  364. definition. For C/C++, functions that are declared static to a module are
  365. emitted as Local Procedure symbols. Functions not specifically declared
  366. static are emitted as Global Procedures.
  367. For each SYMBOL_TYPE_GPROC32 emitted, an SYMBOL_TYPE_GPROCREF symbol
  368. must be fabricated and emitted to the SUBSECTION_TYPE_GLOBAL_SYMBOLS section.
  369. *******************************************************************************}
  370. type
  371. TSymbolProcInfo = packed record
  372. pParent: DWORD;
  373. pEnd: DWORD;
  374. pNext: DWORD;
  375. Size: DWORD; // Length in bytes of this procedure
  376. DebugStart: DWORD; // Offset in bytes from the start of the procedure to
  377. // the point where the stack frame has been set up.
  378. DebugEnd: DWORD; // Offset in bytes from the start of the procedure to
  379. // the point where the procedure is ready to return
  380. // and has calculated its return value, if any.
  381. // Frame and register variables an still be viewed.
  382. Offset: DWORD; // Offset portion of the segmented address of
  383. // the start of the procedure in the code segment
  384. Segment: Word; // Segment portion of the segmented address of
  385. // the start of the procedure in the code segment
  386. ProcType: DWORD; // Type of the procedure type record
  387. NearFar: Byte; // Type of return the procedure makes:
  388. // 0 near
  389. // 4 far
  390. Reserved: Byte;
  391. NameIndex: DWORD; // Name index of procedure
  392. end;
  393. TSymbolObjNameInfo = packed record
  394. Signature: DWORD; // Signature for the CodeView information contained in
  395. // this module
  396. NameIndex: DWORD; // Name index of the object file
  397. end;
  398. TSymbolDataInfo = packed record
  399. Offset: DWORD; // Offset portion of the segmented address of
  400. // the start of the data in the code segment
  401. Segment: Word; // Segment portion of the segmented address of
  402. // the start of the data in the code segment
  403. Reserved: Word;
  404. TypeIndex: DWORD; // Type index of the symbol
  405. NameIndex: DWORD; // Name index of the symbol
  406. end;
  407. TSymbolWithInfo = packed record
  408. pParent: DWORD;
  409. pEnd: DWORD;
  410. Size: DWORD; // Length in bytes of this "with"
  411. Offset: DWORD; // Offset portion of the segmented address of
  412. // the start of the "with" in the code segment
  413. Segment: Word; // Segment portion of the segmented address of
  414. // the start of the "with" in the code segment
  415. Reserved: Word;
  416. NameIndex: DWORD; // Name index of the "with"
  417. end;
  418. TSymbolLabelInfo = packed record
  419. Offset: DWORD; // Offset portion of the segmented address of
  420. // the start of the label in the code segment
  421. Segment: Word; // Segment portion of the segmented address of
  422. // the start of the label in the code segment
  423. NearFar: Byte; // Address mode of the label:
  424. // 0 near
  425. // 4 far
  426. Reserved: Byte;
  427. NameIndex: DWORD; // Name index of the label
  428. end;
  429. TSymbolConstantInfo = packed record
  430. TypeIndex: DWORD; // Type index of the constant (for enums)
  431. NameIndex: DWORD; // Name index of the constant
  432. Reserved: DWORD;
  433. Value: DWORD; // value of the constant
  434. end;
  435. TSymbolUdtInfo = packed record
  436. TypeIndex: DWORD; // Type index of the type
  437. Properties: Word; // isTag:1 True if this is a tag (not a typedef)
  438. // isNest:1 True if the type is a nested type (its name
  439. // will be 'class_name::type_name' in that case)
  440. NameIndex: DWORD; // Name index of the type
  441. Reserved: DWORD;
  442. end;
  443. TSymbolVftPathInfo = packed record
  444. Offset: DWORD; // Offset portion of start of the virtual function table
  445. Segment: Word; // Segment portion of the virtual function table
  446. Reserved: Word;
  447. RootIndex: DWORD; // The type index of the class at the root of the path
  448. PathIndex: DWORD; // Type index of the record describing the base class
  449. // path from the root to the leaf class for the virtual
  450. // function table
  451. end;
  452. type
  453. { Symbol Information Records }
  454. PSymbolInfo = ^TSymbolInfo;
  455. TSymbolInfo = packed record
  456. Size: Word;
  457. SymbolType: Word;
  458. case Word of
  459. SYMBOL_TYPE_LPROC32, SYMBOL_TYPE_GPROC32:
  460. (Proc: TSymbolProcInfo);
  461. SYMBOL_TYPE_OBJNAME:
  462. (ObjName: TSymbolObjNameInfo);
  463. SYMBOL_TYPE_LDATA32, SYMBOL_TYPE_GDATA32, SYMBOL_TYPE_PUB32:
  464. (Data: TSymbolDataInfo);
  465. SYMBOL_TYPE_WITH32:
  466. (With32: TSymbolWithInfo);
  467. SYMBOL_TYPE_LABEL32:
  468. (Label32: TSymbolLabelInfo);
  469. SYMBOL_TYPE_CONST:
  470. (Constant: TSymbolConstantInfo);
  471. SYMBOL_TYPE_UDT:
  472. (Udt: TSymbolUdtInfo);
  473. SYMBOL_TYPE_VFTPATH32:
  474. (VftPath: TSymbolVftPathInfo);
  475. end;
  476. PSymbolInfos = ^TSymbolInfos;
  477. TSymbolInfos = packed record
  478. Signature: DWORD;
  479. Symbols: array [0..0] of TSymbolInfo;
  480. end;
  481. {$IFDEF SUPPORTS_EXTSYM}
  482. {$EXTERNALSYM Borland32BitSymbolFileSignatureForDelphi}
  483. {$EXTERNALSYM Borland32BitSymbolFileSignatureForBCB}
  484. {$EXTERNALSYM SUBSECTION_TYPE_MODULE}
  485. {$EXTERNALSYM SUBSECTION_TYPE_TYPES}
  486. {$EXTERNALSYM SUBSECTION_TYPE_SYMBOLS}
  487. {$EXTERNALSYM SUBSECTION_TYPE_ALIGN_SYMBOLS}
  488. {$EXTERNALSYM SUBSECTION_TYPE_SOURCE_MODULE}
  489. {$EXTERNALSYM SUBSECTION_TYPE_GLOBAL_SYMBOLS}
  490. {$EXTERNALSYM SUBSECTION_TYPE_GLOBAL_TYPES}
  491. {$EXTERNALSYM SUBSECTION_TYPE_NAMES}
  492. {$EXTERNALSYM SYMBOL_TYPE_COMPILE}
  493. {$EXTERNALSYM SYMBOL_TYPE_REGISTER}
  494. {$EXTERNALSYM SYMBOL_TYPE_CONST}
  495. {$EXTERNALSYM SYMBOL_TYPE_UDT}
  496. {$EXTERNALSYM SYMBOL_TYPE_SSEARCH}
  497. {$EXTERNALSYM SYMBOL_TYPE_END}
  498. {$EXTERNALSYM SYMBOL_TYPE_SKIP}
  499. {$EXTERNALSYM SYMBOL_TYPE_CVRESERVE}
  500. {$EXTERNALSYM SYMBOL_TYPE_OBJNAME}
  501. {$EXTERNALSYM SYMBOL_TYPE_BPREL16}
  502. {$EXTERNALSYM SYMBOL_TYPE_LDATA16}
  503. {$EXTERNALSYM SYMBOL_TYPE_GDATA16}
  504. {$EXTERNALSYM SYMBOL_TYPE_PUB16}
  505. {$EXTERNALSYM SYMBOL_TYPE_LPROC16}
  506. {$EXTERNALSYM SYMBOL_TYPE_GPROC16}
  507. {$EXTERNALSYM SYMBOL_TYPE_THUNK16}
  508. {$EXTERNALSYM SYMBOL_TYPE_BLOCK16}
  509. {$EXTERNALSYM SYMBOL_TYPE_WITH16}
  510. {$EXTERNALSYM SYMBOL_TYPE_LABEL16}
  511. {$EXTERNALSYM SYMBOL_TYPE_CEXMODEL16}
  512. {$EXTERNALSYM SYMBOL_TYPE_VFTPATH16}
  513. {$EXTERNALSYM SYMBOL_TYPE_BPREL32}
  514. {$EXTERNALSYM SYMBOL_TYPE_LDATA32}
  515. {$EXTERNALSYM SYMBOL_TYPE_GDATA32}
  516. {$EXTERNALSYM SYMBOL_TYPE_PUB32}
  517. {$EXTERNALSYM SYMBOL_TYPE_LPROC32}
  518. {$EXTERNALSYM SYMBOL_TYPE_GPROC32}
  519. {$EXTERNALSYM SYMBOL_TYPE_THUNK32}
  520. {$EXTERNALSYM SYMBOL_TYPE_BLOCK32}
  521. {$EXTERNALSYM SYMBOL_TYPE_WITH32}
  522. {$EXTERNALSYM SYMBOL_TYPE_LABEL32}
  523. {$EXTERNALSYM SYMBOL_TYPE_CEXMODEL32}
  524. {$EXTERNALSYM SYMBOL_TYPE_VFTPATH32}
  525. {$ENDIF SUPPORTS_EXTSYM}
  526. // TD32 information related classes
  527. type
  528. TJclTD32ModuleInfo = class(TObject)
  529. private
  530. FNameIndex: DWORD;
  531. FSegments: PSegmentInfoArray;
  532. FSegmentCount: Integer;
  533. function GetSegment(const Idx: Integer): TSegmentInfo;
  534. public
  535. constructor Create(pModInfo: PModuleInfo);
  536. property NameIndex: DWORD read FNameIndex;
  537. property SegmentCount: Integer read FSegmentCount; //GetSegmentCount;
  538. property Segment[const Idx: Integer]: TSegmentInfo read GetSegment; default;
  539. end;
  540. TJclTD32LineInfo = class(TObject)
  541. private
  542. FLineNo: DWORD;
  543. FOffset: DWORD;
  544. public
  545. constructor Create(ALineNo, AOffset: DWORD);
  546. property LineNo: DWORD read FLineNo;
  547. property Offset: DWORD read FOffset;
  548. end;
  549. TJclTD32SourceModuleInfo = class(TObject)
  550. private
  551. FLines: TObjectList;
  552. FSegments: POffsetPairArray;
  553. FSegmentCount: Integer;
  554. FNameIndex: DWORD;
  555. function GetLine(const Idx: Integer): TJclTD32LineInfo;
  556. function GetLineCount: Integer;
  557. function GetSegment(const Idx: Integer): TOffsetPair;
  558. public
  559. constructor Create(pSrcFile: PSourceFileEntry; Base: TJclAddr);
  560. destructor Destroy; override;
  561. function FindLine(const AAddr: DWORD; out ALine: TJclTD32LineInfo): Boolean;
  562. property NameIndex: DWORD read FNameIndex;
  563. property LineCount: Integer read GetLineCount;
  564. property Line[const Idx: Integer]: TJclTD32LineInfo read GetLine; default;
  565. property SegmentCount: Integer read FSegmentCount; //GetSegmentCount;
  566. property Segment[const Idx: Integer]: TOffsetPair read GetSegment;
  567. end;
  568. TJclTD32SymbolInfo = class(TObject)
  569. private
  570. FSymbolType: Word;
  571. public
  572. constructor Create(pSymInfo: PSymbolInfo); virtual;
  573. property SymbolType: Word read FSymbolType;
  574. end;
  575. TJclTD32ProcSymbolInfo = class(TJclTD32SymbolInfo)
  576. private
  577. FNameIndex: DWORD;
  578. FOffset: DWORD;
  579. FSize: DWORD;
  580. public
  581. constructor Create(pSymInfo: PSymbolInfo); override;
  582. property NameIndex: DWORD read FNameIndex;
  583. property Offset: DWORD read FOffset;
  584. property Size: DWORD read FSize;
  585. end;
  586. TJclTD32LocalProcSymbolInfo = class(TJclTD32ProcSymbolInfo);
  587. TJclTD32GlobalProcSymbolInfo = class(TJclTD32ProcSymbolInfo);
  588. { not used by Delphi }
  589. TJclTD32ObjNameSymbolInfo = class(TJclTD32SymbolInfo)
  590. private
  591. FSignature: DWORD;
  592. FNameIndex: DWORD;
  593. public
  594. constructor Create(pSymInfo: PSymbolInfo); override;
  595. property NameIndex: DWORD read FNameIndex;
  596. property Signature: DWORD read FSignature;
  597. end;
  598. TJclTD32DataSymbolInfo = class(TJclTD32SymbolInfo)
  599. private
  600. FOffset: DWORD;
  601. FTypeIndex: DWORD;
  602. FNameIndex: DWORD;
  603. public
  604. constructor Create(pSymInfo: PSymbolInfo); override;
  605. property NameIndex: DWORD read FNameIndex;
  606. property TypeIndex: DWORD read FTypeIndex;
  607. property Offset: DWORD read FOffset;
  608. end;
  609. TJclTD32LDataSymbolInfo = class(TJclTD32DataSymbolInfo);
  610. TJclTD32GDataSymbolInfo = class(TJclTD32DataSymbolInfo);
  611. TJclTD32PublicSymbolInfo = class(TJclTD32DataSymbolInfo);
  612. TJclTD32WithSymbolInfo = class(TJclTD32SymbolInfo)
  613. private
  614. FOffset: DWORD;
  615. FSize: DWORD;
  616. FNameIndex: DWORD;
  617. public
  618. constructor Create(pSymInfo: PSymbolInfo); override;
  619. property NameIndex: DWORD read FNameIndex;
  620. property Offset: DWORD read FOffset;
  621. property Size: DWORD read FSize;
  622. end;
  623. { not used by Delphi }
  624. TJclTD32LabelSymbolInfo = class(TJclTD32SymbolInfo)
  625. private
  626. FOffset: DWORD;
  627. FNameIndex: DWORD;
  628. public
  629. constructor Create(pSymInfo: PSymbolInfo); override;
  630. property NameIndex: DWORD read FNameIndex;
  631. property Offset: DWORD read FOffset;
  632. end;
  633. { not used by Delphi }
  634. TJclTD32ConstantSymbolInfo = class(TJclTD32SymbolInfo)
  635. private
  636. FValue: DWORD;
  637. FTypeIndex: DWORD;
  638. FNameIndex: DWORD;
  639. public
  640. constructor Create(pSymInfo: PSymbolInfo); override;
  641. property NameIndex: DWORD read FNameIndex;
  642. property TypeIndex: DWORD read FTypeIndex; // for enums
  643. property Value: DWORD read FValue;
  644. end;
  645. TJclTD32UdtSymbolInfo = class(TJclTD32SymbolInfo)
  646. private
  647. FTypeIndex: DWORD;
  648. FNameIndex: DWORD;
  649. FProperties: Word;
  650. public
  651. constructor Create(pSymInfo: PSymbolInfo); override;
  652. property NameIndex: DWORD read FNameIndex;
  653. property TypeIndex: DWORD read FTypeIndex;
  654. property Properties: Word read FProperties;
  655. end;
  656. { not used by Delphi }
  657. TJclTD32VftPathSymbolInfo = class(TJclTD32SymbolInfo)
  658. private
  659. FRootIndex: DWORD;
  660. FPathIndex: DWORD;
  661. FOffset: DWORD;
  662. public
  663. constructor Create(pSymInfo: PSymbolInfo); override;
  664. property RootIndex: DWORD read FRootIndex;
  665. property PathIndex: DWORD read FPathIndex;
  666. property Offset: DWORD read FOffset;
  667. end;
  668. // TD32 parser
  669. TJclTD32InfoParser = class(TObject)
  670. private
  671. FBase: Pointer;
  672. FData: TCustomMemoryStream;
  673. FNames: TList;
  674. FModules: TObjectList;
  675. FSourceModules: TObjectList;
  676. FSymbols: TObjectList;
  677. FProcSymbols: TList;
  678. FValidData: Boolean;
  679. FUnmangledNames: TStrings;
  680. function GetName(const Idx: Integer): string;
  681. function GetNameCount: Integer;
  682. function GetSymbol(const Idx: Integer): TJclTD32SymbolInfo;
  683. function GetSymbolCount: Integer;
  684. function GetProcSymbol(const Idx: Integer): TJclTD32ProcSymbolInfo;
  685. function GetProcSymbolCount: Integer;
  686. function GetModule(const Idx: Integer): TJclTD32ModuleInfo;
  687. function GetModuleCount: Integer;
  688. function GetSourceModule(const Idx: Integer): TJclTD32SourceModuleInfo;
  689. function GetSourceModuleCount: Integer;
  690. function FormatProcName(const ProcName: string): string;
  691. protected
  692. procedure Analyse;
  693. procedure AnalyseNames(const pSubsection: Pointer; const Size: DWORD); virtual;
  694. procedure AnalyseGlobalTypes(const pTypes: Pointer; const Size: DWORD); virtual;
  695. procedure AnalyseAlignSymbols(pSymbols: PSymbolInfos; const Size: DWORD); virtual;
  696. procedure AnalyseModules(pModInfo: PModuleInfo; const Size: DWORD); virtual;
  697. procedure AnalyseSourceModules(pSrcModInfo: PSourceModuleInfo; const Size: DWORD); virtual;
  698. procedure AnalyseUnknownSubSection(const pSubsection: Pointer; const Size: DWORD); virtual;
  699. function LfaToVa(Lfa: DWORD): Pointer;
  700. public
  701. constructor Create(const ATD32Data: TCustomMemoryStream); // Data mustn't be freed before the class is destroyed
  702. destructor Destroy; override;
  703. function FindModule(const AAddr: DWORD; out AMod: TJclTD32ModuleInfo): Boolean;
  704. function FindSourceModule(const AAddr: DWORD; out ASrcMod: TJclTD32SourceModuleInfo): Boolean;
  705. function FindProc(const AAddr: DWORD; out AProc: TJclTD32ProcSymbolInfo): Boolean;
  706. procedure GenerateUnmangledNames;
  707. class function IsTD32Sign(const Sign: TJclTD32FileSignature): Boolean;
  708. class function IsTD32DebugInfoValid(const DebugData: Pointer; const DebugDataSize: LongWord): Boolean;
  709. property Data: TCustomMemoryStream read FData;
  710. property Names[const Idx: Integer]: string read GetName;
  711. property NameCount: Integer read GetNameCount;
  712. property Symbols[const Idx: Integer]: TJclTD32SymbolInfo read GetSymbol;
  713. property SymbolCount: Integer read GetSymbolCount;
  714. property ProcSymbols[const Idx: Integer]: TJclTD32ProcSymbolInfo read GetProcSymbol;
  715. property ProcSymbolCount: Integer read GetProcSymbolCount;
  716. property Modules[const Idx: Integer]: TJclTD32ModuleInfo read GetModule;
  717. property ModuleCount: Integer read GetModuleCount;
  718. property SourceModules[const Idx: Integer]: TJclTD32SourceModuleInfo read GetSourceModule;
  719. property SourceModuleCount: Integer read GetSourceModuleCount;
  720. property ValidData: Boolean read FValidData;
  721. end;
  722. // TD32 scanner with source location methods
  723. TJclTD32InfoScanner = class(TJclTD32InfoParser)
  724. public
  725. function LineNumberFromAddr(AAddr: DWORD; out Offset: Integer): Integer; overload;
  726. function LineNumberFromAddr(AAddr: DWORD): Integer; overload;
  727. function ProcNameFromAddr(AAddr: DWORD): string; overload;
  728. function ProcNameFromAddr(AAddr: DWORD; out Offset: Integer): string; overload;
  729. function ModuleNameFromAddr(AAddr: DWORD): string;
  730. function SourceNameFromAddr(AAddr: DWORD): string;
  731. function VAFromUnitAndProcName(const UnitName, ProcName: string): DWORD;
  732. end;
  733. {$IFDEF BORLAND}
  734. // PE Image with TD32 information and source location support
  735. TJclPeBorTD32Image = class(TJclPeBorImage)
  736. private
  737. FIsTD32DebugPresent: Boolean;
  738. FTD32DebugData: TCustomMemoryStream;
  739. FTD32Scanner: TJclTD32InfoScanner;
  740. protected
  741. procedure AfterOpen; override;
  742. procedure Clear; override;
  743. procedure ClearDebugData;
  744. procedure CheckDebugData;
  745. function IsDebugInfoInImage(var DataStream: TCustomMemoryStream): Boolean;
  746. function IsDebugInfoInTds(var DataStream: TCustomMemoryStream): Boolean;
  747. public
  748. property IsTD32DebugPresent: Boolean read FIsTD32DebugPresent;
  749. property TD32DebugData: TCustomMemoryStream read FTD32DebugData;
  750. property TD32Scanner: TJclTD32InfoScanner read FTD32Scanner;
  751. end;
  752. {$ENDIF BORLAND}
  753. {$IFDEF UNITVERSIONING}
  754. const
  755. UnitVersioning: TUnitVersionInfo = (
  756. RCSfile: '$URL$';
  757. Revision: '$Revision$';
  758. Date: '$Date$';
  759. LogPath: 'JCL\source\windows';
  760. Extra: '';
  761. Data: nil
  762. );
  763. {$ENDIF UNITVERSIONING}
  764. implementation
  765. uses
  766. JclResources, JclSysUtils{$IFNDEF WINSCP}, JclStringConversions{$ENDIF};
  767. {$IFDEF BORLAND}
  768. const
  769. TurboDebuggerSymbolExt = '.tds';
  770. {$ENDIF BORLAND}
  771. //=== { TJclModuleInfo } =====================================================
  772. constructor TJclTD32ModuleInfo.Create(pModInfo: PModuleInfo);
  773. begin
  774. Assert(Assigned(pModInfo));
  775. inherited Create;
  776. FNameIndex := pModInfo.NameIndex;
  777. FSegments := @pModInfo.Segments[0];
  778. FSegmentCount := pModInfo.SegmentCount;
  779. end;
  780. function TJclTD32ModuleInfo.GetSegment(const Idx: Integer): TSegmentInfo;
  781. begin
  782. Assert((0 <= Idx) and (Idx < FSegmentCount));
  783. Result := FSegments[Idx];
  784. end;
  785. //=== { TJclLineInfo } =======================================================
  786. constructor TJclTD32LineInfo.Create(ALineNo, AOffset: DWORD);
  787. begin
  788. inherited Create;
  789. FLineNo := ALineNo;
  790. FOffset := AOffset;
  791. end;
  792. //=== { TJclSourceModuleInfo } ===============================================
  793. constructor TJclTD32SourceModuleInfo.Create(pSrcFile: PSourceFileEntry; Base: TJclAddr);
  794. type
  795. PArrayOfWord = ^TArrayOfWord;
  796. TArrayOfWord = array [0..MaxInt div SizeOf(Word) - 1] of Word;
  797. var
  798. I, J: Integer;
  799. pLineEntry: PLineMappingEntry;
  800. begin
  801. Assert(Assigned(pSrcFile));
  802. inherited Create;
  803. FNameIndex := pSrcFile.NameIndex;
  804. FLines := TObjectList.Create;
  805. {$RANGECHECKS OFF}
  806. for I := 0 to pSrcFile.SegmentCount - 1 do
  807. begin
  808. pLineEntry := PLineMappingEntry(Base + pSrcFile.BaseSrcLines[I]);
  809. for J := 0 to pLineEntry.PairCount - 1 do
  810. FLines.Add(TJclTD32LineInfo.Create(
  811. PArrayOfWord(@pLineEntry.Offsets[pLineEntry.PairCount])^[J],
  812. pLineEntry.Offsets[J]));
  813. end;
  814. FSegments := @pSrcFile.BaseSrcLines[pSrcFile.SegmentCount];
  815. FSegmentCount := pSrcFile.SegmentCount;
  816. {$IFDEF RANGECHECKS_ON}
  817. {$RANGECHECKS ON}
  818. {$ENDIF RANGECHECKS_ON}
  819. end;
  820. destructor TJclTD32SourceModuleInfo.Destroy;
  821. begin
  822. FreeAndNil(FLines);
  823. inherited Destroy;
  824. end;
  825. function TJclTD32SourceModuleInfo.GetLine(const Idx: Integer): TJclTD32LineInfo;
  826. begin
  827. Result := TJclTD32LineInfo(FLines.Items[Idx]);
  828. end;
  829. function TJclTD32SourceModuleInfo.GetLineCount: Integer;
  830. begin
  831. Result := FLines.Count;
  832. end;
  833. function TJclTD32SourceModuleInfo.GetSegment(const Idx: Integer): TOffsetPair;
  834. begin
  835. Assert((0 <= Idx) and (Idx < FSegmentCount));
  836. Result := FSegments[Idx];
  837. end;
  838. function TJclTD32SourceModuleInfo.FindLine(const AAddr: DWORD; out ALine: TJclTD32LineInfo): Boolean;
  839. var
  840. I: Integer;
  841. begin
  842. for I := 0 to LineCount - 1 do
  843. with Line[I] do
  844. begin
  845. if AAddr = Offset then
  846. begin
  847. Result := True;
  848. ALine := Line[I];
  849. Exit;
  850. end
  851. else
  852. if (I > 1) and (Line[I - 1].Offset < AAddr) and (AAddr < Offset) then
  853. begin
  854. Result := True;
  855. ALine := Line[I-1];
  856. Exit;
  857. end;
  858. end;
  859. Result := False;
  860. ALine := nil;
  861. end;
  862. //=== { TJclSymbolInfo } =====================================================
  863. constructor TJclTD32SymbolInfo.Create(pSymInfo: PSymbolInfo);
  864. begin
  865. Assert(Assigned(pSymInfo));
  866. inherited Create;
  867. FSymbolType := pSymInfo.SymbolType;
  868. end;
  869. //=== { TJclProcSymbolInfo } =================================================
  870. constructor TJclTD32ProcSymbolInfo.Create(pSymInfo: PSymbolInfo);
  871. begin
  872. Assert(Assigned(pSymInfo));
  873. inherited Create(pSymInfo);
  874. with pSymInfo^ do
  875. begin
  876. FNameIndex := Proc.NameIndex;
  877. FOffset := Proc.Offset;
  878. FSize := Proc.Size;
  879. end;
  880. end;
  881. //=== { TJclObjNameSymbolInfo } ==============================================
  882. constructor TJclTD32ObjNameSymbolInfo.Create(pSymInfo: PSymbolInfo);
  883. begin
  884. Assert(Assigned(pSymInfo));
  885. inherited Create(pSymInfo);
  886. with pSymInfo^ do
  887. begin
  888. FNameIndex := ObjName.NameIndex;
  889. FSignature := ObjName.Signature;
  890. end;
  891. end;
  892. //=== { TJclDataSymbolInfo } =================================================
  893. constructor TJclTD32DataSymbolInfo.Create(pSymInfo: PSymbolInfo);
  894. begin
  895. Assert(Assigned(pSymInfo));
  896. inherited Create(pSymInfo);
  897. with pSymInfo^ do
  898. begin
  899. FTypeIndex := Data.TypeIndex;
  900. FNameIndex := Data.NameIndex;
  901. FOffset := Data.Offset;
  902. end;
  903. end;
  904. //=== { TJclWithSymbolInfo } =================================================
  905. constructor TJclTD32WithSymbolInfo.Create(pSymInfo: PSymbolInfo);
  906. begin
  907. Assert(Assigned(pSymInfo));
  908. inherited Create(pSymInfo);
  909. with pSymInfo^ do
  910. begin
  911. FNameIndex := With32.NameIndex;
  912. FOffset := With32.Offset;
  913. FSize := With32.Size;
  914. end;
  915. end;
  916. //=== { TJclLabelSymbolInfo } ================================================
  917. constructor TJclTD32LabelSymbolInfo.Create(pSymInfo: PSymbolInfo);
  918. begin
  919. Assert(Assigned(pSymInfo));
  920. inherited Create(pSymInfo);
  921. with pSymInfo^ do
  922. begin
  923. FNameIndex := Label32.NameIndex;
  924. FOffset := Label32.Offset;
  925. end;
  926. end;
  927. //=== { TJclConstantSymbolInfo } =============================================
  928. constructor TJclTD32ConstantSymbolInfo.Create(pSymInfo: PSymbolInfo);
  929. begin
  930. Assert(Assigned(pSymInfo));
  931. inherited Create(pSymInfo);
  932. with pSymInfo^ do
  933. begin
  934. FNameIndex := Constant.NameIndex;
  935. FTypeIndex := Constant.TypeIndex;
  936. FValue := Constant.Value;
  937. end;
  938. end;
  939. //=== { TJclUdtSymbolInfo } ==================================================
  940. constructor TJclTD32UdtSymbolInfo.Create(pSymInfo: PSymbolInfo);
  941. begin
  942. Assert(Assigned(pSymInfo));
  943. inherited Create(pSymInfo);
  944. with pSymInfo^ do
  945. begin
  946. FNameIndex := Udt.NameIndex;
  947. FTypeIndex := Udt.TypeIndex;
  948. FProperties := Udt.Properties;
  949. end;
  950. end;
  951. //=== { TJclVftPathSymbolInfo } ==============================================
  952. constructor TJclTD32VftPathSymbolInfo.Create(pSymInfo: PSymbolInfo);
  953. begin
  954. Assert(Assigned(pSymInfo));
  955. inherited Create(pSymInfo);
  956. with pSymInfo^ do
  957. begin
  958. FRootIndex := VftPath.RootIndex;
  959. FPathIndex := VftPath.PathIndex;
  960. FOffset := VftPath.Offset;
  961. end;
  962. end;
  963. //=== { TJclTD32InfoParser } =================================================
  964. constructor TJclTD32InfoParser.Create(const ATD32Data: TCustomMemoryStream);
  965. begin
  966. Assert(Assigned(ATD32Data));
  967. inherited Create;
  968. FNames := TList.Create;
  969. FModules := TObjectList.Create;
  970. FSourceModules := TObjectList.Create;
  971. FSymbols := TObjectList.Create;
  972. FProcSymbols := TList.Create;
  973. FNames.Add(nil);
  974. FData := ATD32Data;
  975. FBase := FData.Memory;
  976. FValidData := IsTD32DebugInfoValid(FBase, FData.Size);
  977. FUnmangledNames := TStringList.Create;
  978. if FValidData then
  979. Analyse;
  980. end;
  981. destructor TJclTD32InfoParser.Destroy;
  982. begin
  983. FreeAndNil(FProcSymbols);
  984. FreeAndNil(FSymbols);
  985. FreeAndNil(FSourceModules);
  986. FreeAndNil(FModules);
  987. FreeAndNil(FNames);
  988. FreeAndNil(FUnmangledNames);
  989. inherited Destroy;
  990. end;
  991. procedure TJclTD32InfoParser.Analyse;
  992. var
  993. I: Integer;
  994. pDirHeader: PDirectoryHeader;
  995. pSubsection: Pointer;
  996. begin
  997. pDirHeader := PDirectoryHeader(LfaToVa(PJclTD32FileSignature(LfaToVa(0)).Offset));
  998. while True do
  999. begin
  1000. Assert(pDirHeader.DirEntrySize = SizeOf(TDirectoryEntry));
  1001. {$RANGECHECKS OFF}
  1002. for I := 0 to pDirHeader.DirEntryCount - 1 do
  1003. with pDirHeader.DirEntries[I] do
  1004. begin
  1005. pSubsection := LfaToVa(Offset);
  1006. case SubsectionType of
  1007. SUBSECTION_TYPE_MODULE:
  1008. AnalyseModules(pSubsection, Size);
  1009. SUBSECTION_TYPE_ALIGN_SYMBOLS:
  1010. AnalyseAlignSymbols(pSubsection, Size);
  1011. SUBSECTION_TYPE_SOURCE_MODULE:
  1012. AnalyseSourceModules(pSubsection, Size);
  1013. SUBSECTION_TYPE_NAMES:
  1014. AnalyseNames(pSubsection, Size);
  1015. SUBSECTION_TYPE_GLOBAL_TYPES:
  1016. AnalyseGlobalTypes(pSubsection, Size);
  1017. else
  1018. AnalyseUnknownSubSection(pSubsection, Size);
  1019. end;
  1020. end;
  1021. {$IFDEF RANGECHECKS_ON}
  1022. {$RANGECHECKS ON}
  1023. {$ENDIF RANGECHECKS_ON}
  1024. if pDirHeader.lfoNextDir <> 0 then
  1025. pDirHeader := PDirectoryHeader(LfaToVa(pDirHeader.lfoNextDir))
  1026. else
  1027. Break;
  1028. end;
  1029. end;
  1030. procedure TJclTD32InfoParser.AnalyseNames(const pSubsection: Pointer; const Size: DWORD);
  1031. var
  1032. I, Count, Len: Integer;
  1033. pszName: PAnsiChar;
  1034. begin
  1035. Count := PDWORD(pSubsection)^;
  1036. pszName := PAnsiChar(TJclAddr(pSubsection) + SizeOf(DWORD));
  1037. if Count > 0 then
  1038. begin
  1039. FNames.Capacity := FNames.Capacity + Count;
  1040. for I := 0 to Count - 1 do
  1041. begin
  1042. // Get the length of the name
  1043. Len := Ord(pszName^);
  1044. Inc(pszName);
  1045. // Get the name
  1046. FNames.Add(pszName);
  1047. // first, skip the length of name
  1048. Inc(pszName, Len);
  1049. // the length is only correct modulo 256 because it is stored on a single byte,
  1050. // so we have to iterate until we find the real end of the string
  1051. while PszName^ <> #0 do
  1052. Inc(pszName, 256);
  1053. // then, skip a NULL at the end
  1054. Inc(pszName, 1);
  1055. end;
  1056. end;
  1057. end;
  1058. { // unused
  1059. const
  1060. // Leaf indices for type records that can be referenced from symbols
  1061. LF_MODIFIER = $0001;
  1062. LF_POINTER = $0002;
  1063. LF_ARRAY = $0003;
  1064. LF_CLASS = $0004;
  1065. LF_STRUCTURE = $0005;
  1066. LF_UNION = $0006;
  1067. LF_ENUM = $0007;
  1068. LF_PROCEDURE = $0008;
  1069. LF_MFUNCTION = $0009;
  1070. LF_VTSHAPE = $000a;
  1071. LF_COBOL0 = $000b;
  1072. LF_COBOL1 = $000c;
  1073. LF_BARRAY = $000d;
  1074. LF_LABEL = $000e;
  1075. LF_NULL = $000f;
  1076. LF_NOTTRAN = $0010;
  1077. LF_DIMARRAY = $0011;
  1078. LF_VFTPATH = $0012;
  1079. // Leaf indices for type records that can be referenced from other type records
  1080. LF_SKIP = $0200;
  1081. LF_ARGLIST = $0201;
  1082. LF_DEFARG = $0202;
  1083. LF_LIST = $0203;
  1084. LF_FIELDLIST = $0204;
  1085. LF_DERIVED = $0205;
  1086. LF_BITFIELD = $0206;
  1087. LF_METHODLIST = $0207;
  1088. LF_DIMCONU = $0208;
  1089. LF_DIMCONLU = $0209;
  1090. LF_DIMVARU = $020a;
  1091. LF_DIMVARLU = $020b;
  1092. LF_REFSYM = $020c;
  1093. // Leaf indices for fields of complex lists:
  1094. LF_BCLASS = $0400;
  1095. LF_VBCLASS = $0401;
  1096. LF_IVBCLASS = $0402;
  1097. LF_ENUMERATE = $0403;
  1098. LF_FRIENDFCN = $0404;
  1099. LF_INDEX = $0405;
  1100. LF_MEMBER = $0406;
  1101. LF_STMEMBER = $0407;
  1102. LF_METHOD = $0408;
  1103. LF_NESTTYPE = $0409;
  1104. LF_VFUNCTAB = $040a;
  1105. LF_FRIENDCLS = $040b;
  1106. // Leaf indices for numeric fields of symbols and type records:
  1107. LF_NUMERIC = $8000;
  1108. LF_CHAR = $8001;
  1109. LF_SHORT = $8002;
  1110. LF_USHORT = $8003;
  1111. LF_LONG = $8004;
  1112. LF_ULONG = $8005;
  1113. LF_REAL32 = $8006;
  1114. LF_REAL64 = $8007;
  1115. LF_REAL80 = $8008;
  1116. LF_REAL128 = $8009;
  1117. LF_QUADWORD = $800a;
  1118. LF_UQUADWORD = $800b;
  1119. LF_REAL48 = $800c;
  1120. LF_PAD0 = $f0;
  1121. LF_PAD1 = $f1;
  1122. LF_PAD2 = $f2;
  1123. LF_PAD3 = $f3;
  1124. LF_PAD4 = $f4;
  1125. LF_PAD5 = $f5;
  1126. LF_PAD6 = $f6;
  1127. LF_PAD7 = $f7;
  1128. LF_PAD8 = $f8;
  1129. LF_PAD9 = $f9;
  1130. LF_PAD10 = $fa;
  1131. LF_PAD11 = $fb;
  1132. LF_PAD12 = $fc;
  1133. LF_PAD13 = $fd;
  1134. LF_PAD14 = $fe;
  1135. LF_PAD15 = $ff;
  1136. }
  1137. type
  1138. PSymbolTypeInfo = ^TSymbolTypeInfo;
  1139. TSymbolTypeInfo = packed record
  1140. TypeId: DWORD;
  1141. NameIndex: DWORD; // 0 if unnamed
  1142. Size: Word; // size in bytes of the object
  1143. MaxSize: Byte;
  1144. ParentIndex: DWORD;
  1145. end;
  1146. { unused
  1147. const
  1148. TID_VOID = $00; // Unknown or no type
  1149. TID_LSTR = $01; // Basic Literal string
  1150. TID_DSTR = $02; // Basic Dynamic string
  1151. TID_PSTR = $03; // Pascal style string
  1152. }
  1153. procedure TJclTD32InfoParser.AnalyseGlobalTypes(const pTypes: Pointer; const Size: DWORD);
  1154. var
  1155. pTyp: PSymbolTypeInfo;
  1156. begin
  1157. pTyp := PSymbolTypeInfo(pTypes);
  1158. repeat
  1159. {case pTyp.TypeId of
  1160. TID_VOID: ;
  1161. end;}
  1162. pTyp := PSymbolTypeInfo(TJclAddr(pTyp) + pTyp.Size + SizeOf(pTyp^));
  1163. until TJclAddr(pTyp) >= TJclAddr(pTypes) + Size;
  1164. end;
  1165. procedure TJclTD32InfoParser.AnalyseAlignSymbols(pSymbols: PSymbolInfos; const Size: DWORD);
  1166. var
  1167. Offset: TJclAddr;
  1168. pInfo: PSymbolInfo;
  1169. Symbol: TJclTD32SymbolInfo;
  1170. begin
  1171. Offset := TJclAddr(@pSymbols.Symbols[0]) - TJclAddr(pSymbols);
  1172. while Offset < Size do
  1173. begin
  1174. pInfo := PSymbolInfo(TJclAddr(pSymbols) + Offset);
  1175. case pInfo.SymbolType of
  1176. SYMBOL_TYPE_LPROC32:
  1177. begin
  1178. Symbol := TJclTD32LocalProcSymbolInfo.Create(pInfo);
  1179. FProcSymbols.Add(Symbol);
  1180. end;
  1181. SYMBOL_TYPE_GPROC32:
  1182. begin
  1183. Symbol := TJclTD32GlobalProcSymbolInfo.Create(pInfo);
  1184. FProcSymbols.Add(Symbol);
  1185. end;
  1186. SYMBOL_TYPE_OBJNAME:
  1187. Symbol := TJclTD32ObjNameSymbolInfo.Create(pInfo);
  1188. SYMBOL_TYPE_LDATA32:
  1189. Symbol := TJclTD32LDataSymbolInfo.Create(pInfo);
  1190. SYMBOL_TYPE_GDATA32:
  1191. Symbol := TJclTD32GDataSymbolInfo.Create(pInfo);
  1192. SYMBOL_TYPE_PUB32:
  1193. Symbol := TJclTD32PublicSymbolInfo.Create(pInfo);
  1194. SYMBOL_TYPE_WITH32:
  1195. Symbol := TJclTD32WithSymbolInfo.Create(pInfo);
  1196. SYMBOL_TYPE_LABEL32:
  1197. Symbol := TJclTD32LabelSymbolInfo.Create(pInfo);
  1198. SYMBOL_TYPE_CONST:
  1199. Symbol := TJclTD32ConstantSymbolInfo.Create(pInfo);
  1200. SYMBOL_TYPE_UDT:
  1201. Symbol := TJclTD32UdtSymbolInfo.Create(pInfo);
  1202. SYMBOL_TYPE_VFTPATH32:
  1203. Symbol := TJclTD32VftPathSymbolInfo.Create(pInfo);
  1204. else
  1205. Symbol := nil;
  1206. end;
  1207. if Assigned(Symbol) then
  1208. FSymbols.Add(Symbol);
  1209. Inc(Offset, pInfo.Size + SizeOf(pInfo.Size));
  1210. end;
  1211. end;
  1212. procedure TJclTD32InfoParser.AnalyseModules(pModInfo: PModuleInfo; const Size: DWORD);
  1213. begin
  1214. FModules.Add(TJclTD32ModuleInfo.Create(pModInfo));
  1215. end;
  1216. procedure TJclTD32InfoParser.AnalyseSourceModules(pSrcModInfo: PSourceModuleInfo; const Size: DWORD);
  1217. var
  1218. I: Integer;
  1219. pSrcFile: PSourceFileEntry;
  1220. begin
  1221. {$RANGECHECKS OFF}
  1222. for I := 0 to pSrcModInfo.FileCount - 1 do
  1223. begin
  1224. pSrcFile := PSourceFileEntry(TJclAddr(pSrcModInfo) + pSrcModInfo.BaseSrcFiles[I]);
  1225. if pSrcFile.NameIndex > 0 then
  1226. FSourceModules.Add(TJclTD32SourceModuleInfo.Create(pSrcFile, TJclAddr(pSrcModInfo)));
  1227. end;
  1228. {$IFDEF RANGECHECKS_ON}
  1229. {$RANGECHECKS ON}
  1230. {$ENDIF RANGECHECKS_ON}
  1231. end;
  1232. procedure TJclTD32InfoParser.AnalyseUnknownSubSection(const pSubsection: Pointer; const Size: DWORD);
  1233. begin
  1234. // do nothing
  1235. end;
  1236. function TJclTD32InfoParser.FormatProcName(const ProcName: string): string;
  1237. var
  1238. SecondAtChar, P: PChar;
  1239. begin
  1240. Result := ProcName;
  1241. if (Length(ProcName) > 1) and (ProcName[1] = '@') then
  1242. begin
  1243. SecondAtChar := StrScan(PChar(ProcName) + 1, '@');
  1244. if SecondAtChar <> nil then
  1245. begin
  1246. Inc(SecondAtChar);
  1247. Result := SecondAtChar;
  1248. P := PChar(Result);
  1249. while P^ <> #0 do
  1250. begin
  1251. if (SecondAtChar^ = '@') and ((SecondAtChar - 1)^ <> '@') then
  1252. P^ := '.';
  1253. Inc(P);
  1254. Inc(SecondAtChar);
  1255. end;
  1256. end;
  1257. end;
  1258. if PeIsNameMangled(Result) <> umNotMangled then
  1259. Result := PeBorUnmangleName(Result);
  1260. end;
  1261. procedure TJclTD32InfoParser.GenerateUnmangledNames;
  1262. var
  1263. I: Integer;
  1264. begin
  1265. if FUnmangledNames.Count <> 0 then
  1266. Exit;
  1267. // FUnmangledNames.Capacity := NameCount;
  1268. for I := 0 to NameCount - 1 do
  1269. FUnmangledNames.Add(FormatProcName(UTF8ToString(PAnsiChar(FNames.Items[I]))));
  1270. end;
  1271. function TJclTD32InfoParser.GetModule(const Idx: Integer): TJclTD32ModuleInfo;
  1272. begin
  1273. Result := TJclTD32ModuleInfo(FModules.Items[Idx]);
  1274. end;
  1275. function TJclTD32InfoParser.GetModuleCount: Integer;
  1276. begin
  1277. Result := FModules.Count;
  1278. end;
  1279. function TJclTD32InfoParser.GetName(const Idx: Integer): string;
  1280. begin
  1281. if FUnmangledNames.Count > Idx then
  1282. Result := FUnmangledNames[Idx]
  1283. else
  1284. Result := UTF8ToString(PAnsiChar(FNames.Items[Idx]));
  1285. end;
  1286. function TJclTD32InfoParser.GetNameCount: Integer;
  1287. begin
  1288. Result := FNames.Count;
  1289. end;
  1290. function TJclTD32InfoParser.GetSourceModule(const Idx: Integer): TJclTD32SourceModuleInfo;
  1291. begin
  1292. Result := TJclTD32SourceModuleInfo(FSourceModules.Items[Idx]);
  1293. end;
  1294. function TJclTD32InfoParser.GetSourceModuleCount: Integer;
  1295. begin
  1296. Result := FSourceModules.Count;
  1297. end;
  1298. function TJclTD32InfoParser.GetSymbol(const Idx: Integer): TJclTD32SymbolInfo;
  1299. begin
  1300. Result := TJclTD32SymbolInfo(FSymbols.Items[Idx]);
  1301. end;
  1302. function TJclTD32InfoParser.GetSymbolCount: Integer;
  1303. begin
  1304. Result := FSymbols.Count;
  1305. end;
  1306. function TJclTD32InfoParser.GetProcSymbol(const Idx: Integer): TJclTD32ProcSymbolInfo;
  1307. begin
  1308. Result := TJclTD32ProcSymbolInfo(FProcSymbols.Items[Idx]);
  1309. end;
  1310. function TJclTD32InfoParser.GetProcSymbolCount: Integer;
  1311. begin
  1312. Result := FProcSymbols.Count;
  1313. end;
  1314. function TJclTD32InfoParser.FindModule(const AAddr: DWORD; out AMod: TJclTD32ModuleInfo): Boolean;
  1315. var
  1316. I, J: Integer;
  1317. begin
  1318. if ValidData then
  1319. for I := 0 to ModuleCount - 1 do
  1320. with Modules[I] do
  1321. for J := 0 to SegmentCount - 1 do
  1322. begin
  1323. if (FSegments[J].Flags = 1) and (AAddr >= FSegments[J].Offset) and (AAddr - FSegments[J].Offset <= Segment[J].Size) then
  1324. begin
  1325. Result := True;
  1326. AMod := Modules[I];
  1327. Exit;
  1328. end;
  1329. end;
  1330. Result := False;
  1331. AMod := nil;
  1332. end;
  1333. function TJclTD32InfoParser.FindSourceModule(const AAddr: DWORD; out ASrcMod: TJclTD32SourceModuleInfo): Boolean;
  1334. var
  1335. I, J: Integer;
  1336. begin
  1337. if ValidData then
  1338. for I := 0 to SourceModuleCount - 1 do
  1339. with SourceModules[I] do
  1340. for J := 0 to SegmentCount - 1 do
  1341. with Segment[J] do
  1342. if (StartOffset <= AAddr) and (AAddr < EndOffset) then
  1343. begin
  1344. Result := True;
  1345. ASrcMod := SourceModules[I];
  1346. Exit;
  1347. end;
  1348. ASrcMod := nil;
  1349. Result := False;
  1350. end;
  1351. function TJclTD32InfoParser.FindProc(const AAddr: DWORD; out AProc: TJclTD32ProcSymbolInfo): Boolean;
  1352. var
  1353. I: Integer;
  1354. begin
  1355. if ValidData then
  1356. for I := 0 to ProcSymbolCount - 1 do
  1357. begin
  1358. AProc := ProcSymbols[I];
  1359. with AProc do
  1360. if (Offset <= AAddr) and (AAddr < Offset + Size) then
  1361. begin
  1362. Result := True;
  1363. Exit;
  1364. end;
  1365. end;
  1366. AProc := nil;
  1367. Result := False;
  1368. end;
  1369. class function TJclTD32InfoParser.IsTD32DebugInfoValid(
  1370. const DebugData: Pointer; const DebugDataSize: LongWord): Boolean;
  1371. var
  1372. Sign: TJclTD32FileSignature;
  1373. EndOfDebugData: TJclAddr;
  1374. begin
  1375. Assert(not IsBadReadPtr(DebugData, DebugDataSize));
  1376. Result := False;
  1377. EndOfDebugData := TJclAddr(DebugData) + DebugDataSize;
  1378. if DebugDataSize > SizeOf(Sign) then
  1379. begin
  1380. Sign := PJclTD32FileSignature(EndOfDebugData - SizeOf(Sign))^;
  1381. if IsTD32Sign(Sign) and (Sign.Offset <= DebugDataSize) then
  1382. begin
  1383. Sign := PJclTD32FileSignature(EndOfDebugData - Sign.Offset)^;
  1384. Result := IsTD32Sign(Sign);
  1385. end;
  1386. end;
  1387. end;
  1388. class function TJclTD32InfoParser.IsTD32Sign(const Sign: TJclTD32FileSignature): Boolean;
  1389. begin
  1390. Result := (Sign.Signature = Borland32BitSymbolFileSignatureForDelphi) or
  1391. (Sign.Signature = Borland32BitSymbolFileSignatureForBCB);
  1392. end;
  1393. function TJclTD32InfoParser.LfaToVa(Lfa: DWORD): Pointer;
  1394. begin
  1395. Result := Pointer(TJclAddr(FBase) + Lfa)
  1396. end;
  1397. //=== { TJclTD32InfoScanner } ================================================
  1398. function TJclTD32InfoScanner.LineNumberFromAddr(AAddr: DWORD): Integer;
  1399. var
  1400. Dummy: Integer;
  1401. begin
  1402. Result := LineNumberFromAddr(AAddr, Dummy);
  1403. end;
  1404. function TJclTD32InfoScanner.LineNumberFromAddr(AAddr: DWORD; out Offset: Integer): Integer;
  1405. var
  1406. ASrcMod: TJclTD32SourceModuleInfo;
  1407. ALine: TJclTD32LineInfo;
  1408. begin
  1409. if FindSourceModule(AAddr, ASrcMod) and ASrcMod.FindLine(AAddr, ALine) then
  1410. begin
  1411. Result := ALine.LineNo;
  1412. Offset := AAddr - ALine.Offset;
  1413. end
  1414. else
  1415. begin
  1416. Result := 0;
  1417. Offset := 0;
  1418. end;
  1419. end;
  1420. function TJclTD32InfoScanner.ModuleNameFromAddr(AAddr: DWORD): string;
  1421. var
  1422. AMod: TJclTD32ModuleInfo;
  1423. begin
  1424. if FindModule(AAddr, AMod) then
  1425. Result := Names[AMod.NameIndex]
  1426. else
  1427. Result := '';
  1428. end;
  1429. function TJclTD32InfoScanner.ProcNameFromAddr(AAddr: DWORD): string;
  1430. var
  1431. Dummy: Integer;
  1432. begin
  1433. Result := ProcNameFromAddr(AAddr, Dummy);
  1434. end;
  1435. function TJclTD32InfoScanner.ProcNameFromAddr(AAddr: DWORD; out Offset: Integer): string;
  1436. var
  1437. AProc: TJclTD32ProcSymbolInfo;
  1438. begin
  1439. if FindProc(AAddr, AProc) then
  1440. begin
  1441. Result := FormatProcName(Names[AProc.NameIndex]);
  1442. Offset := AAddr - AProc.Offset;
  1443. end
  1444. else
  1445. begin
  1446. Result := '';
  1447. Offset := 0;
  1448. end;
  1449. end;
  1450. function TJclTD32InfoScanner.SourceNameFromAddr(AAddr: DWORD): string;
  1451. var
  1452. ASrcMod: TJclTD32SourceModuleInfo;
  1453. begin
  1454. if FindSourceModule(AAddr, ASrcMod) then
  1455. Result := Names[ASrcMod.NameIndex];
  1456. end;
  1457. function TJclTD32InfoScanner.VAFromUnitAndProcName(const UnitName, ProcName: string): DWORD;
  1458. var
  1459. I: Integer;
  1460. QualifiedName: string;
  1461. begin
  1462. Result := 0;
  1463. if (UnitName = '') or (ProcName = '') then
  1464. Exit;
  1465. QualifiedName := UnitName + '.' + ProcName;
  1466. for I := 0 to ProcSymbolCount - 1 do
  1467. begin
  1468. if CompareText(FormatProcName(Names[ProcSymbols[I].FNameIndex]), QualifiedName) = 0 then
  1469. begin
  1470. Result := ProcSymbols[I].FOffset;
  1471. Break;
  1472. end;
  1473. end;
  1474. end;
  1475. {$IFDEF BORLAND}
  1476. //=== { TJclPeBorTD32Image } =================================================
  1477. procedure TJclPeBorTD32Image.AfterOpen;
  1478. begin
  1479. inherited AfterOpen;
  1480. CheckDebugData;
  1481. end;
  1482. procedure TJclPeBorTD32Image.CheckDebugData;
  1483. begin
  1484. FIsTD32DebugPresent := IsDebugInfoInImage(FTD32DebugData);
  1485. if not FIsTD32DebugPresent then
  1486. FIsTD32DebugPresent := IsDebugInfoInTds(FTD32DebugData);
  1487. if FIsTD32DebugPresent then
  1488. begin
  1489. FTD32Scanner := TJclTD32InfoScanner.Create(FTD32DebugData);
  1490. if not FTD32Scanner.ValidData then
  1491. begin
  1492. ClearDebugData;
  1493. if not NoExceptions then
  1494. raise EJclError.CreateResFmt(@RsHasNotTD32Info, [FileName]);
  1495. end;
  1496. end;
  1497. end;
  1498. procedure TJclPeBorTD32Image.Clear;
  1499. begin
  1500. ClearDebugData;
  1501. inherited Clear;
  1502. end;
  1503. procedure TJclPeBorTD32Image.ClearDebugData;
  1504. begin
  1505. FIsTD32DebugPresent := False;
  1506. FreeAndNil(FTD32Scanner);
  1507. FreeAndNil(FTD32DebugData);
  1508. end;
  1509. function TJclPeBorTD32Image.IsDebugInfoInImage(var DataStream: TCustomMemoryStream): Boolean;
  1510. var
  1511. DebugDir: TImageDebugDirectory;
  1512. BugDataStart: Pointer;
  1513. DebugDataSize: Integer;
  1514. begin
  1515. Result := False;
  1516. DataStream := nil;
  1517. if IsBorlandImage and (DebugList.Count = 1) then
  1518. begin
  1519. DebugDir := DebugList[0];
  1520. if DebugDir._Type = IMAGE_DEBUG_TYPE_UNKNOWN then
  1521. begin
  1522. BugDataStart := RvaToVa(DebugDir.AddressOfRawData);
  1523. DebugDataSize := DebugDir.SizeOfData;
  1524. Result := TJclTD32InfoParser.IsTD32DebugInfoValid(BugDataStart, DebugDataSize);
  1525. if Result then
  1526. DataStream := TJclReferenceMemoryStream.Create(BugDataStart, DebugDataSize);
  1527. end;
  1528. end;
  1529. end;
  1530. function TJclPeBorTD32Image.IsDebugInfoInTds(var DataStream: TCustomMemoryStream): Boolean;
  1531. var
  1532. TdsFileName: TFileName;
  1533. TempStream: TCustomMemoryStream;
  1534. begin
  1535. Result := False;
  1536. DataStream := nil;
  1537. TdsFileName := ChangeFileExt(FileName, TurboDebuggerSymbolExt);
  1538. if FileExists(TdsFileName) then
  1539. begin
  1540. TempStream := TJclFileMappingStream.Create(TdsFileName, fmOpenRead or fmShareDenyNone);
  1541. try
  1542. Result := TJclTD32InfoParser.IsTD32DebugInfoValid(TempStream.Memory, TempStream.Size);
  1543. if Result then
  1544. DataStream := TempStream
  1545. else
  1546. TempStream.Free;
  1547. except
  1548. TempStream.Free;
  1549. raise;
  1550. end;
  1551. end;
  1552. end;
  1553. {$ENDIF BORLAND}
  1554. {$IFDEF UNITVERSIONING}
  1555. initialization
  1556. RegisterUnitVersion(HInstance, UnitVersioning);
  1557. finalization
  1558. UnregisterUnitVersion(HInstance);
  1559. {$ENDIF UNITVERSIONING}
  1560. end.