Merge pull request #10808 from sdmaclea/PR-ARM64-enable-initblk-unroll
[platform/upstream/coreclr.git] / src / ildasm / dres.cpp
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 //
6 // Win32 Resource extractor
7 //
8 #include "ildasmpch.h"
9
10 #ifndef FEATURE_PAL
11 #include "debugmacros.h"
12 #include "corpriv.h"
13 #include "dasmenum.hpp"
14 #include "formattype.h"
15 #include "dis.h"
16 #include "resource.h"
17 #include "ilformatter.h"
18 #include "outstring.h"
19
20 #include "ceeload.h"
21 #include "dynamicarray.h"
22 extern IMAGE_COR20_HEADER *    g_CORHeader;
23 extern IMDInternalImport*      g_pImport;
24 extern PELoader * g_pPELoader;
25 extern IMetaDataImport2*        g_pPubImport;
26 extern char g_szAsmCodeIndent[];
27 extern unsigned g_uConsoleCP;
28
29 struct ResourceHeader
30 {
31     DWORD   dwDataSize;
32     DWORD   dwHeaderSize;
33     DWORD   dwTypeID;
34     DWORD   dwNameID;
35     DWORD   dwDataVersion;
36     WORD    wMemFlags;
37     WORD    wLangID;
38     DWORD   dwVersion;
39     DWORD   dwCharacteristics;
40     ResourceHeader()
41     {
42         memset(this,0,sizeof(ResourceHeader));
43         dwHeaderSize = sizeof(ResourceHeader);
44         dwTypeID = dwNameID = 0xFFFF;
45     };
46 };
47
48 struct ResourceNode
49 {
50     ResourceHeader  ResHdr;
51     IMAGE_RESOURCE_DATA_ENTRY DataEntry;
52     WCHAR* wzType;
53     WCHAR* wzName;
54     ResourceNode(DWORD tid, DWORD nid, DWORD lid, DWORD dataOffset, BYTE* ptrBase)
55     {
56         if(tid & 0x80000000)
57         {
58             ResHdr.dwTypeID = 0;
59             tid &= 0x7FFFFFFF;
60             WORD L = *((WORD*)(ptrBase+tid));
61             wzType = new WCHAR[L+1];
62             memcpy(wzType,ptrBase+tid+sizeof(WORD),L*sizeof(WCHAR));
63             wzType[L]=0;
64         }
65         else
66         {
67             ResHdr.dwTypeID = (0xFFFF |((tid & 0xFFFF)<<16));
68             wzType = NULL;
69         }
70         
71         if(nid & 0x80000000)
72         {
73             ResHdr.dwNameID = 0;
74             nid &= 0x7FFFFFFF;
75             WORD L = *((WORD*)(ptrBase+nid));
76             wzName = new WCHAR[L+1];
77             memcpy(wzName, ptrBase+nid+sizeof(WORD), L*sizeof(WCHAR));
78             wzName[L]=0;
79         }
80         else
81         {
82             ResHdr.dwNameID = (0xFFFF |((nid & 0xFFFF)<<16));
83             wzName = NULL;
84         }
85         
86         //ResHdr.dwTypeID = (tid & 0x80000000) ? tid : (0xFFFF |((tid & 0xFFFF)<<16));
87         //ResHdr.dwNameID = (nid & 0x80000000) ? nid : (0xFFFF |((nid & 0xFFFF)<<16));
88         ResHdr.wLangID = (WORD)lid;
89         if(ptrBase) memcpy(&DataEntry,(ptrBase+dataOffset),sizeof(IMAGE_RESOURCE_DATA_ENTRY));
90         ResHdr.dwDataSize = DataEntry.Size;
91     };
92     ~ResourceNode()
93     {
94         if(wzType) VDELETE(wzType);
95         if(wzName) VDELETE(wzName);
96     };
97     void Save(FILE* pF)
98     {
99         // Dump them to pF
100         BYTE* pbData;
101         DWORD   dwFiller = 0;
102         BYTE    bNil[3] = {0,0,0};
103         // For each resource write header and data
104         if(g_pPELoader->getVAforRVA(VAL32(DataEntry.OffsetToData), (void **) &pbData))
105         {
106             //fwrite(&(g_prResNodePtr[i]->ResHdr),g_prResNodePtr[i]->ResHdr.dwHeaderSize,1,pF);
107             ResHdr.dwHeaderSize = sizeof(ResourceHeader);
108             if(wzType) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzType) + 1)*sizeof(WCHAR) - sizeof(DWORD));
109             if(wzName) ResHdr.dwHeaderSize += (DWORD)((wcslen(wzName) + 1)*sizeof(WCHAR) - sizeof(DWORD));
110
111             //---- Constant part of the header: DWORD,DWORD
112             fwrite(&ResHdr.dwDataSize, sizeof(DWORD),1,pF);
113             fwrite(&ResHdr.dwHeaderSize, sizeof(DWORD),1,pF);
114             //--- Variable part of header: type and name
115             if(wzType)
116             {
117                 fwrite(wzType,(wcslen(wzType) + 1)*sizeof(WCHAR), 1, pF);
118                 dwFiller += (DWORD)wcslen(wzType) + 1;
119             }
120             else
121                 fwrite(&ResHdr.dwTypeID,sizeof(DWORD),1,pF);
122             if(wzName)
123             {
124                 fwrite(wzName,(wcslen(wzName) + 1)*sizeof(WCHAR), 1, pF);
125                 dwFiller += (DWORD)wcslen(wzName) + 1;
126             }
127             else
128                 fwrite(&ResHdr.dwNameID,sizeof(DWORD),1,pF);
129
130             // Align remaining fields on DWORD
131             if(dwFiller & 1)
132                 fwrite(bNil,2,1,pF);
133
134             //---- Constant part of the header: DWORD,WORD,WORD,DWORD,DWORD
135             fwrite(&ResHdr.dwDataVersion,8*sizeof(WORD),1,pF);
136             //---- Header done, now data
137             fwrite(pbData,VAL32(DataEntry.Size),1,pF);
138             dwFiller = VAL32(DataEntry.Size) & 3;
139             if(dwFiller)
140             {
141                 dwFiller = 4 - dwFiller;
142                 fwrite(bNil,dwFiller,1,pF);
143             }
144         }
145     };
146 };
147
148
149 #define RES_FILE_DUMP_ENABLED
150
151 DWORD   DumpResourceToFile(__in __nullterminated WCHAR*   wzFileName)
152 {
153
154     BYTE*   pbResBase;
155     FILE*   pF = NULL;
156     DWORD ret = 0;
157     DWORD   dwResDirRVA;
158     DWORD   dwResDirSize;
159     unsigned ulNumResNodes=0;
160     DynamicArray<ResourceNode*> g_prResNodePtr;
161
162     if (g_pPELoader->IsPE32())
163     {
164         IMAGE_OPTIONAL_HEADER32 *pOptHeader = &(g_pPELoader->ntHeaders32()->OptionalHeader);
165
166         dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
167         dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
168     }
169     else
170     {
171         IMAGE_OPTIONAL_HEADER64 *pOptHeader = &(g_pPELoader->ntHeaders64()->OptionalHeader);
172
173         dwResDirRVA = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
174         dwResDirSize = VAL32(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
175     }
176
177     if(dwResDirRVA && dwResDirSize)
178     {
179         if(g_pPELoader->getVAforRVA(dwResDirRVA, (void **) &pbResBase))
180         {
181             // First, pull out all resource nodes (tree leaves), see ResourceNode struct
182             PIMAGE_RESOURCE_DIRECTORY pirdType = (PIMAGE_RESOURCE_DIRECTORY)pbResBase;
183             PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeType = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbResBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
184             DWORD       dwTypeID;
185             unsigned short i = 0,N = pirdType->NumberOfNamedEntries+pirdType->NumberOfIdEntries;
186             PAL_CPP_TRY {
187                 for(i=0; i < N; i++, pirdeType++)
188                 {
189                     dwTypeID = VAL32(IMAGE_RDE_NAME(pirdeType));
190                     if(IMAGE_RDE_OFFSET_FIELD(pirdeType, DataIsDirectory))
191                     {
192                         BYTE*   pbNameBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeType, OffsetToDirectory));
193                         PIMAGE_RESOURCE_DIRECTORY pirdName = (PIMAGE_RESOURCE_DIRECTORY)pbNameBase;
194                         PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeName = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbNameBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
195                         DWORD   dwNameID;
196                         unsigned short i,N = VAL16(pirdName->NumberOfNamedEntries)+VAL16(pirdName->NumberOfIdEntries);
197
198                         for(i=0; i < N; i++, pirdeName++)
199                         {
200                             dwNameID = VAL32(IMAGE_RDE_NAME(pirdeName));
201                             if(IMAGE_RDE_OFFSET_FIELD(pirdeName, DataIsDirectory))
202                             {
203                                 BYTE*   pbLangBase = pbResBase + VAL32(IMAGE_RDE_OFFSET_FIELD(pirdeName, OffsetToDirectory));
204                                 PIMAGE_RESOURCE_DIRECTORY pirdLang = (PIMAGE_RESOURCE_DIRECTORY)pbLangBase;
205                                 PIMAGE_RESOURCE_DIRECTORY_ENTRY pirdeLang = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(pbLangBase+sizeof(IMAGE_RESOURCE_DIRECTORY));
206                                 DWORD   dwLangID;
207                                 unsigned short i,N = VAL16(pirdLang->NumberOfNamedEntries)+VAL16(pirdLang->NumberOfIdEntries);
208
209                                 for(i=0; i < N; i++, pirdeLang++)
210                                 {
211                                     dwLangID = VAL32(IMAGE_RDE_NAME(pirdeLang));
212                                     if(IMAGE_RDE_OFFSET_FIELD(pirdeLang, DataIsDirectory))
213                                     {
214                                         _ASSERTE(!"Resource hierarchy exceeds three levels");
215                                     }
216                                     else
217                                     {
218                                         g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,dwLangID, VAL32(IMAGE_RDE_OFFSET(pirdeLang)),pbResBase);
219                                     }
220                                 }
221                             }
222                             else
223                             {
224                                 g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,dwNameID,0,VAL32(IMAGE_RDE_OFFSET(pirdeName)),pbResBase);
225                             }
226                         }
227                     }
228                     else
229                     {
230                         g_prResNodePtr[ulNumResNodes++] = new ResourceNode(dwTypeID,0,0,VAL32(IMAGE_RDE_OFFSET(pirdeType)),pbResBase);
231                     }
232                 }
233             } PAL_CPP_CATCH_ALL {
234                 ret= 0xDFFFFFFF;
235                 ulNumResNodes = 0;
236             }
237             PAL_CPP_ENDTRY
238             // OK, all tree leaves are in ResourceNode structs, and ulNumResNodes ptrs are in g_prResNodePtr
239             if(ulNumResNodes)
240             {
241                 ret = 1;
242 #ifdef RES_FILE_DUMP_ENABLED
243
244                 _wfopen_s(&pF,wzFileName,L"wb");
245                 if(pF)
246                 {
247                     // Dump them to pF
248                     // Write dummy header
249                     ResourceHeader  *pRH = new ResourceHeader();
250                     fwrite(pRH,sizeof(ResourceHeader),1,pF);
251                     SDELETE(pRH);
252                     // For each resource write header and data
253                     PAL_CPP_TRY {
254                         for(i=0; i < ulNumResNodes; i++)
255                         {
256                             /*
257                             sprintf_s(szString,SZSTRING_SIZE,"// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
258                                 i+1,
259                                 g_prResNodePtr[i]->ResHdr.dwTypeID,
260                                 g_prResNodePtr[i]->ResHdr.dwNameID,
261                                 g_prResNodePtr[i]->ResHdr.wLangID,
262                                 VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
263                                 VAL32(g_prResNodePtr[i]->DataEntry.Size));
264                             printLine(NULL,szString);
265                             */
266                             g_prResNodePtr[i]->Save(pF);
267                             SDELETE(g_prResNodePtr[i]);
268                         }
269                     }
270                     PAL_CPP_CATCH_ALL {
271                         ret= 0xDFFFFFFF;
272                     }
273                     PAL_CPP_ENDTRY
274                     fclose(pF);
275                 }// end if file opened
276                 else ret = 0xEFFFFFFF;
277 #else
278                 // Dump to text, using wzFileName as GUICookie
279                 //char szString[4096];
280                 void* GUICookie = (void*)wzFileName;
281                 BYTE* pbData;
282                 printLine(GUICookie,"");
283                 sprintf_s(szString, _countof(szString), "// ========== Win32 Resource Entries (%d) ========",ulNumResNodes);
284                 for(i=0; i < ulNumResNodes; i++)
285                 {
286                     printLine(GUICookie,"");
287                     sprintf_s(szString, _countof(szString), "// Res.# %d Type=0x%X Name=0x%X Lang=0x%X DataOffset=0x%X DataLength=%d",
288                         i+1,
289                         g_prResNodePtr[i]->ResHdr.dwTypeID,
290                         g_prResNodePtr[i]->ResHdr.dwNameID,
291                         g_prResNodePtr[i]->ResHdr.wLangID,
292                         VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData),
293                         VAL32(g_prResNodePtr[i]->DataEntry.Size));
294                     printLine(GUICookie,szString);
295                     if(g_pPELoader->getVAforRVA(VAL32(g_prResNodePtr[i]->DataEntry.OffsetToData), (void **) &pbData))
296                     {
297                         strcat(g_szAsmCodeIndent,"//  ");
298                         strcpy(szString,g_szAsmCodeIndent);
299                         DumpByteArray(szString,pbData,VAL32(g_prResNodePtr[i]->DataEntry.Size),GUICookie);
300                         printLine(GUICookie,szString);
301                         g_szAsmCodeIndent[strlen(g_szAsmCodeIndent)-4] = 0;
302                     }
303                     SDELETE(g_prResNodePtr[i]);
304                 }
305                 ret = 1;
306 #endif
307             } // end if there are nodes
308         }// end if got ptr to resource
309         else ret = 0xFFFFFFFF;
310     } // end if there is resource
311     else ret = 0;
312
313     return ret;
314 }
315 #endif // FEATURE_PAL
316