source: trunk/src/odinprof/symfile.cpp@ 7421

Last change on this file since 7421 was 7421, checked in by phaller, 24 years ago

Added ODIN profiler employing the VAC308 generated profiler hooks

File size: 12.4 KB
Line 
1/* $Id: symfile.cpp,v 1.1 2001-11-22 10:44:00 phaller Exp $ */
2/*
3 * Project Odin Software License can be found in LICENSE.TXT
4 * Execution Trace Profiler
5 *
6 * Copyright 2001 Patrick Haller <patrick.haller@innotek.de>
7 *
8 */
9
10
11/****************************************************************************
12 * To Do
13 ****************************************************************************
14
15 - find and load symbolic debug information file
16 (SYM2IDA)
17 => verify against kernel32\exceptionstack.cpp
18 (KERNEL32.SYM is not interpreted correctly)
19 - try to demangle C++ names
20 - fix weird duplicate lookups of same symbol (i. e. SetBkColor)
21 */
22
23
24/****************************************************************************
25 * includes
26 ****************************************************************************/
27
28#define INCL_DOSERRORS
29#define INCL_DOSPROCESS
30#define INCL_DOSMISC
31#define INCL_DOSFILEMGR
32#include <os2.h>
33
34#include <os2sel.h>
35#include <stdlib.h>
36#include <string.h>
37#include <stdio.h>
38#include <demangle.h>
39
40#include "profcollection.h"
41#include "symfile.h"
42
43
44/****************************************************************************
45 * implementation
46 ****************************************************************************/
47
48/*****************************************************************************
49 * Name : APIRET ReadFileToBuffer
50 * Funktion : Reads a single file completely into a memory buffer
51 * Parameter : PSZ pszFile, PPVOID ppBuffer, PULONG pulBuffer
52 * Variablen :
53 * Ergebnis : API-Returncode
54 * Bemerkung :
55 *
56 * Autor : Patrick Haller [Samstag, 07.10.1995 03.22.44]
57 *****************************************************************************/
58
59APIRET ToolsReadFileToBuffer (PSZ pszFile,
60 PPVOID ppBuffer,
61 PULONG pulBuffer)
62{
63 APIRET rc; /* API-Returncode */
64 FILESTATUS3 fs3Status; /* Dateiinformationen */
65 HFILE hFileInput; /* input file handle */
66 ULONG ulAction; /* dummy parameter for DosOpen */
67 ULONG ulReadSize; /* number of bytes to read per call */
68 ULONG ulReadTotal = 0; /* total number of bytes read */
69
70 if ( (pszFile == NULL) || /* check parameters */
71 (ppBuffer == NULL) ||
72 (pulBuffer == NULL) )
73 return (ERROR_INVALID_PARAMETER); /* signal error */
74
75
76 rc = DosQueryPathInfo (pszFile, /* Infos einholen */
77 FIL_STANDARD,
78 &fs3Status,
79 sizeof(fs3Status));
80 if (rc != NO_ERROR) /* check if an error occured */
81 return (rc); /* signal error */
82
83 /* allocate buffer RAM for the file */
84 *pulBuffer = fs3Status.cbFile; /* return the size of the file */
85 rc = DosAllocMem(ppBuffer, /* allocate the buffer */
86 fs3Status.cbFile,
87 PAG_WRITE |
88 PAG_READ |
89 PAG_COMMIT);
90 if (rc != NO_ERROR) /* check if the allocation failed */
91 return (rc); /* signal error */
92
93 ulReadSize = fs3Status.cbFile;
94
95 rc = DosOpen(pszFile, /* File path name */
96 &hFileInput, /* File handle */
97 &ulAction, /* Action taken */
98 0L, /* File primary allocation */
99 FILE_ARCHIVED |
100 FILE_NORMAL, /* File attribute */
101 OPEN_ACTION_FAIL_IF_NEW |
102 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
103 OPEN_FLAGS_NOINHERIT |
104 OPEN_FLAGS_SEQUENTIAL|
105 OPEN_SHARE_DENYNONE |
106 OPEN_ACCESS_READONLY, /* Open mode of the file */
107 0L); /* No extended attribute */
108 if (rc == NO_ERROR) /* check for errors */
109 {
110 ULONG ulRead; /* number of read bytes */
111
112 rc = DosRead (hFileInput,
113 *ppBuffer,
114 ulReadSize,
115 &ulRead);
116
117 DosClose (hFileInput); /* close the filehandle in any case */
118 }
119
120 if (rc != NO_ERROR) /* check for errors */
121 {
122 DosFreeMem (*ppBuffer); /* free the allocated memory */
123 *ppBuffer = NULL; /* reset the passed back values */
124 *pulBuffer = 0;
125 }
126
127 return (rc); /* return code */
128}
129
130
131
132
133LXSymbolFile::LXSymbolFile(PSZ _pszName, PSZ _pszFileName)
134{
135 pszName = strdup(_pszName); // copy lookup name
136 pszFileName = strdup(_pszFileName);
137 pszErrorMessage = NULL;
138}
139
140
141LXSymbolFile::~LXSymbolFile()
142{
143 if (pszName)
144 free(pszName);
145
146 if (pszErrorMessage)
147 free(pszErrorMessage);
148
149 if (pszFileName)
150 free(pszFileName);
151
152 if (pSymbolRawData)
153 DosFreeMem (pSymbolRawData);
154}
155
156
157void LXSymbolFile::setErrorMessage(PSZ _pszErrorMessage)
158{
159 if (pszErrorMessage)
160 free(pszErrorMessage);
161
162 if (NULL != _pszErrorMessage)
163 pszErrorMessage = strdup(_pszErrorMessage);
164 else
165 pszErrorMessage = NULL;
166}
167
168
169APIRET LXSymbolFile::parseFile()
170{
171 APIRET rc;
172 ULONG ulBufferSize;
173
174 // 1 - read file to buffer
175 rc = ToolsReadFileToBuffer(pszFileName,
176 (PPVOID)&pSymbolRawData,
177 &ulBufferSize);
178 if (NO_ERROR != rc)
179 {
180 setErrorMessage("unable to read file");
181 return rc;
182 }
183
184 return NO_ERROR;
185}
186
187
188BOOL LXSymbolFile::isAvailable()
189{
190 return pszErrorMessage == NULL;
191}
192
193
194PSZ LXSymbolFile::getErrorMessage()
195{
196 return pszErrorMessage;
197}
198
199
200PSZ LXSymbolFile::getFileName()
201{
202 return pszFileName;
203}
204
205
206BOOL LXSymbolFile::getSymbolName(ULONG objNr,
207 ULONG offset,
208 PSZ pszNameBuffer,
209 ULONG ulNameBufferLength)
210{
211 PUCHAR p = (PUCHAR)pSymbolRawData;
212 ULONG ulMapDefs;
213 PMAPDEF pMapDef;
214 ULONG SegOffset;
215 ULONG SymOffset;
216 ULONG ulSegNum;
217 ULONG ulSymNum;
218 SEGDEF* pSegDef;
219 SYMDEF32* pSymDef32;
220
221 // scan through the maps
222 pMapDef = (PMAPDEF)p;
223 for (ulMapDefs = 0;
224 pMapDef->ppNextMap != 0;
225 ulMapDefs++)
226 {
227 SegOffset = pMapDef->ppSegDef * 16;
228
229 for (ulSegNum = 0;
230 ulSegNum < pMapDef->cSegs;
231 ulSegNum++)
232 {
233 pSegDef = (PSEGDEF)(p + SegOffset);
234
235 // check for the segment number
236 if (ulSegNum == objNr)
237 {
238 PSYMDEF32 pSymClosest = NULL;
239
240 // lookup the symbol
241 for (ulSymNum = 0;
242 ulSymNum < pSegDef->cSymbols;
243 ulSymNum++)
244 {
245 /* calculate symbol offset */
246 PUCHAR pucTemp = ( (PUCHAR)pSegDef +
247 pSegDef->pSymDef +
248 ulSymNum * sizeof(USHORT) );
249 SymOffset = *(PUSHORT)pucTemp;
250 pucTemp = (PUCHAR)pSegDef + SymOffset;
251
252 if (pSegDef->bFlags & 0x01)
253 {
254 // 32-bit segment
255 pSymDef32 = (PSYMDEF32)pucTemp;
256
257 if (NULL == pSymClosest)
258 pSymClosest = pSymDef32;
259 else
260 {
261 int iClosest = offset - pSymClosest->wSymVal;
262 int iCurrent = offset - pSymDef32->wSymVal;
263
264 // find nearest symbol to the given offset
265 if (iCurrent > 0)
266 if (iClosest < iCurrent)
267 pSymClosest = pSymDef32;
268 }
269
270 // check if we've found it (or get the closest symbol)
271 if (offset == pSymDef32->wSymVal)
272 {
273 int iLen = min(pSymDef32->cbSymName, ulNameBufferLength);
274 memcpy(pszNameBuffer,
275 pSymDef32->achSymName,
276 iLen);
277
278 // terminate the string in any case
279 pszNameBuffer[iLen] = 0;
280
281 // OK, found
282 return TRUE;
283 }
284 }
285 else
286 {
287 // 16-bit segment
288 // @@@PH not supported
289 }
290 } /* symbol lookup */
291
292 if (NULL != pSymClosest)
293 {
294 CHAR szBuf[128];
295 CHAR szBuf2[128];
296 int iLen;
297
298 // proper symbol name found?
299 if ( (pSymClosest->achSymName[0] > 32) &&
300 (pSymClosest->cbSymName < 255) )
301 {
302 memcpy(szBuf, pSymClosest->achSymName, sizeof(szBuf));
303 szBuf[ sizeof(szBuf) ] = 0;
304 sprintf(szBuf2, "%s+%0xh", szBuf, offset - pSymClosest->wSymVal);
305 iLen = min(pSymClosest->cbSymName, ulNameBufferLength);
306 }
307 else
308 {
309 sprintf(szBuf2, "%s:obj%d:%08xh", getName(), objNr, offset);
310 iLen = min(strlen(szBuf2), ulNameBufferLength);
311 }
312
313 memcpy(pszNameBuffer, szBuf2, iLen);
314 pszNameBuffer[iLen] = 0; // terminate the string in any case
315 return TRUE; // at least something usable has been found!
316 }
317 else
318 {
319 // nothing usable was found
320 return FALSE;
321 }
322 }
323
324 SegOffset = (pSegDef->ppNextSeg * 16);
325 } /* segment loop */
326
327 p += (pMapDef->ppNextMap * 16);
328 pMapDef = (PMAPDEF)p;
329 } /* map loop */
330
331 // not found
332 return FALSE;
333}
334
335
336
337
338
339SymbolFilePool::SymbolFilePool()
340{
341 pHashModules = new CHashtableLookup(67);
342}
343
344
345SymbolFilePool::~SymbolFilePool()
346{
347 if (pHashModules)
348 delete pHashModules;
349}
350
351
352APIRET SymbolFilePool::searchModule(PSZ pszModule, PBYTE pBuffer, ULONG ulBufferLength)
353{
354 // 1 - build symbol filename
355 CHAR szSymFile[260];
356
357 strcpy(szSymFile, pszModule);
358 PSZ pszDot = strrchr(szSymFile, '.');
359 if (NULL == pszDot)
360 pszDot = szSymFile + strlen(szSymFile);
361
362 strcpy(pszDot, ".sym");
363
364 // 2 - search path for symbol files
365 // and copy result to pszFilename
366 APIRET rc = DosSearchPath(SEARCH_IGNORENETERRS |
367 SEARCH_ENVIRONMENT |
368 SEARCH_CUR_DIRECTORY,
369 "PATH",
370 szSymFile,
371 pBuffer,
372 ulBufferLength);
373 if ( (rc == ERROR_FILE_NOT_FOUND) ||
374 (rc == ERROR_ENVVAR_NOT_FOUND) )
375 rc = DosSearchPath(SEARCH_IGNORENETERRS |
376 SEARCH_ENVIRONMENT |
377 SEARCH_CUR_DIRECTORY,
378 "DPATH",
379 szSymFile,
380 pBuffer,
381 ulBufferLength);
382
383 return rc;
384}
385
386
387
388BOOL SymbolFilePool::getSymbolName(PSZ pszModule,
389 ULONG objNr,
390 ULONG offset,
391 PSZ pszNameBuffer,
392 ULONG ulNameBufferLength)
393{
394 LXSymbolFile* pSym = (LXSymbolFile*)pHashModules->getElement(pszModule);
395 if (NULL == pSym)
396 {
397 CHAR szFilename[260];
398
399 // 1 - locate the file
400 APIRET rc = searchModule(pszModule, szFilename, sizeof(szFilename));
401
402 // create new entry
403 pSym = new LXSymbolFile(pszModule, szFilename);
404
405 // parse the file
406 if (rc == NO_ERROR)
407 pSym->parseFile();
408 else
409 pSym->setErrorMessage("file not found");
410
411 // add to the hashtable
412 pHashModules->addElement(pszModule, pSym);
413 }
414
415 BOOL rc;
416
417 // if the parsed symbol table is correct, lookup the symbol
418 if (pSym->isAvailable())
419 {
420 rc = pSym->getSymbolName(objNr,
421 offset,
422 pszNameBuffer,
423 ulNameBufferLength);
424
425 if (rc == TRUE)
426 {
427 // check if we can demangle a C++ name
428 char* rest;
429 Name* name = Demangle(pszNameBuffer, rest);
430 if (name != NULL)
431 {
432 strncpy(pszNameBuffer,
433 name->Text(),
434 ulNameBufferLength);
435
436 delete name;
437 }
438 }
439 }
440 else
441 rc = FALSE;
442
443 return rc;
444}
445
Note: See TracBrowser for help on using the repository browser.