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 | |