| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 | #include <stdio.h> | 
|---|
| 6 | #include <ctype.h> | 
|---|
| 7 | #include <crtdbg.h> | 
|---|
| 8 | #include "mdinfo.h" | 
|---|
| 9 |  | 
|---|
| 10 | #ifndef STRING_BUFFER_LEN | 
|---|
| 11 | #define STRING_BUFFER_LEN 4096 | 
|---|
| 12 | #endif | 
|---|
| 13 |  | 
|---|
| 14 | #define OBJ_EXT         ".obj" | 
|---|
| 15 | #define OBJ_EXT_W       W(".obj") | 
|---|
| 16 | #define OBJ_EXT_LEN     4 | 
|---|
| 17 | #define LIB_EXT         ".lib" | 
|---|
| 18 | #define LIB_EXT_W       W(".lib") | 
|---|
| 19 | #define LIB_EXT_LEN     4 | 
|---|
| 20 |  | 
|---|
| 21 | extern IMetaDataDispenserEx *g_pDisp; | 
|---|
| 22 | extern DWORD g_ValModuleType; | 
|---|
| 23 |  | 
|---|
| 24 | // This function is copied from peparse.c file.  Making this static, so we won't end up with | 
|---|
| 25 | // duplicate definitions causing confusion. | 
|---|
| 26 | static const char g_szCORMETA[] = ".cormeta"; | 
|---|
| 27 | static HRESULT FindObjMetaData(PVOID pImage, PVOID *ppMetaData, long *pcbMetaData) | 
|---|
| 28 | { | 
|---|
| 29 | IMAGE_FILE_HEADER *pImageHdr;       // Header for the .obj file. | 
|---|
| 30 | IMAGE_SECTION_HEADER *pSectionHdr;  // Section header. | 
|---|
| 31 | WORD        i;                      // Loop control. | 
|---|
| 32 |  | 
|---|
| 33 | // Get a pointer to the header and the first section. | 
|---|
| 34 | pImageHdr = (IMAGE_FILE_HEADER *) pImage; | 
|---|
| 35 | pSectionHdr = (IMAGE_SECTION_HEADER *)(pImageHdr + 1); | 
|---|
| 36 |  | 
|---|
| 37 | // Avoid confusion. | 
|---|
| 38 | *ppMetaData = NULL; | 
|---|
| 39 | *pcbMetaData = 0; | 
|---|
| 40 |  | 
|---|
| 41 | // Walk each section looking for .cormeta. | 
|---|
| 42 | for (i=0;  i<VAL16(pImageHdr->NumberOfSections);  i++, pSectionHdr++) | 
|---|
| 43 | { | 
|---|
| 44 | // Simple comparison to section name. | 
|---|
| 45 | if (strcmp((const char *) pSectionHdr->Name, g_szCORMETA) == 0) | 
|---|
| 46 | { | 
|---|
| 47 | *pcbMetaData = VAL32(pSectionHdr->SizeOfRawData); | 
|---|
| 48 | *ppMetaData = (void *) ((UINT_PTR)pImage + VAL32(pSectionHdr->PointerToRawData)); | 
|---|
| 49 | break; | 
|---|
| 50 | } | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 | // Check for errors. | 
|---|
| 54 | if (*ppMetaData == NULL || *pcbMetaData == 0) | 
|---|
| 55 | return (E_FAIL); | 
|---|
| 56 | return (S_OK); | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 |  | 
|---|
| 60 | // This function returns the address to the MapView of file and file size. | 
|---|
| 61 | void GetMapViewOfFile(__in wchar_t *szFile, PBYTE *ppbMap, DWORD *pdwFileSize) | 
|---|
| 62 | { | 
|---|
| 63 | HANDLE      hMapFile; | 
|---|
| 64 | DWORD       dwHighSize; | 
|---|
| 65 |  | 
|---|
| 66 | HANDLE hFile = WszCreateFile(szFile, | 
|---|
| 67 | GENERIC_READ, | 
|---|
| 68 | FILE_SHARE_READ, | 
|---|
| 69 | NULL, | 
|---|
| 70 | OPEN_EXISTING, | 
|---|
| 71 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, | 
|---|
| 72 | NULL); | 
|---|
| 73 | if (hFile == INVALID_HANDLE_VALUE) | 
|---|
| 74 | MDInfo::Error( "CreateFileA failed!"); | 
|---|
| 75 |  | 
|---|
| 76 | *pdwFileSize = GetFileSize(hFile, &dwHighSize); | 
|---|
| 77 |  | 
|---|
| 78 | if ((*pdwFileSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) | 
|---|
| 79 | { | 
|---|
| 80 | CloseHandle(hFile); | 
|---|
| 81 | MDInfo::Error( "GetFileSize failed!"); | 
|---|
| 82 | } | 
|---|
| 83 | _ASSERTE(dwHighSize == 0); | 
|---|
| 84 |  | 
|---|
| 85 | hMapFile = CreateFileMappingA(hFile, NULL, PAGE_READONLY, 0, 0, NULL); | 
|---|
| 86 | CloseHandle(hFile); | 
|---|
| 87 | if (!hMapFile) | 
|---|
| 88 | MDInfo::Error( "CreateFileMappingA failed!"); | 
|---|
| 89 |  | 
|---|
| 90 | *ppbMap = (PBYTE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); | 
|---|
| 91 | CloseHandle(hMapFile); | 
|---|
| 92 |  | 
|---|
| 93 | if (!*ppbMap) | 
|---|
| 94 | MDInfo::Error( "MapViewOfFile failed!"); | 
|---|
| 95 | } // void GetMapViewOfFile() | 
|---|
| 96 |  | 
|---|
| 97 | // This function skips a member given the pointer to the member header | 
|---|
| 98 | // and returns a pointer to the next header. | 
|---|
| 99 | PBYTE SkipMember(PBYTE pbMapAddress) | 
|---|
| 100 | { | 
|---|
| 101 | PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr; | 
|---|
| 102 | ULONG       ulMemSize; | 
|---|
| 103 | int         j; | 
|---|
| 104 |  | 
|---|
| 105 | pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress; | 
|---|
| 106 |  | 
|---|
| 107 | // Get size of the member. | 
|---|
| 108 | ulMemSize = 0; | 
|---|
| 109 | for (j = 0; j < 10; j++) | 
|---|
| 110 | { | 
|---|
| 111 | if (pMemHdr->Size[j] < '0' || pMemHdr->Size[j] > '9') | 
|---|
| 112 | break; | 
|---|
| 113 | else | 
|---|
| 114 | ulMemSize = ulMemSize * 10 + pMemHdr->Size[j] - '0'; | 
|---|
| 115 | } | 
|---|
| 116 |  | 
|---|
| 117 | // Skip past the header. | 
|---|
| 118 | pbMapAddress += IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR + ulMemSize; | 
|---|
| 119 | // Find the next even address if the current one is not even. | 
|---|
| 120 | if ((ULONG_PTR)pbMapAddress % 2) | 
|---|
| 121 | pbMapAddress++; | 
|---|
| 122 |  | 
|---|
| 123 | return pbMapAddress; | 
|---|
| 124 | } // void SkipMember() | 
|---|
| 125 |  | 
|---|
| 126 | // This function returns the name of the given Obj.  If the name fits in the header, | 
|---|
| 127 | // szBuf will be filled in and returned from the function.  Else an offset into the long | 
|---|
| 128 | // names section will be returned. | 
|---|
| 129 | char *(PBYTE pbLongNames, PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr, char szBuf[17]) | 
|---|
| 130 | { | 
|---|
| 131 | if (pMemHdr->Name[0] == '/') | 
|---|
| 132 | { | 
|---|
| 133 | ULONG   ulOffset = 0; | 
|---|
| 134 |  | 
|---|
| 135 | // Long Names section must exist if the .obj file name starts with '/'. | 
|---|
| 136 | _ASSERTE(pbLongNames && | 
|---|
| 137 | "Corrupt archive file - .obj file name in the header starts with " | 
|---|
| 138 | "'/' but no long names section present in the archive file."); | 
|---|
| 139 |  | 
|---|
| 140 | // Calculate the offset into the long names section. | 
|---|
| 141 | for (int j = 1; j < 16; j++) | 
|---|
| 142 | { | 
|---|
| 143 | if (pMemHdr->Name[j] < '0' || pMemHdr->Name[j] > '9') | 
|---|
| 144 | break; | 
|---|
| 145 | else | 
|---|
| 146 | ulOffset = ulOffset * 10 + pMemHdr->Name[j] - '0'; | 
|---|
| 147 | } | 
|---|
| 148 | return (char *)(pbLongNames + ulOffset); | 
|---|
| 149 | } | 
|---|
| 150 | else | 
|---|
| 151 | { | 
|---|
| 152 | int j; | 
|---|
| 153 | for (j = 0; j < 16; j++) | 
|---|
| 154 | if ((szBuf[j] = pMemHdr->Name[j]) == '/') | 
|---|
| 155 | break; | 
|---|
| 156 | szBuf[j] = '\0'; | 
|---|
| 157 | return szBuf; | 
|---|
| 158 | } | 
|---|
| 159 | } // char *GetNameOfObj() | 
|---|
| 160 |  | 
|---|
| 161 | // DisplayArchive() function | 
|---|
| 162 | // | 
|---|
| 163 | // Opens the .LIB file, and displays the metadata in the specified object files. | 
|---|
| 164 |  | 
|---|
| 165 | void DisplayArchive(__in_z __in wchar_t* szFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString) | 
|---|
| 166 | { | 
|---|
| 167 | PBYTE       pbMapAddress; | 
|---|
| 168 | PBYTE       pbStartAddress; | 
|---|
| 169 | PBYTE       pbLongNameAddress; | 
|---|
| 170 | PIMAGE_ARCHIVE_MEMBER_HEADER pMemHdr; | 
|---|
| 171 | DWORD       dwFileSize; | 
|---|
| 172 | PVOID       pvMetaData; | 
|---|
| 173 | char        *szName; | 
|---|
| 174 | wchar_t     wzName[1024]; | 
|---|
| 175 | char        szBuf[17]; | 
|---|
| 176 | long        cbMetaData; | 
|---|
| 177 | int         i; | 
|---|
| 178 | HRESULT     hr; | 
|---|
| 179 | char		szString[1024]; | 
|---|
| 180 |  | 
|---|
| 181 | GetMapViewOfFile(szFile, &pbMapAddress, &dwFileSize); | 
|---|
| 182 | pbStartAddress = pbMapAddress; | 
|---|
| 183 |  | 
|---|
| 184 | // Verify and skip archive signature. | 
|---|
| 185 | if (dwFileSize < IMAGE_ARCHIVE_START_SIZE || | 
|---|
| 186 | strncmp((char *)pbMapAddress, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) | 
|---|
| 187 | { | 
|---|
| 188 | MDInfo::Error( "Bad file format - archive signature mis-match!"); | 
|---|
| 189 | } | 
|---|
| 190 | pbMapAddress += IMAGE_ARCHIVE_START_SIZE; | 
|---|
| 191 |  | 
|---|
| 192 | // Skip linker member 1, linker member 2. | 
|---|
| 193 | for (i = 0; i < 2; i++) | 
|---|
| 194 | pbMapAddress = SkipMember(pbMapAddress); | 
|---|
| 195 |  | 
|---|
| 196 | // Save address of the long name member and skip it if there exists one. | 
|---|
| 197 | pMemHdr = (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress; | 
|---|
| 198 | if (pMemHdr->Name[0] == '/' && pMemHdr->Name[1] == '/') | 
|---|
| 199 | { | 
|---|
| 200 | pbLongNameAddress = pbMapAddress + IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR; | 
|---|
| 201 | pbMapAddress = SkipMember(pbMapAddress); | 
|---|
| 202 | } | 
|---|
| 203 | else | 
|---|
| 204 | pbLongNameAddress = 0; | 
|---|
| 205 |  | 
|---|
| 206 | pDisplayString ( "\n"); | 
|---|
| 207 | // Get the MetaData for each object file and display it. | 
|---|
| 208 | while (DWORD(pbMapAddress - pbStartAddress) < dwFileSize) | 
|---|
| 209 | { | 
|---|
| 210 | if((szName = GetNameOfObj(pbLongNameAddress, (PIMAGE_ARCHIVE_MEMBER_HEADER)pbMapAddress, szBuf))!=NULL) | 
|---|
| 211 | { | 
|---|
| 212 | if (Wsz_mbstowcs(wzName, szName, 1024) == -1) | 
|---|
| 213 | MDInfo::Error( "Conversion from Multi-Byte to Wide-Char failed."); | 
|---|
| 214 |  | 
|---|
| 215 | // Display metadata only for object files. | 
|---|
| 216 | // If szObjName is specified, display metadata only for that one object file. | 
|---|
| 217 | if (!_stricmp(&szName[strlen(szName) - OBJ_EXT_LEN], OBJ_EXT) && | 
|---|
| 218 | (!szObjName || !_wcsicmp(szObjName, wzName))) | 
|---|
| 219 | { | 
|---|
| 220 | // Try to find the MetaData section in the current object file. | 
|---|
| 221 | hr = FindObjMetaData(pbMapAddress+IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR, &pvMetaData, &cbMetaData); | 
|---|
| 222 | if (SUCCEEDED(hr)) | 
|---|
| 223 | { | 
|---|
| 224 | sprintf_s (szString,1024, "MetaData for object file %s:\n", szName); | 
|---|
| 225 | pDisplayString(szString); | 
|---|
| 226 | MDInfo archiveInfo(g_pDisp, | 
|---|
| 227 | (PBYTE)pvMetaData, | 
|---|
| 228 | cbMetaData, | 
|---|
| 229 | pDisplayString, | 
|---|
| 230 | DumpFilter); | 
|---|
| 231 | archiveInfo.DisplayMD(); | 
|---|
| 232 | } | 
|---|
| 233 | else | 
|---|
| 234 | { | 
|---|
| 235 | sprintf_s(szString,1024, "MetaData not found for object file %s!\n\n", szName); | 
|---|
| 236 | pDisplayString(szString); | 
|---|
| 237 | } | 
|---|
| 238 | } | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | // Skip past the object file. | 
|---|
| 242 | pbMapAddress = SkipMember(pbMapAddress); | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | UnmapViewOfFile(pbStartAddress); | 
|---|
| 246 | } // void DisplayArchive() | 
|---|
| 247 |  | 
|---|
| 248 | // DisplayFile() function | 
|---|
| 249 | // | 
|---|
| 250 | // Opens the meta data content of a .EXE, .CLB, .CLASS, .TLB, .DLL or .LIB file, and | 
|---|
| 251 | // calls RawDisplay() | 
|---|
| 252 |  | 
|---|
| 253 | void DisplayFile(__in_z __in wchar_t* szFile, BOOL isFile, ULONG DumpFilter, __in_z __in_opt wchar_t* szObjName, strPassBackFn pDisplayString) | 
|---|
| 254 | { | 
|---|
| 255 | // Open the emit scope | 
|---|
| 256 |  | 
|---|
| 257 | // We need to make sure this file isn't too long. Checking _MAX_PATH is probably safe, but since we have a much | 
|---|
| 258 | // larger buffer, we might as well use it all. | 
|---|
| 259 | if (wcslen(szFile) > 1000) | 
|---|
| 260 | return; | 
|---|
| 261 |  | 
|---|
| 262 |  | 
|---|
| 263 | WCHAR szScope[1024]; | 
|---|
| 264 | char szString[1024]; | 
|---|
| 265 |  | 
|---|
| 266 | if (isFile) | 
|---|
| 267 | { | 
|---|
| 268 | wcscpy_s(szScope, 1024, W( "file:")); | 
|---|
| 269 | wcscat_s(szScope, 1024, szFile); | 
|---|
| 270 | } | 
|---|
| 271 | else | 
|---|
| 272 | wcscpy_s(szScope, 1024, szFile); | 
|---|
| 273 |  | 
|---|
| 274 | // print bar that separates different files | 
|---|
| 275 | pDisplayString( "////////////////////////////////////////////////////////////////\n"); | 
|---|
| 276 | wchar_t rcFname[_MAX_FNAME], rcExt[_MAX_EXT]; | 
|---|
| 277 |  | 
|---|
| 278 | _wsplitpath_s(szFile, NULL, 0, NULL, 0, rcFname, _MAX_FNAME, rcExt, _MAX_EXT); | 
|---|
| 279 | sprintf_s(szString,1024, "\nFile %S%S: \n",rcFname, rcExt); | 
|---|
| 280 | pDisplayString(szString); | 
|---|
| 281 |  | 
|---|
| 282 | if (DumpFilter & MDInfo::dumpValidate) | 
|---|
| 283 | { | 
|---|
| 284 | if (!_wcsicmp(rcExt, OBJ_EXT_W) || !_wcsicmp(rcExt, LIB_EXT_W)) | 
|---|
| 285 | g_ValModuleType = ValidatorModuleTypeObj; | 
|---|
| 286 | else | 
|---|
| 287 | g_ValModuleType = ValidatorModuleTypePE; | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | if (!_wcsicmp(rcExt, LIB_EXT_W)) | 
|---|
| 291 | DisplayArchive(szFile, DumpFilter, szObjName, pDisplayString); | 
|---|
| 292 | else | 
|---|
| 293 | { | 
|---|
| 294 | MDInfo metaDataInfo(g_pDisp, szScope, pDisplayString, DumpFilter); | 
|---|
| 295 | metaDataInfo.DisplayMD(); | 
|---|
| 296 | } | 
|---|
| 297 | } // void DisplayFile() | 
|---|
| 298 |  | 
|---|
| 299 |  | 
|---|