1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Support functions for dbghelp api test
5  * PROGRAMMER:      Mark Jansen
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_exe(char szFile[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     return 1;
87 }
88 
89 void cleanup_msvc_exe()
90 {
91     char szFile[MAX_PATH];
92     BOOL ret;
93     const char* dir = tmpdir();
94 
95     sprintf(szFile, "%s\\uffs.pdb", dir);
96     ret = DeleteFileA(szFile);
97     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
98 
99     sprintf(szFile, "%s\\uffs.dll", dir);
100     ret = DeleteFileA(szFile);
101     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
102     ret = RemoveDirectoryA(dir);
103     ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
104 }
105 
106 int extract_gcc_exe(char szFile[MAX_PATH])
107 {
108     const char* dir = tmpdir();
109     BOOL ret = CreateDirectoryA(dir, NULL);
110     ok(ret, "CreateDirectoryA failed(%d)\n", GetLastError());
111 
112     sprintf(szFile, "%s\\uffs.dll", dir);
113     if (!extract_one(szFile, "gcc_uffs.dll"))
114         return 0;
115 
116     return 1;
117 }
118 
119 void cleanup_gcc_exe()
120 {
121     char szFile[MAX_PATH];
122     BOOL ret;
123     const char* dir = tmpdir();
124 
125     sprintf(szFile, "%s\\uffs.dll", dir);
126     ret = DeleteFileA(szFile);
127     ok(ret, "DeleteFileA failed(%d)\n", GetLastError());
128     ret = RemoveDirectoryA(dir);
129     ok(ret, "RemoveDirectoryA failed(%d)\n", GetLastError());
130 }
131 
132 
133 #if 0
134 static int compress_one(const char* src, const char* dest)
135 {
136     DWORD size, size2, res;
137     FILE* file = fopen(src, "rb");
138     fseek(file, 0, SEEK_END);
139     size = ftell(file);
140     fseek(file, 0, SEEK_SET);
141 
142     Bytef* buffer, *buffer2;
143     DWORD dwErr = GetLastError();
144 
145     buffer = malloc(size);
146     res = fread(buffer, 1, size, file);
147 
148     fclose(file);
149 
150     if (res != size)
151     {
152         printf("Could not read file: 0x%x\n", dwErr);
153         free(buffer);
154         CloseHandle(file);
155         return 0;
156     }
157     size2 = size *2;
158     buffer2 = malloc(size2);
159     res = compress(buffer2, &size2, buffer, size);
160 
161     free(buffer);
162 
163     if (Z_OK != res)
164     {
165         free(buffer2);
166         return 0;
167     }
168 
169     file = fopen(dest, "wb");
170     res = fwrite(buffer2, 1, size2, file);
171     fclose(file);
172 
173     free(buffer2);
174 
175     return size2 == res;
176 }
177 
178 void create_compressed_files()
179 {
180     SetCurrentDirectoryA("R:/src/trunk/reactos/modules/rostests/apitests/dbghelp");
181     if (!compress_one("testdata/msvc_uffs.dll", "testdata/msvc_uffs.dll.compr"))
182         printf("msvc_uffs.dll failed\n");
183     if (!compress_one("testdata/msvc_uffs.pdb", "testdata/msvc_uffs.pdb.compr"))
184         printf("msvc_uffs.pdb failed\n");
185     if (!compress_one("testdata/gcc_uffs.dll", "testdata/gcc_uffs.dll.compr"))
186         printf("gcc_uffs.dll failed\n");
187 }
188 #endif
189 
190 #if 0
191 typedef struct _SYMBOLFILE_HEADER {
192     ULONG SymbolsOffset;
193     ULONG SymbolsLength;
194     ULONG StringsOffset;
195     ULONG StringsLength;
196 } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER;
197 
198 typedef struct _ROSSYM_ENTRY {
199     ULONG Address;
200     ULONG FunctionOffset;
201     ULONG FileOffset;
202     ULONG SourceLine;
203 } ROSSYM_ENTRY, *PROSSYM_ENTRY;
204 
205 
206 static int is_metadata(const char* name)
207 {
208     size_t len = name ? strlen(name) : 0;
209     return len > 3 && name[0] == '_' && name[1] != '_' && name[len-1] == '_' && name[len-2] == '_';
210 };
211 
212 static void dump_rsym_internal(void* data)
213 {
214     PSYMBOLFILE_HEADER RosSymHeader = (PSYMBOLFILE_HEADER)data;
215     PROSSYM_ENTRY Entries = (PROSSYM_ENTRY)((char *)data + RosSymHeader->SymbolsOffset);
216     size_t symbols = RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
217     size_t i;
218     char *Strings = (char *)data + RosSymHeader->StringsOffset;
219 
220     for (i = 0; i < symbols; i++)
221     {
222         PROSSYM_ENTRY Entry = Entries + i;
223         if (!Entry->FileOffset)
224         {
225             if (Entry->SourceLine)
226                 printf("ERR: SOURCELINE (%D) ", Entry->SourceLine);
227             if (is_metadata(Strings + Entry->FunctionOffset))
228                 printf("metadata: %s: 0x%x\n", Strings + Entry->FunctionOffset, Entry->Address);
229             else
230                 printf("0x%x: %s\n", Entry->Address, Strings + Entry->FunctionOffset);
231         }
232         else
233         {
234             printf("0x%x: %s (%s:%u)\n", Entry->Address,
235                 Strings + Entry->FunctionOffset,
236                 Strings + Entry->FileOffset,
237                 Entry->SourceLine);
238         }
239     }
240 
241 }
242 
243 void dump_rsym(const char* filename)
244 {
245     char* data;
246     long size, res;
247     PIMAGE_FILE_HEADER PEFileHeader;
248     PIMAGE_OPTIONAL_HEADER PEOptHeader;
249     PIMAGE_SECTION_HEADER PESectionHeaders;
250     WORD i;
251 
252     FILE* f = fopen(filename, "rb");
253 
254     fseek(f, 0, SEEK_END);
255     size = ftell(f);
256     fseek(f, 0, SEEK_SET);
257 
258     data = malloc(size);
259     res = fread(data, 1, size, f);
260     fclose(f);
261 
262     PEFileHeader = (PIMAGE_FILE_HEADER)((char *)data + ((PIMAGE_DOS_HEADER)data)->e_lfanew + sizeof(ULONG));
263     PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
264     PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *)PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
265 
266     for (i = 0; i < PEFileHeader->NumberOfSections; i++)
267     {
268         if (!strcmp((char *)PESectionHeaders[i].Name, ".rossym"))
269         {
270             dump_rsym_internal(data + PESectionHeaders[i].PointerToRawData);
271             break;
272         }
273     }
274     free(data);
275 }
276 
277 #endif
278