source: trunk/src/odinprof/symfile.cpp

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

.

File size: 14.3 KB
Line 
1/* $Id: symfile.cpp,v 1.3 2001-11-22 13:35:42 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 */
20
21
22/****************************************************************************
23 * includes
24 ****************************************************************************/
25
26#define INCL_DOSERRORS
27#define INCL_DOSPROCESS
28#define INCL_DOSMISC
29#define INCL_DOSFILEMGR
30#include <os2.h>
31
32#include <os2sel.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdio.h>
36#include <demangle.h>
37
38#include "profcollection.h"
39#include "symfile.h"
40
41
42/****************************************************************************
43 * implementation
44 ****************************************************************************/
45
46/*****************************************************************************
47 * Name : APIRET ReadFileToBuffer
48 * Funktion : Reads a single file completely into a memory buffer
49 * Parameter : PSZ pszFile, PPVOID ppBuffer, PULONG pulBuffer
50 * Variablen :
51 * Ergebnis : API-Returncode
52 * Bemerkung :
53 *
54 * Autor : Patrick Haller [Samstag, 07.10.1995 03.22.44]
55 *****************************************************************************/
56
57APIRET ToolsReadFileToBuffer (PSZ pszFile,
58 PPVOID ppBuffer,
59 PULONG pulBuffer)
60{
61 APIRET rc; /* API-Returncode */
62 FILESTATUS3 fs3Status; /* Dateiinformationen */
63 HFILE hFileInput; /* input file handle */
64 ULONG ulAction; /* dummy parameter for DosOpen */
65 ULONG ulReadSize; /* number of bytes to read per call */
66 ULONG ulReadTotal = 0; /* total number of bytes read */
67
68 if ( (pszFile == NULL) || /* check parameters */
69 (ppBuffer == NULL) ||
70 (pulBuffer == NULL) )
71 return (ERROR_INVALID_PARAMETER); /* signal error */
72
73
74 rc = DosQueryPathInfo (pszFile, /* Infos einholen */
75 FIL_STANDARD,
76 &fs3Status,
77 sizeof(fs3Status));
78 if (rc != NO_ERROR) /* check if an error occured */
79 return (rc); /* signal error */
80
81 /* allocate buffer RAM for the file */
82 *pulBuffer = fs3Status.cbFile; /* return the size of the file */
83 rc = DosAllocMem(ppBuffer, /* allocate the buffer */
84 fs3Status.cbFile,
85 PAG_WRITE |
86 PAG_READ |
87 PAG_COMMIT);
88 if (rc != NO_ERROR) /* check if the allocation failed */
89 return (rc); /* signal error */
90
91 ulReadSize = fs3Status.cbFile;
92
93 rc = DosOpen(pszFile, /* File path name */
94 &hFileInput, /* File handle */
95 &ulAction, /* Action taken */
96 0L, /* File primary allocation */
97 FILE_ARCHIVED |
98 FILE_NORMAL, /* File attribute */
99 OPEN_ACTION_FAIL_IF_NEW |
100 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
101 OPEN_FLAGS_NOINHERIT |
102 OPEN_FLAGS_SEQUENTIAL|
103 OPEN_SHARE_DENYNONE |
104 OPEN_ACCESS_READONLY, /* Open mode of the file */
105 0L); /* No extended attribute */
106 if (rc == NO_ERROR) /* check for errors */
107 {
108 ULONG ulRead; /* number of read bytes */
109
110 rc = DosRead (hFileInput,
111 *ppBuffer,
112 ulReadSize,
113 &ulRead);
114
115 DosClose (hFileInput); /* close the filehandle in any case */
116 }
117
118 if (rc != NO_ERROR) /* check for errors */
119 {
120 DosFreeMem (*ppBuffer); /* free the allocated memory */
121 *ppBuffer = NULL; /* reset the passed back values */
122 *pulBuffer = 0;
123 }
124
125 return (rc); /* return code */
126}
127
128
129
130
131LXSymbolFile::LXSymbolFile(PSZ _pszName, PSZ _pszFileName)
132{
133 pszName = strdup(_pszName); // copy lookup name
134 pszFileName = strdup(_pszFileName);
135 pszErrorMessage = NULL;
136}
137
138
139LXSymbolFile::~LXSymbolFile()
140{
141 if (pszName)
142 free(pszName);
143
144 if (pszErrorMessage)
145 free(pszErrorMessage);
146
147 if (pszFileName)
148 free(pszFileName);
149
150 if (pSymbolRawData)
151 DosFreeMem (pSymbolRawData);
152}
153
154
155void LXSymbolFile::setErrorMessage(PSZ _pszErrorMessage)
156{
157 if (pszErrorMessage)
158 free(pszErrorMessage);
159
160 if (NULL != _pszErrorMessage)
161 pszErrorMessage = strdup(_pszErrorMessage);
162 else
163 pszErrorMessage = NULL;
164}
165
166
167APIRET LXSymbolFile::parseFile()
168{
169 APIRET rc;
170 ULONG ulBufferSize;
171
172 // 1 - read file to buffer
173 rc = ToolsReadFileToBuffer(pszFileName,
174 (PPVOID)&pSymbolRawData,
175 &ulBufferSize);
176 if (NO_ERROR != rc)
177 {
178 setErrorMessage("unable to read file");
179 return rc;
180 }
181
182 return NO_ERROR;
183}
184
185
186BOOL LXSymbolFile::isAvailable()
187{
188 return pszErrorMessage == NULL;
189}
190
191
192PSZ LXSymbolFile::getErrorMessage()
193{
194 return pszErrorMessage;
195}
196
197
198PSZ LXSymbolFile::getFileName()
199{
200 return pszFileName;
201}
202
203
204BOOL LXSymbolFile::getSymbolName(ULONG objNr,
205 ULONG offset,
206 PSZ pszNameBuffer,
207 ULONG ulNameBufferLength,
208 PULONG pulSymbolOffset)
209{
210 PUCHAR p = (PUCHAR)pSymbolRawData;
211 ULONG ulMapDefs;
212 PMAPDEF pMapDef;
213 ULONG SegOffset;
214 ULONG SymOffset;
215 ULONG ulSegNum;
216 ULONG ulSymNum;
217 SEGDEF* pSegDef;
218 SYMDEF32* pSymDef32;
219
220 // scan through the maps
221 pMapDef = (PMAPDEF)p;
222 for (ulMapDefs = 0;
223 pMapDef->ppNextMap != 0;
224 ulMapDefs++)
225 {
226 SegOffset = pMapDef->ppSegDef * 16;
227
228 for (ulSegNum = 0;
229 ulSegNum < pMapDef->cSegs;
230 ulSegNum++)
231 {
232 pSegDef = (PSEGDEF)(p + SegOffset);
233
234 // check for the segment number
235 if (ulSegNum == objNr)
236 {
237 PSYMDEF32 pSymClosest = NULL;
238
239 // lookup the symbol
240 for (ulSymNum = 0;
241 ulSymNum < pSegDef->cSymbols;
242 ulSymNum++)
243 {
244 /* calculate symbol offset */
245 PUCHAR pucTemp = ( (PUCHAR)pSegDef +
246 pSegDef->pSymDef +
247 ulSymNum * sizeof(USHORT) );
248 SymOffset = *(PUSHORT)pucTemp;
249 pucTemp = (PUCHAR)pSegDef + SymOffset;
250
251 if (pSegDef->bFlags & 0x01)
252 {
253 // 32-bit segment
254 pSymDef32 = (PSYMDEF32)pucTemp;
255
256 if (NULL == pSymClosest)
257 pSymClosest = pSymDef32;
258 else
259 {
260 int iClosest = offset - pSymClosest->wSymVal;
261 int iCurrent = offset - pSymDef32->wSymVal;
262
263 // find nearest symbol to the given offset
264 if (iCurrent > 0)
265 if (iClosest > iCurrent)
266 pSymClosest = pSymDef32;
267 }
268
269 // check if we've found it (or get the closest symbol)
270 if (offset == pSymDef32->wSymVal)
271 {
272 int iLen = min(pSymDef32->cbSymName, ulNameBufferLength);
273 memcpy(pszNameBuffer,
274 pSymDef32->achSymName,
275 iLen);
276
277 // terminate the string in any case
278 pszNameBuffer[iLen] = 0;
279 *pulSymbolOffset = 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 int iLen;
296
297 // proper symbol name found?
298 if ( (pSymClosest->achSymName[0] > 32) &&
299 (pSymClosest->cbSymName < 255) )
300 {
301 memcpy(szBuf, pSymClosest->achSymName, sizeof(szBuf));
302 szBuf[ min(sizeof(szBuf), pSymClosest->cbSymName) ] = 0;
303 iLen = min(strlen(szBuf), ulNameBufferLength);
304 }
305 else
306 {
307 sprintf(szBuf, "%s:obj%d:%08xh", getName(), objNr, offset);
308 iLen = min(strlen(szBuf), ulNameBufferLength);
309 }
310
311 memcpy(pszNameBuffer, szBuf, iLen);
312 pszNameBuffer[iLen] = 0; // terminate the string in any case
313 *pulSymbolOffset = offset - pSymClosest->wSymVal;
314 return TRUE; // at least something usable has been found!
315 }
316 else
317 {
318 // nothing usable was found
319 return FALSE;
320 }
321 }
322
323 SegOffset = (pSegDef->ppNextSeg * 16);
324 } /* segment loop */
325
326 p += (pMapDef->ppNextMap * 16);
327 pMapDef = (PMAPDEF)p;
328 } /* map loop */
329
330 // not found
331 return FALSE;
332}
333
334
335
336
337
338SymbolFilePool::SymbolFilePool()
339{
340 pHashModules = new CHashtableLookup(67);
341}
342
343
344SymbolFilePool::~SymbolFilePool()
345{
346 if (pHashModules)
347 delete pHashModules;
348}
349
350
351APIRET SymbolFilePool::searchModule(PSZ pszModule, PBYTE pBuffer, ULONG ulBufferLength)
352{
353 // 1 - build symbol filename
354 CHAR szSymFile[260];
355
356 strcpy(szSymFile, pszModule);
357 PSZ pszDot = strrchr(szSymFile, '.');
358 if (NULL == pszDot)
359 pszDot = szSymFile + strlen(szSymFile);
360
361 strcpy(pszDot, ".sym");
362
363 // 2 - search path for symbol files
364 // and copy result to pszFilename
365 APIRET rc = DosSearchPath(SEARCH_IGNORENETERRS |
366 SEARCH_ENVIRONMENT |
367 SEARCH_CUR_DIRECTORY,
368 "PATH",
369 szSymFile,
370 pBuffer,
371 ulBufferLength);
372 if ( (rc == ERROR_FILE_NOT_FOUND) ||
373 (rc == ERROR_ENVVAR_NOT_FOUND) )
374 rc = DosSearchPath(SEARCH_IGNORENETERRS |
375 SEARCH_ENVIRONMENT |
376 SEARCH_CUR_DIRECTORY,
377 "DPATH",
378 szSymFile,
379 pBuffer,
380 ulBufferLength);
381
382 return rc;
383}
384
385
386
387BOOL SymbolFilePool::getSymbolName(PSZ pszModule,
388 ULONG objNr,
389 ULONG offset,
390 PSZ pszNameBuffer,
391 ULONG ulNameBufferLength,
392 PULONG pulSymbolOffset)
393{
394 LXSymbolFile* pSym = (LXSymbolFile*)pHashModules->getElement(pszModule);
395 if (NULL == pSym)
396 {
397 DosEnterCritSec();
398
399 // try again since someone else could have loaded the map already
400 pSym = (LXSymbolFile*)pHashModules->getElement(pszModule);
401 if (NULL == pSym)
402 {
403 CHAR szFilename[260];
404
405 // 1 - locate the file
406 APIRET rc = searchModule(pszModule, szFilename, sizeof(szFilename));
407
408 // create new entry
409 pSym = new LXSymbolFile(pszModule, szFilename);
410
411 // parse the file
412 if (rc == NO_ERROR)
413 pSym->parseFile();
414 else
415 pSym->setErrorMessage("file not found");
416
417 // add to the hashtable
418 PSZ pszCopyOfModuleName = strdup(pszModule);
419 pHashModules->addElement(pszCopyOfModuleName, pSym);
420 }
421
422 DosExitCritSec();
423 }
424
425 BOOL rc;
426
427 // if the parsed symbol table is correct, lookup the symbol
428 if (pSym->isAvailable())
429 {
430 rc = pSym->getSymbolName(objNr,
431 offset,
432 pszNameBuffer,
433 ulNameBufferLength,
434 pulSymbolOffset);
435
436 if (rc == TRUE)
437 {
438 // check if we can demangle a C++ name
439 char* rest;
440 Name* name = Demangle(pszNameBuffer, rest);
441 if (name != NULL)
442 {
443 strncpy(pszNameBuffer,
444 name->Text(),
445 ulNameBufferLength);
446 delete name;
447 }
448
449 // append symbol offsets
450 if (*pulSymbolOffset != 0)
451 {
452 CHAR szBuf[256];
453 sprintf(szBuf,
454 "%s+%xh",
455 pszNameBuffer,
456 *pulSymbolOffset);
457 strncpy(pszNameBuffer,
458 szBuf,
459 ulNameBufferLength);
460 }
461 }
462 }
463 else
464 rc = FALSE;
465
466 return rc;
467}
468
469
470static int _Optlink sortHashtableSYMs(const void *arg1,const void *arg2)
471{
472 PHASHTABLEENTRY pHTE1 = (PHASHTABLEENTRY)arg1;
473 PHASHTABLEENTRY pHTE2 = (PHASHTABLEENTRY)arg2;
474
475 LXSymbolFile* p1 = (LXSymbolFile*)pHTE1->pObject;
476 LXSymbolFile* p2 = (LXSymbolFile*)pHTE2->pObject;
477
478 return stricmp(p1->getName(), p2->getName());
479}
480
481
482void SymbolFilePool::printSYMs(FILE *file)
483{
484 int iEntries = pHashModules->getNumberOfElements();
485
486 // get a list of all entries of the hashtable
487 PHASHTABLEENTRY arrEntries = (PHASHTABLEENTRY)malloc( iEntries * sizeof(HASHTABLEENTRY) );
488 iEntries = pHashModules->getElementMap(arrEntries);
489
490 fprintf(file,
491 "\nSymbolic debug information maps (%d maps)\n",
492 iEntries);
493
494 // sort the list by name
495 qsort(arrEntries,
496 iEntries,
497 sizeof( HASHTABLEENTRY ),
498 sortHashtableSYMs);
499
500 // write to file
501 fprintf(file,
502 "Module ---- Status --------------------------------------------------------\n");
503 for(int i = 0;
504 i < iEntries;
505 i++)
506 {
507 LXSymbolFile* p = (LXSymbolFile*)arrEntries[i].pObject;
508 fprintf(file,
509 "%-10s %s (%s)\n",
510 p->getName(),
511 p->getFileName(),
512 (p->getErrorMessage() != NULL) ? p->getErrorMessage() : "");
513 }
514}
Note: See TracBrowser for help on using the repository browser.