mscoree: Implement ICorDebug EnumerateProcesses.
[wine] / dlls / mscoree / assembly.c
1 /*
2  * assembly parser
3  *
4  * Copyright 2008 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "winver.h"
28 #include "dbghelp.h"
29 #include "ole2.h"
30 #include "mscoree.h"
31 #include "corhdr.h"
32 #include "metahost.h"
33 #include "cordebug.h"
34 #include "wine/list.h"
35 #include "mscoree_private.h"
36
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39
40 typedef struct
41 {
42     ULONG Signature;
43     USHORT MajorVersion;
44     USHORT MinorVersion;
45     ULONG Reserved;
46     ULONG VersionLength;
47     LPSTR Version;
48     BYTE Flags;
49     WORD Streams;
50 } METADATAHDR;
51
52 typedef struct
53 {
54     DWORD Offset;
55     DWORD Size;
56 } METADATASTREAMHDR;
57
58 typedef struct tagCLRTABLE
59 {
60     INT rows;
61     DWORD offset;
62 } CLRTABLE;
63
64 struct tagASSEMBLY
65 {
66     LPWSTR path;
67
68     HANDLE hfile;
69     HANDLE hmap;
70     BYTE *data;
71
72     IMAGE_NT_HEADERS *nthdr;
73     IMAGE_COR20_HEADER *corhdr;
74
75     METADATAHDR *metadatahdr;
76 };
77
78 static inline LPWSTR strdupW(LPCWSTR src)
79 {
80     LPWSTR dest;
81
82     if (!src)
83         return NULL;
84
85     dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR));
86     if (dest)
87         lstrcpyW(dest, src);
88
89     return dest;
90 }
91
92 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
93 {
94     METADATAHDR *metadatahdr;
95     BYTE *ptr, *dest;
96     DWORD size, ofs;
97     ULONG rva;
98
99     rva = assembly->corhdr->MetaData.VirtualAddress;
100     ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
101     if (!ptr)
102         return E_FAIL;
103
104     metadatahdr = (METADATAHDR *)ptr;
105
106     assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
107     if (!assembly->metadatahdr)
108         return E_OUTOFMEMORY;
109
110     size = FIELD_OFFSET(METADATAHDR, Version);
111     memcpy(assembly->metadatahdr, metadatahdr, size);
112
113     assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version;
114
115     ofs = FIELD_OFFSET(METADATAHDR, Flags);
116     ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
117     dest = (BYTE *)assembly->metadatahdr + ofs;
118     memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
119
120     *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
121
122     return S_OK;
123 }
124
125 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
126 {
127     HRESULT hr;
128     DWORD hdrsz;
129
130     hr = parse_metadata_header(assembly, &hdrsz);
131     if (FAILED(hr))
132         return hr;
133
134     return S_OK;
135 }
136
137 static HRESULT parse_pe_header(ASSEMBLY *assembly)
138 {
139     IMAGE_DATA_DIRECTORY *datadirs;
140
141     assembly->nthdr = ImageNtHeader(assembly->data);
142     if (!assembly->nthdr)
143         return E_FAIL;
144
145     if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
146     {
147         IMAGE_OPTIONAL_HEADER64 *opthdr =
148                 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
149         datadirs = opthdr->DataDirectory;
150     }
151     else
152     {
153         IMAGE_OPTIONAL_HEADER32 *opthdr =
154                 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
155         datadirs = opthdr->DataDirectory;
156     }
157
158     if (!datadirs)
159         return E_FAIL;
160
161     if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
162         !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
163     {
164         return E_FAIL;
165     }
166
167     assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
168         datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
169     if (!assembly->corhdr)
170         return E_FAIL;
171
172     return S_OK;
173 }
174
175 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
176 {
177     ASSEMBLY *assembly;
178     HRESULT hr;
179
180     *out = NULL;
181
182     assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
183     if (!assembly)
184         return E_OUTOFMEMORY;
185
186     assembly->path = strdupW(file);
187     if (!assembly->path)
188     {
189         hr = E_OUTOFMEMORY;
190         goto failed;
191     }
192
193     assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
194                                   NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
195     if (assembly->hfile == INVALID_HANDLE_VALUE)
196     {
197         hr = HRESULT_FROM_WIN32(GetLastError());
198         goto failed;
199     }
200
201     assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
202                                         0, 0, NULL);
203     if (!assembly->hmap)
204     {
205         hr = HRESULT_FROM_WIN32(GetLastError());
206         goto failed;
207     }
208
209     assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
210     if (!assembly->data)
211     {
212         hr = HRESULT_FROM_WIN32(GetLastError());
213         goto failed;
214     }
215
216     hr = parse_pe_header(assembly);
217     if (FAILED(hr)) goto failed;
218
219     hr = parse_clr_metadata(assembly);
220     if (FAILED(hr)) goto failed;
221
222     *out = assembly;
223     return S_OK;
224
225 failed:
226     assembly_release(assembly);
227     return hr;
228 }
229
230 HRESULT assembly_release(ASSEMBLY *assembly)
231 {
232     if (!assembly)
233         return S_OK;
234
235     HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
236     HeapFree(GetProcessHeap(), 0, assembly->path);
237     UnmapViewOfFile(assembly->data);
238     CloseHandle(assembly->hmap);
239     CloseHandle(assembly->hfile);
240     HeapFree(GetProcessHeap(), 0, assembly);
241
242     return S_OK;
243 }
244
245 HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version)
246 {
247     *version = assembly->metadatahdr->Version;
248
249     return S_OK;
250 }