Source code of Windows XP (NT5)
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.

437 lines
16 KiB

  1. // WppFmt.c
  2. // This module contains the routines used by BinPlace to copy out the trace format information used
  3. // by software tracing. It creates "guid".tmf files
  4. // The pre-processor TraceWpp creates annotation records in the PDB with the first string bwinfg the text
  5. // "TMF:" we find these annotation records and extract the complete record. The first record
  6. // after "TMF:" contains the guid and friendly name. This GUID is used to create the filename.
  7. // Currently the remainder of the records are copied to the file, a possible future change is to turn the
  8. // file into a pointer file.
  9. // Based on PDB sample code from VC folks, with names kept the same.
  10. #ifdef __cplusplus
  11. extern "C"{
  12. #endif
  13. //#define UNICODE
  14. //#define _UNICODE
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <windows.h>
  21. #include <shellapi.h>
  22. #include <tchar.h>
  23. #include <dbghelp.h>
  24. #include <cvinfo.h>
  25. #define PDB_LIBRARY
  26. #include <pdb.h>
  27. typedef LONG CB; // count of bytes
  28. typedef CHAR * ST;
  29. typedef SYMTYPE* PSYM;
  30. typedef SYMTYPE UNALIGNED * PSYMUNALIGNED;
  31. typedef BYTE* PB; // pointer to some bytes
  32. FILE* TraceFileP = NULL; // Current File
  33. CHAR lastguid[MAX_PATH]; // The last file we processed
  34. CHAR TraceFile[MAX_PATH]; // The current full file spec.
  35. CHAR TraceFileExt[] = ".tmf" ; // Extension used by Trace Files
  36. CHAR TraceControlExt[] = ".tmc" ; // Extension used by Trace Control Files
  37. BOOL TracePathChecked = FALSE ; // if we have ascertained the trace Path exists.
  38. CHAR Fname[MAX_PATH] ;
  39. CHAR Mname[MAX_PATH] ;
  40. #define GUIDTEXTLENGTH 32+4 // Guid takes 32 chars plus 4 -'s
  41. #define MAXLINE MAX_PATH + 256
  42. CHAR Line[MAXLINE] ;
  43. CHAR FirstLine[MAXLINE] ;
  44. BOOL fVerbose = FALSE ;
  45. typedef BOOL ( __cdecl *PPDBOPEN )(
  46. LNGNM_CONST char *,
  47. LNGNM_CONST char *,
  48. SIG,
  49. EC *,
  50. char [cbErrMax],
  51. PDB **
  52. );
  53. typedef BOOL ( __cdecl *PPDBCLOSE ) (
  54. PDB* ppdb
  55. );
  56. typedef BOOL ( __cdecl *PPDBOPENDBI ) (
  57. PDB* ppdb, const char* szMode, const char* szTarget, OUT DBI** ppdbi
  58. );
  59. typedef BOOL ( __cdecl *PDBICLOSE ) (
  60. DBI* pdbi
  61. );
  62. typedef BOOL ( __cdecl *PMODQUERYSYMBOLS ) (
  63. Mod* pmod, BYTE* pbSym, long* pcb
  64. );
  65. typedef BOOL ( __cdecl *PDBIQUERYNEXTMOD ) (
  66. DBI* pdbi, Mod* pmod, Mod** ppmodNext
  67. );
  68. static PPDBOPEN pPDBOpen = NULL;
  69. static PPDBCLOSE pPDBClose = NULL;
  70. static PPDBOPENDBI pPDBOpenDBI = NULL;
  71. static PDBICLOSE pDBIClose = NULL;
  72. static PMODQUERYSYMBOLS pModQuerySymbols = NULL;
  73. static PDBIQUERYNEXTMOD pDBIQueryNextMod = NULL;
  74. static BOOL RSDSLibLoaded = FALSE;
  75. // Return the number of bytes the symbol record occupies.
  76. #define MDALIGNTYPE_ DWORD
  77. __inline CB cbAlign_(CB cb) {
  78. return((cb + sizeof(MDALIGNTYPE_) - 1)) & ~(sizeof(MDALIGNTYPE_) - 1);}
  79. // Return the number of bytes in an ST
  80. __inline CB cbForSt(ST st) { return *(PB)st + 1;}
  81. CB cbForSym(PSYMUNALIGNED psym)
  82. {
  83. CB cb = psym->reclen + sizeof(psym->reclen);
  84. // procrefs also have a hidden length preceeded name following the record
  85. if ((psym->rectyp == S_PROCREF) || (psym->rectyp == S_LPROCREF))
  86. cb += cbAlign_(cbForSt((ST)(psym + cb)));
  87. return cb;
  88. }
  89. // Return a pointer to the byte just past the end of the symbol record.
  90. PSYM pbEndSym(PSYM psym) { return(PSYM)((CHAR *)psym + cbForSym(psym));}
  91. CHAR * SymBuffer = 0;
  92. int SymBufferSize = 0;
  93. BOOL ensureBufferSizeAtLeast(int size)
  94. {
  95. if (size > SymBufferSize) {
  96. LocalFree(SymBuffer);
  97. SymBufferSize = 0;
  98. size = (size + 0xFFFF) & ~0xFFFF;
  99. SymBuffer = LocalAlloc(LMEM_FIXED, size );
  100. if (!SymBuffer) {
  101. fprintf(stderr,"%s : error BNP0000: WPPFMT alloc of %d bytes failed\n",Fname, size);
  102. return FALSE;
  103. }
  104. SymBufferSize = size;
  105. }
  106. return TRUE;
  107. }
  108. void dumpSymbol(PSYM psym,
  109. PSTR PdbFileName,
  110. PSTR TraceFormatFilePath)
  111. {
  112. static char FuncName[256] = "Unknown";
  113. static char Fmode[8] = "w" ;
  114. if (psym->rectyp == S_GPROC32 || psym->rectyp == S_LPROC32) {
  115. PROCSYM32* p = (PROCSYM32*)psym;
  116. int n = p->name[0];
  117. memcpy(FuncName, p->name + 1, n);
  118. FuncName[n] = 0;
  119. return;
  120. }
  121. //
  122. // The following is a complete crock to let us handle some V7 PDB changes
  123. // This code will have qbe changed by DIA but this lets users get work done
  124. #define S_GPROC32_V7 0x110f
  125. #define S_LPROC32_V7 0x1110
  126. if (psym->rectyp == (S_GPROC32_V7) || psym->rectyp == (S_LPROC32_V7)) {
  127. PROCSYM32* p = (PROCSYM32*)psym;
  128. strncpy(FuncName,p->name, 256); // Note name is null terminated, not length!!!
  129. return;
  130. }
  131. // End of V7 PDB crock
  132. if (psym->rectyp == S_ANNOTATION) {
  133. ANNOTATIONSYM* aRec = (ANNOTATIONSYM*) psym;
  134. UCHAR * Aline = aRec->rgsz;
  135. int cnt = aRec->csz, i;
  136. CHAR* Ext;
  137. if ( cnt < 2 ) {
  138. return;
  139. }
  140. if ( strcmp(Aline, "TMF:") == 0 ) {
  141. Ext = TraceFileExt;
  142. } else if ( strcmp(Aline, "TMC:") == 0 ) {
  143. Ext = TraceControlExt;
  144. } else {
  145. return;
  146. }
  147. // skip tmf
  148. Aline += strlen(Aline) + 1;
  149. // now Aline points to guid, is it the same as before?
  150. if ( (TraceFileP != stdout) && strncmp(Aline, lastguid, GUIDTEXTLENGTH) != 0) {
  151. // the guid has changed, we need to change the file
  152. if (TraceFileP) {
  153. fclose(TraceFileP); // Close the last one
  154. TraceFileP = NULL ;
  155. }
  156. strncpy(lastguid, Aline, GUIDTEXTLENGTH);
  157. _snprintf(TraceFile,MAX_PATH,"%s\\%s%s",TraceFormatFilePath,lastguid,Ext);
  158. if (!TracePathChecked) {
  159. if (!MakeSureDirectoryPathExists(TraceFile)) { // Make the directory if we need to
  160. fprintf(stderr,"%s : error BNP0000: WPPFMT Failed to make path %s\n",Fname, TraceFile);
  161. return;
  162. } else {
  163. TracePathChecked = TRUE ;
  164. }
  165. }
  166. sprintf(Fmode,"w"); // Assume its to be overwritten
  167. if ((TraceFileP = fopen(TraceFile,"r")) != NULL ) {
  168. // Hmm it already exists, is it an old one or must we add to it.
  169. if (_fgetts(Line, MAXLINE, TraceFileP)) {
  170. if (strcmp(Line,FirstLine) == 0) {
  171. sprintf(Fmode,"a");
  172. }
  173. }
  174. fclose (TraceFileP);
  175. TraceFileP = NULL ;
  176. }
  177. TraceFileP = fopen(TraceFile, Fmode);
  178. if (!TraceFileP) {
  179. fprintf(stderr,"%s : error BNP0000: WPPFMT Failed to open %s\n",Fname, TraceFile);
  180. return;
  181. }
  182. if (fVerbose) {
  183. fprintf(stdout,"%s : warning BNP0000: WPPFMT generating %s for %s\n",
  184. Fname, TraceFile, PdbFileName);
  185. }
  186. if (!(strcmp(Fmode,"w"))) {
  187. // First time around comment on what we are doing.
  188. fprintf(TraceFileP,"%s",FirstLine); // Note the name of the PDB etc.
  189. fprintf(TraceFileP,"%s\n",Aline); // Guid and friendly name
  190. } else {
  191. fprintf(TraceFileP,"//PDB append\n");
  192. }
  193. }
  194. // process the annotation which is a series of null terminated strings.
  195. cnt -= 2; Aline += strlen(Aline) + 1;
  196. for (i = 0; i < cnt; ++i) {
  197. if (i == 0) {
  198. fprintf(TraceFileP, "%s FUNC=%s\n", Aline, FuncName);
  199. } else {
  200. fprintf(TraceFileP,"%s\n", Aline);
  201. }
  202. Aline += strlen(Aline) + 1;
  203. }
  204. }
  205. }
  206. DWORD
  207. BinplaceWppFmt(
  208. LPSTR PdbFileName,
  209. LPSTR TraceFormatFilePath,
  210. LPSTR szRSDSDllToLoad,
  211. BOOL TraceVerbose
  212. )
  213. {
  214. PDB *pPdb;
  215. DBI *pDbi;
  216. HANDLE hPdb ;
  217. UCHAR szErr[cbErrMax];
  218. EC errorCode;
  219. Mod* pMod;
  220. DWORD Status ;
  221. BOOL rc;
  222. fVerbose = TraceVerbose ;
  223. // get name of the caller
  224. Status = GetModuleFileName(NULL, Mname, MAX_PATH);
  225. _splitpath(Mname, NULL, NULL, Fname, NULL);
  226. #ifdef _WIN64
  227. rc = FALSE;
  228. #else
  229. __try
  230. {
  231. if (hPdb = CreateFile(PdbFileName,
  232. GENERIC_READ,
  233. 0,NULL,
  234. OPEN_EXISTING,
  235. FILE_ATTRIBUTE_NORMAL,
  236. NULL)) {
  237. FILETIME ftime ;
  238. SYSTEMTIME stime ;
  239. if (GetFileTime(hPdb,NULL,NULL,&ftime)) {
  240. if ( FileTimeToSystemTime(&ftime,&stime) ) {
  241. _snprintf(FirstLine,MAXLINE,"//PDB: %s Last Updated :%d-%d-%d:%d:%d:%d:%d (UTC) [%s]\n",
  242. PdbFileName,
  243. stime.wYear,stime.wMonth,stime.wDay,
  244. stime.wHour,stime.wMinute,stime.wSecond,stime.wMilliseconds,
  245. Fname);
  246. }
  247. }
  248. CloseHandle(hPdb);
  249. } else {
  250. // Let the failure case be dealt with by PDBOpen
  251. }
  252. rc=PDBOpen(PdbFileName, pdbRead, 0, &errorCode, szErr, &pPdb);
  253. }
  254. __except( EXCEPTION_EXECUTE_HANDLER )
  255. {
  256. rc=FALSE;
  257. }
  258. #endif
  259. if ( !rc ) {
  260. // Try the one that works with RSDS
  261. if ( szRSDSDllToLoad != NULL ) {
  262. HMODULE hDll;
  263. if ( !RSDSLibLoaded ) {
  264. hDll = LoadLibrary( szRSDSDllToLoad );
  265. if (hDll != NULL) {
  266. RSDSLibLoaded = TRUE;
  267. pPDBOpen = ( PPDBOPEN ) GetProcAddress( hDll, "PDBOpen" );
  268. if (pPDBOpen == NULL ) {
  269. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed PDBOpen\n",Fname);
  270. return(FALSE);
  271. }
  272. pPDBClose = ( PPDBCLOSE ) GetProcAddress( hDll, "PDBClose" );
  273. if (pPDBClose == NULL ) {
  274. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed PDBOClose\n",Fname);
  275. return(FALSE);
  276. }
  277. pPDBOpenDBI = ( PPDBOPENDBI ) GetProcAddress( hDll, "PDBOpenDBI" );
  278. if (pPDBOpenDBI == NULL ) {
  279. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed PDBOpenDBI\n",Fname);
  280. return(FALSE);
  281. }
  282. pDBIClose = ( PDBICLOSE ) GetProcAddress( hDll, "DBIClose" );
  283. if (pDBIClose == NULL ) {
  284. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed DBICLOSE\n",Fname);
  285. return(FALSE);
  286. }
  287. pDBIQueryNextMod = ( PDBIQUERYNEXTMOD ) GetProcAddress( hDll, "DBIQueryNextMod" );
  288. if (pDBIQueryNextMod == NULL ) {
  289. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed DBIQueryNextMod\n",Fname);
  290. return(FALSE);
  291. }
  292. pModQuerySymbols = ( PMODQUERYSYMBOLS ) GetProcAddress( hDll, "ModQuerySymbols" );
  293. if (pModQuerySymbols == NULL ) {
  294. fprintf(stderr,"%s : error BNP0000: WPPFMT GEtPRocAddressFailed ModQuerySymbols\n",Fname);
  295. return(FALSE);
  296. }
  297. } else {
  298. fprintf(stderr,"%s : error BNP0000: WPPFMT Failed to load library %s (0x%08X)\n",Fname, szRSDSDllToLoad,GetLastError());
  299. return(FALSE);
  300. }
  301. }
  302. }
  303. if (RSDSLibLoaded) {
  304. __try
  305. {
  306. rc = pPDBOpen(PdbFileName, pdbRead, 0, &errorCode, szErr, &pPdb);
  307. }
  308. __except (EXCEPTION_EXECUTE_HANDLER )
  309. {
  310. rc=FALSE;
  311. }
  312. }
  313. }
  314. if (!rc) {
  315. fprintf(stderr,"%s : warning BNP0000: WPPFMT PDBOpen failed, code %d, error %s\n",
  316. Fname, errorCode, szErr);
  317. goto fail1;
  318. }
  319. if (RSDSLibLoaded) {
  320. rc = pPDBOpenDBI(pPdb, pdbRead, "<target>.exe", &pDbi);
  321. } else {
  322. rc = PDBOpenDBI(pPdb, pdbRead, "<target>.exe", &pDbi);
  323. }
  324. if (!rc) {
  325. fprintf(stderr,"%s : warning BNP0000: WPPFMT PDBOpenDBI failed\n",Fname);
  326. goto fail2;
  327. }
  328. if (RSDSLibLoaded) {
  329. for (pMod = 0; pDBIQueryNextMod(pDbi, pMod, &pMod) && pMod; ) {
  330. CB cbSyms;
  331. if ( pModQuerySymbols(pMod, 0, &cbSyms)
  332. && ensureBufferSizeAtLeast(cbSyms)
  333. && pModQuerySymbols(pMod, SymBuffer, &cbSyms) ) {
  334. PSYM psymEnd = (PSYM)(SymBuffer + cbSyms);
  335. PSYM psym = (PSYM)(SymBuffer + sizeof(ULONG));
  336. for (; psym < psymEnd; psym = pbEndSym(psym))
  337. dumpSymbol(psym,PdbFileName,TraceFormatFilePath);
  338. } else {
  339. fprintf(stderr,"%s : warning BNP0000: WPPFMT ModQuerySymbols failed pMod = %p cbSyms = %d\n",
  340. Fname, pMod, cbSyms);
  341. break;
  342. }
  343. }
  344. } else {
  345. for (pMod = 0; DBIQueryNextMod(pDbi, pMod, &pMod) && pMod; ) {
  346. CB cbSyms;
  347. if ( ModQuerySymbols(pMod, 0, &cbSyms)
  348. && ensureBufferSizeAtLeast(cbSyms)
  349. && ModQuerySymbols(pMod, SymBuffer, &cbSyms) ) {
  350. PSYM psymEnd = (PSYM)(SymBuffer + cbSyms);
  351. PSYM psym = (PSYM)(SymBuffer + sizeof(ULONG));
  352. for (; psym < psymEnd; psym = pbEndSym(psym))
  353. dumpSymbol(psym,PdbFileName,TraceFormatFilePath);
  354. } else {
  355. fprintf(stderr,"%s : warning BNP0000: WPPFMT ModQuerySymbols failed pMod = %p cbSyms = %d\n",
  356. Fname, pMod, cbSyms);
  357. break;
  358. }
  359. }
  360. }
  361. if (RSDSLibLoaded) {
  362. pDBIClose(pDbi);
  363. } else {
  364. DBIClose(pDbi);
  365. }
  366. fail2:
  367. if (RSDSLibLoaded) {
  368. pPDBClose(pPdb);
  369. } else {
  370. PDBClose(pPdb);
  371. }
  372. fail1:
  373. if (TraceFileP) {
  374. fclose(TraceFileP); // Close the last one
  375. TraceFileP = NULL ;
  376. }
  377. return errorCode;
  378. }
  379. #ifdef __cplusplus
  380. }
  381. #endif