1 /*
2  * PROJECT:     ReactOS api tests
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     Support functions for dbghelp api test
5  * COPYRIGHT:   Copyright 2017-2019 Mark Jansen (mark.jansen@reactos.org)
6  */
7 
8 #include <windows.h>
9 #include <stdio.h>
10 #include <zlib.h>
11 
12 #include "wine/test.h"
13 
14 extern IMAGE_DOS_HEADER __ImageBase;
15 
16 static char szTempPath[MAX_PATH];
17 
18 static const char* tmpdir()
19 {
20     if (szTempPath[0] == '\0')
21     {
22         GetTempPathA(MAX_PATH, szTempPath);
23         lstrcatA(szTempPath, "dbghelp_tst");
24     }
25     return szTempPath;
26 }
27 
28 static int extract_one(const char* filename, const char* resid)
29 {
30     HMODULE mod = (HMODULE)&__ImageBase;
31     HGLOBAL glob;
32     PVOID data, decompressed;
33     uLongf size, dstsize;
34     DWORD gccSize, dwErr;
35     HANDLE file;
36     int ret;
37     HRSRC rsrc = FindResourceA(mod, resid, MAKEINTRESOURCEA(RT_RCDATA));
38     ok(rsrc != 0, "Failed finding '%s' res\n", resid);
39     if (!rsrc)
40         return 0;
41 
42     size = SizeofResource(mod, rsrc);
43     glob = LoadResource(mod, rsrc);
44     ok(glob != NULL, "Failed loading '%s' res\n", resid);
45     if (!glob)
46         return 0;
47 
48     data = LockResource(glob);
49 
50     dstsize = 1024 * 256;
51     decompressed = malloc(dstsize);
52 
53     if (uncompress(decompressed, &dstsize, data, size) != Z_OK)
54     {
55         ok(0, "uncompress failed for %s\n", resid);
56         free(decompressed);
57         return 0;
58     }
59 
60 
61     file = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
62     gccSize = size;
63     ret = WriteFile(file, decompressed, dstsize, &gccSize, NULL);
64     dwErr = GetLastError();
65     CloseHandle(file);
66     free(decompressed);
67     ok(ret, "WriteFile failed (%d)\n", dwErr);
68     return ret && dstsize == gccSize;
69 }
70 
71 
72 int extract_msvc_dll(char szFile[MAX_PATH], char szPath[MAX_PATH])
73 {
74     const char* dir = tmpdir();
75     BOOL ret = CreateDirectoryA(dir, NULL);
76     ok(ret, "CreateDirectoryA failed(%d)\n", GetLastError());
77 
78     sprintf(szFile, "%s\\uffs.pdb", dir);
79     if (!extract_one(szFile, "msvc_uffs.pdb"))
80         return 0;
81 
82     sprintf(szFile, "%s\\uffs.dll", dir);
83     if (!extract_one(szFile, "msvc_uffs.dll"))
84         return 0;
85 
86     strcpy(szPath, dir);
87     return 1;
88 }
89 
90 void cleanup_msvc_dll()
91 {
92     char szFile[MAX_PATH];
93     BOOL ret;
94     const char* dir = tmpdir();
95 
96     sprintf(szFile, "%s\\uffs.pdb", dir);
97     ret = DeleteFileA(szFile);
98     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
99 
100     sprintf(szFile, "%s\\uffs.dll", dir);
101     ret = DeleteFileA(szFile);
102     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
103     ret = RemoveDirectoryA(dir);
104     ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
105 }
106 
107 int extract_gcc_dll(char szFile[MAX_PATH])
108 {
109     const char* dir = tmpdir();
110     BOOL ret = CreateDirectoryA(dir, NULL);
111     ok(ret, "CreateDirectoryA failed(%d)\n", GetLastError());
112 
113     sprintf(szFile, "%s\\uffs.dll", dir);
114     if (!extract_one(szFile, "gcc_uffs.dll"))
115         return 0;
116 
117     return 1;
118 }
119 
120 void cleanup_gcc_dll()
121 {
122     char szFile[MAX_PATH];
123     BOOL ret;
124     const char* dir = tmpdir();
125 
126     sprintf(szFile, "%s\\uffs.dll", dir);
127     ret = DeleteFileA(szFile);
128     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
129     ret = RemoveDirectoryA(dir);
130     ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
131 }
132 
133 
134 #if 0
135 static int compress_one(const char* src, const char* dest)
136 {
137     DWORD size, size2, res;
138     FILE* file = fopen(src, "rb");
139     fseek(file, 0, SEEK_END);
140     size = ftell(file);
141     fseek(file, 0, SEEK_SET);
142 
143     Bytef* buffer, *buffer2;
144     DWORD dwErr = GetLastError();
145 
146     buffer = malloc(size);
147     res = fread(buffer, 1, size, file);
148 
149     fclose(file);
150 
151     if (res != size)
152     {
153         printf("Could not read file: 0x%x\n", dwErr);
154         free(buffer);
155         CloseHandle(file);
156         return 0;
157     }
158     size2 = size *2;
159     buffer2 = malloc(size2);
160     res = compress(buffer2, &size2, buffer, size);
161 
162     free(buffer);
163 
164     if (Z_OK != res)
165     {
166         free(buffer2);
167         return 0;
168     }
169 
170     file = fopen(dest, "wb");
171     res = fwrite(buffer2, 1, size2, file);
172     fclose(file);
173 
174     free(buffer2);
175 
176     return size2 == res;
177 }
178 
179 void create_compressed_files()
180 {
181     SetCurrentDirectoryA("R:/src/trunk/reactos/modules/rostests/apitests/dbghelp");
182     if (!compress_one("testdata/msvc_uffs.dll", "testdata/msvc_uffs.dll.compr"))
183         printf("msvc_uffs.dll failed\n");
184     if (!compress_one("testdata/msvc_uffs.pdb", "testdata/msvc_uffs.pdb.compr"))
185         printf("msvc_uffs.pdb failed\n");
186     if (!compress_one("testdata/gcc_uffs.dll", "testdata/gcc_uffs.dll.compr"))
187         printf("gcc_uffs.dll failed\n");
188 }
189 #endif
190 
191 #if 0
192 typedef struct _SYMBOLFILE_HEADER {
193     ULONG SymbolsOffset;
194     ULONG SymbolsLength;
195     ULONG StringsOffset;
196     ULONG StringsLength;
197 } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
198 
199 typedef struct _ROSSYM_ENTRY {
200     ULONG Address;
201     ULONG FunctionOffset;
202     ULONG FileOffset;
203     ULONG SourceLine;
204 } ROSSYM_ENTRY, *PROSSYM_ENTRY;
205 
206 
207 static int is_metadata(const char* name)
208 {
209     size_t len = name ? strlen(name) : 0;
210     return len > 3 && name[0] == '_' && name[1] != '_' && name[len-1] == '_' && name[len-2] == '_';
211 };
212 
213 static void dump_rsym_internal(void* data)
214 {
215     PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data;
216     PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char *)data + RosSymHeader->SymbolsOffset);
217     size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
218     size_t i;
219     char *Strings = (char *)data + RosSymHeader->StringsOffset;
220 
221     for (i = 0; i < symbols; i++)
222     {
223         PROSSYM_ENTRY Entry = Entries + i;
224         if (!Entry->FileOffset)
225         {
226             if (Entry->SourceLine)
227                 printf("ERR: SOURCELINE (%D) ", Entry->SourceLine);
228             if (is_metadata(Strings + Entry->FunctionOffset))
229                 printf("metadata: %s: 0x%x\n", Strings + Entry->FunctionOffset, Entry->Address);
230             else
231                 printf("0x%x: %s\n", Entry->Address, Strings + Entry->FunctionOffset);
232         }
233         else
234         {
235             printf("0x%x: %s (%s:%u)\n", Entry->Address,
236                 Strings + Entry->FunctionOffset,
237                 Strings + Entry->FileOffset,
238                 Entry->SourceLine);
239         }
240     }
241 
242 }
243 
244 void dump_rsym(const char* filename)
245 {
246     char* data;
247     long size, res;
248     PIMAGE_FILE_HEADER PEFileHeader;
249     PIMAGE_OPTIONAL_HEADER PEOptHeader;
250     PIMAGE_SECTION_HEADER PESectionHeaders;
251     WORD i;
252 
253     FILE* f = fopen(filename, "rb");
254 
255     fseek(f, 0, SEEK_END);
256     size = ftell(f);
257     fseek(f, 0, SEEK_SET);
258 
259     data = malloc(size);
260     res = fread(data, 1, size, f);
261     fclose(f);
262 
263     PEFileHeader = (PIMAGE_FILE_HEADER)((char *)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew + sizeof(ULONG));
264     PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
265     PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *)PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
266 
267     for (i = 0; i < PEFileHeader->NumberOfSections; i++)
268     {
269         if (!strcmp((char *)PESectionHeaders[i].Name, ".rossym"))
270         {
271             dump_rsym_internal(data + PESectionHeaders[i].PointerToRawData);
272             break;
273         }
274     }
275     free(data);
276 }
277 
278 #endif
279