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.

523 lines
17 KiB

  1. /***
  2. *pdblkup.cpp - RTC support
  3. *
  4. * Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *
  7. *Revision History:
  8. * 07-28-98 JWM Module incorporated into CRTs (from KFrei)
  9. * 05-11-99 KBF Error if RTC support define not enabled
  10. * 05-26-99 KBF Minor Cleanup, _RTC_ prefix added to GetSrcLine
  11. * 11-30-99 PML Compile /Wp64 clean.
  12. * 06-20-00 KBF Major mods to use PDBOpenValidate3 & MSPDB70
  13. * 03-19-01 KBF Fix buffer overruns (vs7#227306), eliminate all /GS
  14. * checks (vs7#224261), use correct VS7 registry key.
  15. * 03-28-01 PML Protect against GetModuleFileName overflow (vs7#231284)
  16. *
  17. ****/
  18. #ifndef _RTC
  19. #error RunTime Check support not enabled!
  20. #endif
  21. #include "rtcpriv.h"
  22. #include <tlhelp32.h>
  23. #pragma warning(disable:4311 4312) // 32-bit specific, ignore /Wp64 warnings
  24. #define REGISTRY_KEY_MASTER HKEY_LOCAL_MACHINE
  25. #define REGISTRY_KEY_NAME "EnvironmentDirectory"
  26. #define REGISTRY_KEY_LOCATION "SOFTWARE\\Microsoft\\VisualStudio\\7.0\\Setup\\VS"
  27. static const char *mspdbName = "MSPDB70.DLL";
  28. static const mspdbNameLen = 11;
  29. // Here's some stuff from the PDB header
  30. typedef char * SZ;
  31. typedef ULONG SIG; // unique (across PDB instances) signature
  32. typedef long EC; // error code
  33. typedef USHORT ISECT; // section index
  34. typedef LONG OFF; // offset
  35. typedef LONG CB; // count of bytes
  36. typedef BYTE* PB; // pointer to some bytes
  37. struct PDB; // program database
  38. struct DBI; // debug information within the PDB
  39. struct Mod; // a module within the DBI
  40. #define pdbRead "r"
  41. // Here's some stuff from the psapi header
  42. typedef struct _MODULEINFO {
  43. LPVOID lpBaseOfDll;
  44. DWORD SizeOfImage;
  45. LPVOID EntryPoint;
  46. } MODULEINFO, *LPMODULEINFO;
  47. static HINSTANCE mspdb = 0;
  48. static HINSTANCE psapi = 0;
  49. static HINSTANCE imghlp = 0;
  50. static HINSTANCE kernel = 0;
  51. #define declare(rettype, call_type, name, parms)\
  52. extern "C" { typedef rettype ( call_type * name ## Proc) parms; }
  53. #define decldef(rettype, call_type, name, parms)\
  54. declare(rettype, call_type, name, parms)\
  55. static name ## Proc name = 0
  56. #define GetProcedure(lib, name) name = (name ## Proc)GetProcAddress(lib, #name)
  57. #define GetW9xProc(lib, name) name ## W9x = (name ## W9xProc)GetProcAddress(lib, #name)
  58. #define GetReqProcedure(lib, name, err) {if (!(GetProcedure(lib, name))) return err;}
  59. #define GetReqW9xProc(lib, name, err) {if (!(GetW9xProc(lib, name))) return err;}
  60. /* PDB functions */
  61. decldef(BOOL, __cdecl, PDBOpenValidate3,
  62. (SZ szExe, SZ szPath, OUT EC* pec, OUT SZ szError, OUT SZ szDbgPath, OUT DWORD *pfo, OUT DWORD *pcb, OUT PDB** pppdb));
  63. decldef(BOOL, __cdecl, PDBOpenDBI,
  64. (PDB* ppdb, SZ szMode, SZ szTarget, OUT DBI** ppdbi));
  65. decldef(BOOL, __cdecl, DBIQueryModFromAddr,
  66. (DBI* pdbi, ISECT isect, OFF off, OUT Mod** ppmod, OUT ISECT* pisect, OUT OFF* poff, OUT CB* pcb));
  67. decldef(BOOL, __cdecl, ModQueryLines,
  68. (Mod* pmod, PB pbLines, CB* pcb));
  69. decldef(BOOL, __cdecl, ModClose,
  70. (Mod* pmod));
  71. decldef(BOOL, __cdecl, DBIClose,
  72. (DBI* pdbi));
  73. decldef(BOOL, __cdecl, PDBClose,
  74. (PDB* ppdb));
  75. /* ImageHlp Functions */
  76. decldef(PIMAGE_NT_HEADERS, __stdcall, ImageNtHeader,
  77. (IN PVOID Base));
  78. /* PSAPI Functions */
  79. decldef(BOOL, WINAPI, GetModuleInformation,
  80. (HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb));
  81. decldef(BOOL, WINAPI, EnumProcessModules,
  82. (HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded));
  83. /* Win9X Functions */
  84. decldef(HANDLE, WINAPI, CreateToolhelp32SnapshotW9x,
  85. (DWORD dwFlags, DWORD th32ProcessID));
  86. decldef(BOOL, WINAPI, Module32FirstW9x,
  87. (HANDLE hSnapshot, LPMODULEENTRY32 lpme));
  88. decldef(BOOL, WINAPI, Module32NextW9x,
  89. (HANDLE hSnapshot, LPMODULEENTRY32 lpme));
  90. /* AdvAPI32 Functions */
  91. declare(WINADVAPI LONG, APIENTRY, RegOpenKeyExA,
  92. (HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult));
  93. declare(WINADVAPI LONG, APIENTRY, RegQueryValueExA,
  94. (HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData));
  95. declare(WINADVAPI LONG, APIENTRY, RegCloseKey,
  96. (HKEY hKey));
  97. struct ImageInfo {
  98. DWORD sig;
  99. DWORD BaseAddress;
  100. DWORD BaseSize;
  101. HMODULE hndl;
  102. PIMAGE_NT_HEADERS img;
  103. PIMAGE_SECTION_HEADER sectHdr;
  104. char *imgName;
  105. ImageInfo *next;
  106. };
  107. static ImageInfo *lImages = 0;
  108. // I do lots of assignments in conditionals intentionally
  109. #pragma warning(disable:4706)
  110. static ImageInfo *
  111. GetImageInfo(DWORD address)
  112. {
  113. ImageInfo *res, *cur;
  114. // This will not run the first time, because lImages is null
  115. for (res = lImages; res; res = res->next)
  116. {
  117. if (res->BaseAddress <= address && address - res->BaseAddress <= res->BaseSize)
  118. return res;
  119. }
  120. // We didn't find the address in the images we already know about
  121. // Let's refresh the image list, to see if it was delay-loaded
  122. // Clear out the old list
  123. while (lImages)
  124. {
  125. ImageInfo *next = lImages->next;
  126. HeapFree(GetProcessHeap(), 0, lImages);
  127. lImages = next;
  128. }
  129. if (!imghlp)
  130. {
  131. // We haven't already loaded all the DLL entrypoints we need
  132. kernel = LoadLibrary("KERNEL32.DLL");
  133. imghlp = LoadLibrary("IMAGEHLP.DLL");
  134. if (!kernel || !imghlp)
  135. return 0;
  136. GetReqProcedure(imghlp, ImageNtHeader, 0);
  137. GetW9xProc(kernel, CreateToolhelp32Snapshot);
  138. if (!CreateToolhelp32SnapshotW9x)
  139. {
  140. // We're running under WinNT, use PSAPI DLL
  141. psapi = LoadLibrary("PSAPI.DLL");
  142. if (!psapi)
  143. return 0;
  144. GetReqProcedure(psapi, EnumProcessModules, 0);
  145. GetReqProcedure(psapi, GetModuleInformation, 0);
  146. } else
  147. {
  148. // We're running under Win9X, use the toolhelp functions
  149. GetReqW9xProc(kernel, Module32First, 0);
  150. GetReqW9xProc(kernel, Module32Next, 0);
  151. }
  152. }
  153. // Now we have all the callbacks we need, so get the process information needed
  154. if (!CreateToolhelp32SnapshotW9x)
  155. {
  156. // We're running under NT4
  157. // Note that I "prefer" using toolhelp32 - it's supposed to show up in NT5...
  158. HMODULE hModules[512];
  159. HANDLE hProcess = GetCurrentProcess();
  160. DWORD imageCount;
  161. if (!EnumProcessModules(hProcess, hModules, 512 * sizeof(HMODULE), &imageCount))
  162. return 0;
  163. imageCount /= sizeof(HMODULE);
  164. MODULEINFO info;
  165. for (DWORD i = 0; i < imageCount; i++)
  166. {
  167. if (!GetModuleInformation(hProcess, hModules[i], &info, sizeof(MODULEINFO)))
  168. return 0;
  169. if (!(cur = (ImageInfo *)HeapAlloc(GetProcessHeap(), 0, sizeof(ImageInfo))))
  170. goto CHOKE;
  171. cur->hndl = hModules[i];
  172. cur->BaseAddress = (DWORD)info.lpBaseOfDll;
  173. cur->BaseSize = info.SizeOfImage;
  174. cur->imgName = 0;
  175. cur->next = lImages;
  176. lImages = cur;
  177. }
  178. } else
  179. {
  180. HANDLE snap;
  181. if ((snap = CreateToolhelp32SnapshotW9x(TH32CS_SNAPMODULE, 0)) == (HANDLE)-1)
  182. return 0;
  183. MODULEENTRY32 *info = (MODULEENTRY32*)_alloca(sizeof(MODULEENTRY32));
  184. info->dwSize = sizeof(MODULEENTRY32);
  185. if (Module32FirstW9x(snap, info))
  186. {
  187. do {
  188. ImageInfo *newImg;
  189. if (!(newImg = (ImageInfo *)HeapAlloc(GetProcessHeap(), 0, sizeof(ImageInfo))))
  190. {
  191. CloseHandle(snap);
  192. goto CHOKE;
  193. }
  194. newImg->hndl = info->hModule;
  195. newImg->BaseAddress = (DWORD)info->modBaseAddr;
  196. newImg->BaseSize = info->modBaseSize;
  197. newImg->imgName = 0;
  198. newImg->next = lImages;
  199. lImages = newImg;
  200. } while (Module32NextW9x(snap, info));
  201. }
  202. CloseHandle(snap);
  203. }
  204. for (cur = lImages; cur; cur = cur->next)
  205. {
  206. cur->img = ImageNtHeader((void *)cur->BaseAddress);
  207. cur->sectHdr = IMAGE_FIRST_SECTION(cur->img);
  208. char *buf = (char*)_alloca(513);
  209. buf[512] = '\0';
  210. if (!GetModuleFileName(cur->hndl, buf, 512))
  211. goto CHOKE;
  212. int nmLen;
  213. for (nmLen = 0; buf[nmLen]; nmLen++) {}
  214. if (!(cur->imgName = (char*)HeapAlloc(GetProcessHeap(), 0, nmLen+1)))
  215. goto CHOKE;
  216. nmLen = 0;
  217. do {
  218. cur->imgName[nmLen] = buf[nmLen];
  219. } while (buf[nmLen++]);
  220. }
  221. for (res = lImages; res; res = res->next)
  222. {
  223. if (res->BaseAddress <= address && address - res->BaseAddress <= res->BaseSize)
  224. return res;
  225. }
  226. CHOKE:
  227. while (lImages) {
  228. ImageInfo *next = lImages->next;
  229. if (lImages->imgName)
  230. HeapFree(GetProcessHeap(), 0, lImages->imgName);
  231. HeapFree(GetProcessHeap(), 0, lImages);
  232. lImages = next;
  233. }
  234. return 0;
  235. }
  236. static HINSTANCE
  237. GetPdbDll()
  238. {
  239. static BOOL alreadyTried = FALSE;
  240. // If we already tried to load it, return
  241. if (alreadyTried)
  242. return (HINSTANCE)0;
  243. alreadyTried = TRUE;
  244. HINSTANCE res;
  245. if (res = LoadLibrary(mspdbName))
  246. return res;
  247. // Load the AdvAPI32.DLL entrypoints
  248. HINSTANCE advapi32;
  249. if (!(advapi32 = LoadLibrary("ADVAPI32.DLL")))
  250. return 0;
  251. RegOpenKeyExAProc RegOpenKeyExA;
  252. GetReqProcedure(advapi32, RegOpenKeyExA, 0);
  253. RegQueryValueExAProc RegQueryValueExA;
  254. GetReqProcedure(advapi32, RegQueryValueExA, 0);
  255. RegCloseKeyProc RegCloseKey;
  256. GetReqProcedure(advapi32, RegCloseKey, 0);
  257. char *keyname = REGISTRY_KEY_LOCATION;
  258. BYTE *buf;
  259. HKEY key1;
  260. long pos, err;
  261. DWORD type, len;
  262. err = RegOpenKeyExA(REGISTRY_KEY_MASTER, keyname, 0, KEY_QUERY_VALUE, &key1);
  263. if (err != ERROR_SUCCESS)
  264. {
  265. FreeLibrary(advapi32);
  266. return 0;
  267. }
  268. err = RegQueryValueExA(key1, REGISTRY_KEY_NAME, NULL, &type, 0, &len);
  269. if (err != ERROR_SUCCESS)
  270. return 0;
  271. len += 2 + mspdbNameLen;
  272. buf = (BYTE*)_alloca(len * sizeof(BYTE));
  273. err = RegQueryValueExA(key1, REGISTRY_KEY_NAME, NULL, &type, buf, &len);
  274. RegCloseKey(key1);
  275. FreeLibrary(advapi32);
  276. if (err != ERROR_SUCCESS)
  277. return 0;
  278. if (buf[len - 2] != '\\')
  279. buf[len - 1] = '\\';
  280. else
  281. len--;
  282. for (pos = 0; pos <= mspdbNameLen; pos++)
  283. buf[len + pos] = mspdbName[pos];
  284. return LoadLibrary((const char *)buf);
  285. }
  286. BOOL
  287. _RTC_GetSrcLine(
  288. DWORD address,
  289. char* source,
  290. int sourcelen,
  291. int* pline,
  292. char** moduleName
  293. )
  294. {
  295. struct SSrcModuleHdr {
  296. WORD cFile;
  297. WORD cSeg;
  298. };
  299. struct SStartEnd {
  300. DWORD start;
  301. DWORD end;
  302. };
  303. SSrcModuleHdr *liHdr;
  304. ULONG *baseSrcFile; // SSrcModuleHdr.cFile items
  305. SStartEnd *startEnd; // SSrcModuleHdr.cSeg items
  306. USHORT *contribSegs; // SSrcModuleHdr.cSeg items (+1 for alignement)
  307. int i;
  308. ImageInfo *iInf;
  309. PDB *ppdb;
  310. DBI *pdbi;
  311. Mod *pmod;
  312. EC err;
  313. // CB_ERR_MAX from linker is 1024 - not particularly secure, but oh well.
  314. // This whole thing should be rewritten using DIA instead of MSPDB for next rev...
  315. char *errname = (char*)_alloca(1024);
  316. OFF imageAddr;
  317. OFF secAddr;
  318. OFF offsetRes;
  319. USHORT sectionIndex;
  320. USHORT sectionIndexRes;
  321. long size;
  322. PB lineBuffer;
  323. static BOOL PDBOK = FALSE;
  324. BOOL res = FALSE;
  325. *pline = 0;
  326. *source = 0;
  327. *moduleName = 0;
  328. // First, find the image (DLL/EXE) in which this address occurs
  329. iInf = GetImageInfo(address);
  330. if (!iInf)
  331. // We didn't find this address is the list of modules, so quit
  332. goto DONE0;
  333. // Now get the Relative virtual address of the address given
  334. imageAddr = address - iInf->BaseAddress;
  335. *moduleName = iInf->imgName;
  336. res = TRUE;
  337. // Try to load the PDB DLL
  338. if (!PDBOK)
  339. {
  340. // If we already loaded it before, there must be some missing API function
  341. if (mspdb || !(mspdb = GetPdbDll()))
  342. goto DONE0;
  343. GetReqProcedure(mspdb, PDBOpenValidate3, 0);
  344. GetReqProcedure(mspdb, PDBOpenDBI, 0);
  345. GetReqProcedure(mspdb, DBIQueryModFromAddr, 0);
  346. GetReqProcedure(mspdb, ModQueryLines, 0);
  347. GetReqProcedure(mspdb, ModClose, 0);
  348. GetReqProcedure(mspdb, DBIClose, 0);
  349. GetReqProcedure(mspdb, PDBClose, 0);
  350. PDBOK = TRUE;
  351. }
  352. // Now find the section index & section-relative address
  353. secAddr = -1;
  354. for (sectionIndex = 0; sectionIndex < iInf->img->FileHeader.NumberOfSections; sectionIndex++)
  355. {
  356. if (iInf->sectHdr[sectionIndex].VirtualAddress < (unsigned)imageAddr &&
  357. imageAddr - iInf->sectHdr[sectionIndex].VirtualAddress < iInf->sectHdr[sectionIndex].SizeOfRawData)
  358. {
  359. secAddr = imageAddr - iInf->sectHdr[sectionIndex].VirtualAddress;
  360. break;
  361. }
  362. }
  363. if (secAddr == -1)
  364. goto DONE0;
  365. // Open the PDB for this image
  366. DWORD fo, cb;
  367. char *path = (char*)_alloca(MAX_PATH);
  368. // Rumor has it that I'll need to switch to OV5 instead of OV3 for this call soon...
  369. if (!PDBOpenValidate3(iInf->imgName, "", &err, errname, path, &fo, &cb, &ppdb))
  370. goto DONE0;
  371. // Get the DBI interface for the PDB
  372. if (!PDBOpenDBI(ppdb, pdbRead, 0, &pdbi))
  373. goto DONE1;
  374. // Now get the Mod from the section index & the section-relative address
  375. if (!DBIQueryModFromAddr(pdbi, ++sectionIndex, secAddr, &pmod, &sectionIndexRes, &offsetRes, &size))
  376. goto DONE2;
  377. // Get the size of the buffer we need
  378. if (!ModQueryLines(pmod, 0, &size) || !size)
  379. goto DONE3;
  380. lineBuffer = (PB)HeapAlloc(GetProcessHeap(), 0, size);
  381. if (!ModQueryLines(pmod, lineBuffer, &size))
  382. goto DONE3;
  383. // fill in the number of source files, and their corresponding regions
  384. liHdr = (SSrcModuleHdr*)lineBuffer;
  385. baseSrcFile = (ULONG *)(lineBuffer + sizeof(SSrcModuleHdr));
  386. // I think I can actually ignore the rest of the module header info
  387. startEnd = (SStartEnd *)&(baseSrcFile[liHdr->cFile]);
  388. contribSegs = (USHORT *)&(startEnd[liHdr->cSeg]);
  389. for (i = 0; i < liHdr->cFile; i++)
  390. {
  391. BYTE *srcBuff = lineBuffer + baseSrcFile[i];
  392. USHORT segCount = *(USHORT *)srcBuff;
  393. ULONG *baseSrcLn = &(((ULONG *)srcBuff)[1]);
  394. SStartEnd *segStartEnd = (SStartEnd*)&(baseSrcLn[segCount]);
  395. char *srcName = (char *)&segStartEnd[segCount];
  396. // Step through the various bunch of segments this src file contributes
  397. for (int j = 0; j < segCount; j++)
  398. {
  399. if (segStartEnd[j].start <= (unsigned)secAddr &&
  400. (unsigned)secAddr <= segStartEnd[j].end)
  401. {
  402. // If this segment contains the section address,
  403. // we've found the right one, so find the closest line number
  404. BYTE *segLnBuf = &lineBuffer[baseSrcLn[j]];
  405. USHORT pairCount = *(USHORT*)&(segLnBuf[sizeof(USHORT)]);
  406. ULONG *offsets = (ULONG *)&(segLnBuf[sizeof(USHORT)*2]);
  407. USHORT *linNums = (USHORT *)&(offsets[pairCount]);
  408. int best = -1;
  409. ULONG dist = 0xFFFFFFFF;
  410. for (int k = 0; k < pairCount; k++)
  411. {
  412. if (secAddr - offsets[k] < dist)
  413. {
  414. best = k;
  415. dist = secAddr - offsets[k];
  416. }
  417. }
  418. if (best < 0)
  419. // It shoulda been here, but it wasn't...
  420. goto DONE4;
  421. *pline = linNums[best];
  422. for (j = 0; srcName[j] && j < sourcelen; j++)
  423. source[j] = srcName[j];
  424. source[(j < sourcelen) ? j : sourcelen-1] = 0;
  425. goto DONE4;
  426. }
  427. }
  428. }
  429. DONE4:
  430. HeapFree(GetProcessHeap(), 0, lineBuffer);
  431. DONE3:
  432. ModClose(pmod);
  433. DONE2:
  434. DBIClose(pdbi);
  435. DONE1:
  436. PDBClose(ppdb);
  437. DONE0:
  438. return res;
  439. }