Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

752 lines
20 KiB

  1. /********************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. symres.cpp
  5. Abstract:
  6. Symbol translator main file
  7. implements symbol translator function in DLL
  8. takes a callstack entry as input, and resolves symbol name
  9. Revision History:
  10. Brijesh Krishnaswami (brijeshk) - 04/29/99 - Created
  11. ********************************************************************/
  12. #include <windows.h>
  13. #include <dbgtrace.h>
  14. #include <traceids.h>
  15. #include <list>
  16. #include "symdef.h"
  17. #include <imagehlp.h>
  18. // for trace output to include filename
  19. #ifdef THIS_FILE
  20. #undef THIS_FILE
  21. #endif
  22. static char __szTraceSourceFile[]=__FILE__;
  23. #define THIS_FILE __szTraceSourceFile
  24. #define TRACE_ID SYMRESMAINID
  25. // global variable that stores thread local storage index
  26. DWORD g_dwTlsIndex;
  27. // location of sym files repository and log file
  28. WCHAR g_szwSymDir[MAX_PATH];
  29. WCHAR g_szwLogFile[MAX_PATH];
  30. // strip off path and extension from filename
  31. void
  32. SplitExtension(
  33. LPWSTR szwFullname, // [in] full name
  34. LPWSTR szwName, // [out] name part
  35. LPWSTR szwExt // [out] extension part
  36. )
  37. {
  38. LPWSTR plast = NULL;
  39. LPWSTR pfront = NULL;
  40. TraceFunctEnter("SplitExtension");
  41. if (pfront = wcsrchr(szwFullname, L'\\'))
  42. {
  43. pfront++;
  44. lstrcpyW(szwName,pfront);
  45. }
  46. else
  47. {
  48. lstrcpyW(szwName,szwFullname);
  49. }
  50. if (plast = wcsrchr(szwName, L'.'))
  51. {
  52. *plast = L'\0';
  53. plast++;
  54. lstrcpyW(szwExt,plast);
  55. }
  56. else
  57. {
  58. lstrcpyW(szwExt, L"");
  59. }
  60. TraceFunctLeave();
  61. }
  62. // undecorate symbol name
  63. void
  64. UndecorateSymbol(
  65. LPTSTR szSymbol // [in] [out] function name undecorated in place
  66. )
  67. {
  68. TCHAR szTemp[MAX_PATH];
  69. PIMAGEHLP_SYMBOL pihsym;
  70. DWORD dwSize;
  71. TraceFunctEnter("UndecorateSymbol");
  72. dwSize = sizeof(IMAGEHLP_SYMBOL)+MAX_PATH;
  73. pihsym = (IMAGEHLP_SYMBOL *) new BYTE[dwSize];
  74. if (pihsym)
  75. {
  76. pihsym->SizeOfStruct = dwSize;
  77. pihsym->Address = 0;
  78. pihsym->Flags = 0;
  79. pihsym->MaxNameLength = MAX_PATH;
  80. lstrcpy(pihsym->Name,szSymbol);
  81. SymUnDName(pihsym,szTemp,MAX_PATH);
  82. lstrcpy(szSymbol,szTemp);
  83. delete [] pihsym;
  84. }
  85. else
  86. {
  87. ErrorTrace(TRACE_ID, "Cannot allocate memory");
  88. }
  89. TraceFunctLeave();
  90. }
  91. // select file from list of open files, or open and add to list
  92. // maintain files in usage order, least recently used at end of list
  93. OPENFILE* // pointer to open file info
  94. GetFile(
  95. LPWSTR szwModule // [in] name of file
  96. )
  97. {
  98. OPENFILE* pFile = NULL;
  99. OPENFILE* pLast = NULL;
  100. MAPDEF map;
  101. DWORD dwCread;
  102. std::list<OPENFILE *> * pOpenFilesList = NULL;
  103. std::list<OPENFILE *>::iterator it;
  104. TCHAR szTarget[MAX_PATH + MAX_PATH];
  105. TraceFunctEnter("GetFile");
  106. // get file list pointer from thread local storage
  107. pOpenFilesList = (std::list<OPENFILE *> *) TlsGetValue(g_dwTlsIndex);
  108. if (NO_ERROR != GetLastError() || !pOpenFilesList)
  109. {
  110. ErrorTrace(TRACE_ID, "Error reading TLS");
  111. goto exit;
  112. }
  113. // search open list to see if file is already open
  114. it = pOpenFilesList->begin();
  115. while (it != pOpenFilesList->end())
  116. {
  117. if (!lstrcmpiW((*it)->szwName,szwModule))
  118. {
  119. // move the file to the beginning of list
  120. // so that the LRU file is at the end
  121. pFile = *it;
  122. pOpenFilesList->erase(it);
  123. pOpenFilesList->push_front(pFile);
  124. break;
  125. }
  126. it++;
  127. }
  128. if (it == pOpenFilesList->end()) // not open, so open and store handle
  129. {
  130. pFile = new OPENFILE;
  131. if (!pFile)
  132. {
  133. ErrorTrace(TRACE_ID, "Cannot allocate memory");
  134. goto exit;
  135. }
  136. // open SYM file
  137. pFile->hfFile = CreateFileW(szwModule,
  138. GENERIC_READ,
  139. FILE_SHARE_READ,
  140. NULL,
  141. OPEN_EXISTING,
  142. FILE_ATTRIBUTE_NORMAL,
  143. NULL);
  144. if (INVALID_HANDLE_VALUE == pFile->hfFile)
  145. {
  146. ErrorTrace(TRACE_ID,"Error opening file %ls",szwModule);
  147. delete pFile;
  148. pFile = NULL;
  149. goto exit;
  150. }
  151. // copy filename and version into pFile node
  152. lstrcpyW(pFile->szwName, szwModule);
  153. // read map definition
  154. ReadFile(pFile->hfFile, &map, sizeof(MAPDEF)-1, &dwCread, NULL);
  155. if (dwCread != sizeof(MAPDEF)-1)
  156. {
  157. ErrorTrace(TRACE_ID, "Error reading file");
  158. delete pFile;
  159. pFile = NULL;
  160. goto exit;
  161. }
  162. pFile->ulFirstSeg = map.md_spseg*16;
  163. pFile->nSeg = map.md_cseg;
  164. pFile->psCurSymDefPtrs = NULL;
  165. pOpenFilesList->push_front(pFile);
  166. }
  167. // maintain at most MAXOPENFILES open files
  168. if (pOpenFilesList->size() > MAXOPENFILES)
  169. {
  170. // close last file in list
  171. pLast = pOpenFilesList->back();
  172. if (pLast)
  173. {
  174. CloseHandle(pLast->hfFile);
  175. if (pLast->psCurSymDefPtrs)
  176. {
  177. delete [] pLast->psCurSymDefPtrs;
  178. pLast->psCurSymDefPtrs = NULL;
  179. }
  180. delete pLast;
  181. pOpenFilesList->pop_back();
  182. }
  183. else // something is amiss here
  184. {
  185. FatalTrace(TRACE_ID,"Error reading open files list");
  186. goto exit;
  187. }
  188. }
  189. exit:
  190. TraceFunctLeave();
  191. return pFile;
  192. }
  193. // read segment defintion for dwSection
  194. ULONG // return offset of segment definition, 0 if failed
  195. GetSegDef(
  196. OPENFILE* pFile, // [in] pointer to open file info
  197. DWORD dwSection, // [in] section number
  198. SEGDEF* pSeg // [out] pointer to segment definition
  199. )
  200. {
  201. ULONG ulCurSeg = pFile->ulFirstSeg;
  202. int iSectionIndex = 0;
  203. DWORD dwCread;
  204. TraceFunctEnter("GetSegDef");
  205. // step through segments
  206. while (iSectionIndex < pFile->nSeg)
  207. {
  208. // go to segment beginning
  209. if (SetFilePointer(pFile->hfFile, ulCurSeg, NULL, FILE_BEGIN) == 0xFFFFFFFF)
  210. {
  211. ErrorTrace(TRACE_ID, "Cannot set file pointer");
  212. ulCurSeg = 0;
  213. break;
  214. }
  215. // read seg defn
  216. if (!ReadFile(pFile->hfFile, pSeg, sizeof(SEGDEF)-1, &dwCread, NULL))
  217. {
  218. ErrorTrace(TRACE_ID, "Cannot read segment definition");
  219. ulCurSeg = 0;
  220. break;
  221. }
  222. iSectionIndex++;
  223. if (iSectionIndex == dwSection) // gotcha
  224. {
  225. break;
  226. }
  227. // go to next segment definition
  228. ulCurSeg = pSeg->gd_spsegnext*16;
  229. }
  230. // found our section and it's non-empty?
  231. if (iSectionIndex != dwSection || !pSeg->gd_csym) // no
  232. {
  233. ulCurSeg = 0;
  234. }
  235. TraceFunctLeave();
  236. return ulCurSeg;
  237. }
  238. // parse sym file to resolve address
  239. void
  240. GetNameFromAddr(
  241. LPWSTR szwModule, // [in] name of symbol file
  242. DWORD dwSection, // [in] section part of address to resolve
  243. UINT_PTR offset, // [in] offset part of address to resolve
  244. LPWSTR szwFuncName // [out] resolved function name,
  245. ) // "<no symbols>" otherwise
  246. {
  247. SEGDEF seg;
  248. DWORD dwSymAddr;
  249. LPTSTR szMapName;
  250. LPTSTR szSegName;
  251. TCHAR szSymName[MAX_NAME+1];
  252. TCHAR szPrevName[MAX_NAME+1];
  253. TCHAR sztFuncName[MAX_NAME+1];
  254. int i;
  255. int j;
  256. int nNameLen;
  257. DWORD dwCread;
  258. int iSectionIndex;
  259. int nToRead;
  260. unsigned char cName;
  261. ULONG ulCurSeg;
  262. ULONG ulSymNameOffset;
  263. ULONG ulPrevNameOffset;
  264. OPENFILE* pFile = NULL;
  265. HANDLE hfFile;
  266. FILE* fDump = NULL;
  267. BOOL fSuccess = FALSE;
  268. HANDLE hfLogFile = NULL;
  269. DWORD dwWritten;
  270. TCHAR szWrite[MAX_PATH + 50];
  271. DWORD dwArrayOffset;
  272. DWORD dwSymOffset;
  273. TraceFunctEnter("GetNameFromAddr");
  274. // be pessimistic
  275. lstrcpy(sztFuncName,TEXT("<no symbol>"));
  276. // get file from open list, or open file
  277. pFile = GetFile(szwModule);
  278. if (!pFile)
  279. {
  280. ErrorTrace(TRACE_ID, "Error opening file");
  281. goto exit;
  282. }
  283. hfFile = pFile->hfFile; // for easy access
  284. if (!(ulCurSeg = GetSegDef(pFile,dwSection,&seg)))
  285. {
  286. ErrorTrace(TRACE_ID, "Cannot find section");
  287. goto exit;
  288. }
  289. // have we already read in the symbol definition offsets for this section?
  290. if (dwSection != pFile->dwCurSection || !pFile->psCurSymDefPtrs) // no
  291. {
  292. // free up previously read symdef pointers
  293. if (pFile->psCurSymDefPtrs)
  294. {
  295. delete [] pFile->psCurSymDefPtrs;
  296. pFile->psCurSymDefPtrs = NULL;
  297. }
  298. // big symbols?
  299. if (seg.gd_type & MSF_BIGSYMDEF)
  300. {
  301. dwArrayOffset = seg.gd_psymoff * 16;
  302. pFile->psCurSymDefPtrs = new BYTE[seg.gd_csym*3];
  303. }
  304. else
  305. {
  306. dwArrayOffset = seg.gd_psymoff;
  307. pFile->psCurSymDefPtrs = new BYTE[seg.gd_csym*2];
  308. }
  309. if (!pFile->psCurSymDefPtrs)
  310. {
  311. ErrorTrace(TRACE_ID, "Cannot allocate memory");
  312. goto exit;
  313. }
  314. if (SetFilePointer(hfFile,
  315. ulCurSeg + dwArrayOffset,
  316. NULL,
  317. FILE_BEGIN)
  318. == 0xFFFFFFFF)
  319. {
  320. ErrorTrace(TRACE_ID, "Cannot set file pointer");
  321. delete [] pFile->psCurSymDefPtrs;
  322. pFile->psCurSymDefPtrs = NULL;
  323. goto exit;
  324. }
  325. // read symbol definition pointers array
  326. if (!ReadFile(hfFile,
  327. pFile->psCurSymDefPtrs,
  328. seg.gd_csym * ((seg.gd_type & MSF_BIGSYMDEF)?3:2),
  329. &dwCread,
  330. NULL))
  331. {
  332. ErrorTrace(TRACE_ID, "Cannot read sym pointers array");
  333. delete [] pFile->psCurSymDefPtrs;
  334. pFile->psCurSymDefPtrs = NULL;
  335. goto exit;
  336. }
  337. // save this section
  338. pFile->dwCurSection = dwSection;
  339. }
  340. // read symbols
  341. for (i = 0; i < seg.gd_csym; i++)
  342. {
  343. // go to offset of sym defintion
  344. if (seg.gd_type & MSF_BIGSYMDEF)
  345. {
  346. dwSymOffset = pFile->psCurSymDefPtrs[i*3+0]
  347. + pFile->psCurSymDefPtrs[i*3+1]*256
  348. + pFile->psCurSymDefPtrs[i*3+2]*65536;
  349. }
  350. else
  351. {
  352. dwSymOffset = pFile->psCurSymDefPtrs[i*2+0]
  353. + pFile->psCurSymDefPtrs[i*2+1]*256;
  354. }
  355. if (SetFilePointer(hfFile,
  356. ulCurSeg + dwSymOffset,
  357. NULL,
  358. FILE_BEGIN) == 0xFFFFFFFF)
  359. {
  360. ErrorTrace(TRACE_ID, "Cannot set file pointer");
  361. goto exit;
  362. }
  363. // read symbol address DWORD
  364. if (!ReadFile(hfFile,&dwSymAddr,sizeof(DWORD),&dwCread,NULL))
  365. {
  366. ErrorTrace(TRACE_ID, "Cannot read symbol definition");
  367. goto exit;
  368. }
  369. // symbol address is 1 word or two?
  370. nToRead = sizeof(SHORT) + ((seg.gd_type & MSF_32BITSYMS) * sizeof(SHORT));
  371. // calculate offset of symbol name
  372. ulSymNameOffset = ulCurSeg + dwSymOffset + nToRead;
  373. // use just lower word of address if 16-bit symbol
  374. if (!(seg.gd_type & MSF_32BITSYMS))
  375. {
  376. dwSymAddr = dwSymAddr & 0x0000FFFF;
  377. }
  378. // do we have our function?
  379. // if current address is greater than offset, then since we are
  380. // traversing in the increasing order of addresses, the previous
  381. // symbol must be our quarry
  382. if (dwSymAddr > offset) break;
  383. // store previous name offset
  384. ulPrevNameOffset = ulSymNameOffset;
  385. }
  386. // did we get our function?
  387. // BUGBUG: cannot resolve the last symbol in a section, because we don't know
  388. // the size of the function code
  389. // if offset > dwSymAddr of last symbol, then we cannot decide if offset belonged
  390. // to last symbol or was beyond it - so assume <no symbol>
  391. if (i < seg.gd_csym)
  392. {
  393. // go to name offset
  394. if (SetFilePointer(hfFile,
  395. ulPrevNameOffset,
  396. NULL,
  397. FILE_BEGIN)
  398. == 0xFFFFFFFF)
  399. {
  400. ErrorTrace(TRACE_ID, "Error setting file pointer");
  401. goto exit;
  402. }
  403. // read length of name
  404. if (!ReadFile(hfFile,&cName,sizeof(TCHAR),&dwCread,NULL))
  405. {
  406. ErrorTrace(TRACE_ID, "Error reading length of name");
  407. goto exit;
  408. }
  409. nNameLen = (int) cName;
  410. // read symbol name
  411. if (!ReadFile(hfFile,sztFuncName,nNameLen,&dwCread,NULL))
  412. {
  413. ErrorTrace(TRACE_ID, "Error reading name");
  414. goto exit;
  415. }
  416. sztFuncName[nNameLen] = TCHAR('\0');
  417. UndecorateSymbol(sztFuncName);
  418. fSuccess = TRUE;
  419. }
  420. exit:
  421. if (!MultiByteToWideChar(CP_ACP, 0, sztFuncName, -1, szwFuncName, MAX_PATH))
  422. {
  423. lstrcpyW(szwFuncName, L"<no symbol>");
  424. }
  425. // log unresolved symbols to log file (filename read from registry)
  426. // file write operation is not wrapped in a mutex
  427. // for speed considerations
  428. if (!fSuccess)
  429. {
  430. hfLogFile = CreateFileW(g_szwLogFile,
  431. GENERIC_WRITE,
  432. 0,
  433. NULL,
  434. OPEN_ALWAYS,
  435. FILE_ATTRIBUTE_NORMAL,
  436. NULL);
  437. if (INVALID_HANDLE_VALUE != hfLogFile)
  438. {
  439. wsprintf(szWrite, "\n%ls %04X:%08X", szwModule, dwSection, offset);
  440. if (SetFilePointer(hfLogFile, 0, NULL, FILE_END) != 0xFFFFFFFF)
  441. {
  442. WriteFile(hfLogFile, szWrite, lstrlen(szWrite), &dwWritten, NULL);
  443. }
  444. CloseHandle(hfLogFile);
  445. }
  446. }
  447. TraceFunctLeave();
  448. }
  449. // cleanup memory
  450. void
  451. Cleanup()
  452. {
  453. std::list<OPENFILE *>* pOpenFilesList = NULL;
  454. std::list<OPENFILE *>::iterator it;
  455. TraceFunctEnter("Cleanup");
  456. pOpenFilesList = (std::list<OPENFILE *> *) TlsGetValue(g_dwTlsIndex);
  457. if (!pOpenFilesList)
  458. {
  459. goto exit;
  460. }
  461. for (it = pOpenFilesList->begin(); it != pOpenFilesList->end(); it++)
  462. {
  463. if (*it)
  464. {
  465. if ((*it)->psCurSymDefPtrs)
  466. {
  467. delete [] (*it)->psCurSymDefPtrs;
  468. }
  469. if ((*it)->hfFile && (*it)->hfFile != INVALID_HANDLE_VALUE)
  470. {
  471. CloseHandle((*it)->hfFile);
  472. }
  473. delete *it;
  474. }
  475. }
  476. delete pOpenFilesList;
  477. exit:
  478. TraceFunctLeave();
  479. }
  480. BOOL
  481. HandleProcessAttach()
  482. {
  483. std::list<OPENFILE *> * pOpenFilesList = NULL;
  484. BOOL fRc = FALSE;
  485. DWORD dwType;
  486. DWORD dwSize;
  487. ULONG lResult;
  488. HKEY hKey;
  489. TraceFunctEnter("HandleProcessAttach");
  490. // allocate thread local storage
  491. if ((g_dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF)
  492. {
  493. ErrorTrace(TRACE_ID, "Cannot get TLS index");
  494. goto exit;
  495. }
  496. // create a new list of open sym files
  497. pOpenFilesList = new std::list<OPENFILE *>;
  498. if (!pOpenFilesList)
  499. {
  500. ErrorTrace(TRACE_ID, "Out of memory");
  501. goto exit;
  502. }
  503. // store pointer to list in TLS
  504. if (!TlsSetValue(g_dwTlsIndex, (PVOID) pOpenFilesList))
  505. {
  506. ErrorTrace(TRACE_ID, "Cannot write to TLS");
  507. delete pOpenFilesList;
  508. pOpenFilesList = NULL;
  509. goto exit;
  510. }
  511. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  512. TEXT("SOFTWARE\\Microsoft\\PCHealth\\Symbols"),
  513. 0,
  514. KEY_QUERY_VALUE,
  515. &hKey);
  516. // read symbol files location and name of log file from registry
  517. if(lResult == ERROR_SUCCESS)
  518. {
  519. dwSize = MAX_PATH;
  520. RegQueryValueExW(hKey,
  521. L"SymDir",
  522. NULL,
  523. NULL,
  524. (LPBYTE) g_szwSymDir,
  525. &dwSize);
  526. dwSize = MAX_PATH;
  527. RegQueryValueExW(hKey,
  528. L"LogFile",
  529. NULL,
  530. NULL,
  531. (LPBYTE) g_szwLogFile,
  532. &dwSize);
  533. RegCloseKey(hKey);
  534. fRc = TRUE;
  535. }
  536. exit:
  537. TraceFunctLeave();
  538. return fRc;
  539. }
  540. // Dll entry point
  541. // allocates TLS
  542. // initializes list of open sym files - one list per client thread
  543. // cleans up after itself
  544. BOOL APIENTRY
  545. DllMain(
  546. HANDLE hDll, // [in] handle to Dll
  547. DWORD dwReason, // [in] why DllMain is called
  548. LPVOID lpReserved // [in] ignored
  549. )
  550. {
  551. BOOL fRc = TRUE;
  552. std::list<OPENFILE*>* pOpenFilesList = NULL;
  553. switch (dwReason)
  554. {
  555. case DLL_PROCESS_ATTACH:
  556. // initial thread of process that loaded us
  557. fRc = HandleProcessAttach();
  558. break;
  559. case DLL_THREAD_ATTACH:
  560. // if list already exists, do nothing
  561. if (TlsGetValue(g_dwTlsIndex))
  562. {
  563. break;
  564. }
  565. // create new list for every new thread
  566. pOpenFilesList = new std::list<OPENFILE *>;
  567. if (!pOpenFilesList)
  568. {
  569. ErrorTrace(TRACE_ID, "Out of memory");
  570. fRc = FALSE;
  571. break;
  572. }
  573. // store pointer to list in TLS
  574. if (!TlsSetValue(g_dwTlsIndex, (PVOID) pOpenFilesList))
  575. {
  576. ErrorTrace(TRACE_ID, "Cannot write to TLS");
  577. delete pOpenFilesList;
  578. pOpenFilesList = NULL;
  579. fRc = FALSE;
  580. }
  581. break;
  582. case DLL_THREAD_DETACH:
  583. Cleanup();
  584. break;
  585. case DLL_PROCESS_DETACH:
  586. // free TLS
  587. TlsFree(g_dwTlsIndex);
  588. break;
  589. default:
  590. break;
  591. }
  592. return fRc;
  593. }
  594. // exported function
  595. // called by clients to resolve a single callstack entry
  596. extern "C" void APIENTRY
  597. ResolveSymbols(
  598. LPWSTR szwFilename,
  599. LPWSTR szwVersion,
  600. DWORD dwSection,
  601. UINT_PTR Offset,
  602. LPWSTR szwFuncName
  603. )
  604. {
  605. WCHAR szwName[MAX_PATH] = L"";
  606. WCHAR szwSymFile[MAX_PATH+MAX_PATH] = L"";
  607. WCHAR szwExt[MAX_PATH] = L"";
  608. TraceFunctEnter("ResolveSymbols");
  609. // sanity check
  610. if (!szwFilename || !szwVersion)
  611. {
  612. ErrorTrace(TRACE_ID, "No module name/version");
  613. goto exit;
  614. }
  615. // get sym file name
  616. SplitExtension(szwFilename, szwName, szwExt);
  617. wsprintfW(szwSymFile,
  618. L"%s\\%s\\%s_%s_%s.SYM",
  619. g_szwSymDir, szwName, szwName, szwExt, szwVersion);
  620. // resolve symbol name
  621. GetNameFromAddr(szwSymFile,
  622. dwSection,
  623. Offset,
  624. szwFuncName);
  625. exit:
  626. TraceFunctLeave();
  627. }