VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrMemory.cpp@ 90803

Last change on this file since 90803 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.6 KB
Line 
1
2/* $Id: ldrMemory.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
3/** @file
4 * IPRT - Binary Image Loader, The Memory/Debugger Oriented Parts.
5 */
6
7/*
8 * Copyright (C) 2006-2020 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * The contents of this file may alternatively be used under the terms
19 * of the Common Development and Distribution License Version 1.0
20 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
21 * VirtualBox OSE distribution, in which case the provisions of the
22 * CDDL are applicable instead of those of the GPL.
23 *
24 * You may elect to license modified versions of this file under the
25 * terms and conditions of either the GPL or the CDDL or both.
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP RTLOGGROUP_LDR
33#include <iprt/ldr.h>
34#include "internal/iprt.h"
35
36#include <iprt/alloc.h>
37#include <iprt/assert.h>
38#include <iprt/log.h>
39#include <iprt/err.h>
40#include <iprt/string.h>
41#include "internal/ldr.h"
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Memory reader (for debuggers) instance.
49 */
50typedef struct RTLDRRDRMEM
51{
52 /** The core. */
53 RTLDRREADER Core;
54 /** The size of the image. */
55 size_t cbImage;
56 /** The current offset. */
57 size_t offCur;
58
59 /** User parameter for the reader and destructor functions.*/
60 void *pvUser;
61 /** Read function. */
62 PFNRTLDRRDRMEMREAD pfnRead;
63 /** Destructor callback. */
64 PFNRTLDRRDRMEMDTOR pfnDtor;
65
66 /** Mapping of the file. */
67 void *pvMapping;
68 /** Mapping usage counter. */
69 uint32_t cMappings;
70
71 /** The fake filename (variable size). */
72 char szName[1];
73} RTLDRRDRMEM;
74/** Memory based loader reader instance data. */
75typedef RTLDRRDRMEM *PRTLDRRDRMEM;
76
77
78/**
79 * @callback_method_impl{FNRTLDRRDRMEMDTOR,
80 * Default destructor - pvUser points to the image memory block}
81 */
82static DECLCALLBACK(void) rtldrRdrMemDefaultDtor(void *pvUser, size_t cbImage)
83{
84 RT_NOREF(cbImage);
85 RTMemFree(pvUser);
86}
87
88
89/**
90 * @callback_method_impl{FNRTLDRRDRMEMREAD,
91 * Default memory reader - pvUser points to the image memory block}
92 */
93static DECLCALLBACK(int) rtldrRdrMemDefaultReader(void *pvBuf, size_t cb, size_t off, void *pvUser)
94{
95 memcpy(pvBuf, (uint8_t *)pvUser + off, cb);
96 return VINF_SUCCESS;
97}
98
99
100/** @interface_method_impl{RTLDRREADER,pfnRead} */
101static DECLCALLBACK(int) rtldrRdrMem_Read(PRTLDRREADER pReader, void *pvBuf, size_t cb, RTFOFF off)
102{
103 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
104
105 AssertReturn(off >= 0, VERR_INVALID_PARAMETER);
106 if ( cb > pThis->cbImage
107 || off > (RTFOFF)pThis->cbImage
108 || off + (RTFOFF)cb > (RTFOFF)pThis->cbImage)
109 {
110 pThis->offCur = pThis->cbImage;
111 return VERR_EOF;
112 }
113
114 int rc = pThis->pfnRead(pvBuf, cb, (size_t)off, pThis->pvUser);
115 if (RT_SUCCESS(rc))
116 pThis->offCur = (size_t)off + cb;
117 else
118 pThis->offCur = ~(size_t)0;
119 return rc;
120}
121
122
123/** @interface_method_impl{RTLDRREADER,pfnTell} */
124static DECLCALLBACK(RTFOFF) rtldrRdrMem_Tell(PRTLDRREADER pReader)
125{
126 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
127 return pThis->offCur;
128}
129
130
131/** @interface_method_impl{RTLDRREADER,pfnSize} */
132static DECLCALLBACK(uint64_t) rtldrRdrMem_Size(PRTLDRREADER pReader)
133{
134 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
135 return pThis->cbImage;
136}
137
138
139/** @interface_method_impl{RTLDRREADER,pfnLogName} */
140static DECLCALLBACK(const char *) rtldrRdrMem_LogName(PRTLDRREADER pReader)
141{
142 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
143 return pThis->szName;
144}
145
146
147/** @interface_method_impl{RTLDRREADER,pfnMap} */
148static DECLCALLBACK(int) rtldrRdrMem_Map(PRTLDRREADER pReader, const void **ppvBits)
149{
150 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
151
152 /*
153 * Already mapped?
154 */
155 if (pThis->pvMapping)
156 {
157 pThis->cMappings++;
158 *ppvBits = pThis->pvMapping;
159 return VINF_SUCCESS;
160 }
161
162 /*
163 * Allocate memory.
164 */
165 pThis->pvMapping = RTMemAlloc(pThis->cbImage);
166 if (!pThis->pvMapping)
167 return VERR_NO_MEMORY;
168 int rc = rtldrRdrMem_Read(pReader, pThis->pvMapping, pThis->cbImage, 0);
169 if (RT_SUCCESS(rc))
170 {
171 pThis->cMappings = 1;
172 *ppvBits = pThis->pvMapping;
173 }
174 else
175 {
176 RTMemFree(pThis->pvMapping);
177 pThis->pvMapping = NULL;
178 }
179
180 return rc;
181}
182
183
184/** @interface_method_impl{RTLDRREADER,pfnUnmap} */
185static DECLCALLBACK(int) rtldrRdrMem_Unmap(PRTLDRREADER pReader, const void *pvBits)
186{
187 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
188 AssertReturn(pThis->cMappings > 0, VERR_INVALID_PARAMETER);
189
190 if (!--pThis->cMappings)
191 {
192 RTMemFree(pThis->pvMapping);
193 pThis->pvMapping = NULL;
194 }
195
196 NOREF(pvBits);
197 return VINF_SUCCESS;
198}
199
200
201/** @interface_method_impl{RTLDRREADER,pfnDestroy} */
202static DECLCALLBACK(int) rtldrRdrMem_Destroy(PRTLDRREADER pReader)
203{
204 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)pReader;
205 pThis->pfnDtor(pThis->pvUser, pThis->cbImage);
206 pThis->pfnDtor = NULL;
207 pThis->pvUser = NULL;
208 RTMemFree(pThis);
209 return VINF_SUCCESS;
210}
211
212
213/**
214 * Opens a memory based loader reader.
215 *
216 * @returns iprt status code.
217 * @param ppReader Where to store the reader instance on success.
218 * @param pszName The name to give the image.
219 * @param cbImage The image size.
220 * @param pfnRead The reader function. If NULL, a default reader is
221 * used that assumes pvUser points to a memory buffer
222 * of at least @a cbImage size.
223 * @param pfnDtor The destructor. If NULL, a default destructore is
224 * used that will call RTMemFree on @a pvUser.
225 * @param pvUser User argument. If either @a pfnRead or @a pfnDtor
226 * is NULL, this must be a pointer to readable memory
227 * (see above).
228 */
229static int rtldrRdrMem_Create(PRTLDRREADER *ppReader, const char *pszName, size_t cbImage,
230 PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser)
231{
232#if ARCH_BITS > 32 /* 'ing gcc. */
233 AssertReturn(cbImage < RTFOFF_MAX, VERR_INVALID_PARAMETER);
234#endif
235 AssertReturn((RTFOFF)cbImage > 0, VERR_INVALID_PARAMETER);
236
237 size_t cchName = strlen(pszName);
238 int rc = VERR_NO_MEMORY;
239 PRTLDRRDRMEM pThis = (PRTLDRRDRMEM)RTMemAlloc(sizeof(*pThis) + cchName);
240 if (pThis)
241 {
242 memcpy(pThis->szName, pszName, cchName + 1);
243 pThis->cbImage = cbImage;
244 pThis->pvUser = pvUser;
245 pThis->offCur = 0;
246 pThis->pvUser = pvUser;
247 pThis->pfnRead = pfnRead ? pfnRead : rtldrRdrMemDefaultReader;
248 pThis->pfnDtor = pfnDtor ? pfnDtor : rtldrRdrMemDefaultDtor;
249 pThis->pvMapping = NULL;
250 pThis->cMappings = 0;
251 pThis->Core.uMagic = RTLDRREADER_MAGIC;
252 pThis->Core.pfnRead = rtldrRdrMem_Read;
253 pThis->Core.pfnTell = rtldrRdrMem_Tell;
254 pThis->Core.pfnSize = rtldrRdrMem_Size;
255 pThis->Core.pfnLogName = rtldrRdrMem_LogName;
256 pThis->Core.pfnMap = rtldrRdrMem_Map;
257 pThis->Core.pfnUnmap = rtldrRdrMem_Unmap;
258 pThis->Core.pfnDestroy = rtldrRdrMem_Destroy;
259 *ppReader = &pThis->Core;
260 return VINF_SUCCESS;
261 }
262
263 *ppReader = NULL;
264 return rc;
265}
266
267
268RTDECL(int) RTLdrOpenInMemory(const char *pszName, uint32_t fFlags, RTLDRARCH enmArch, size_t cbImage,
269 PFNRTLDRRDRMEMREAD pfnRead, PFNRTLDRRDRMEMDTOR pfnDtor, void *pvUser,
270 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
271{
272 LogFlow(("RTLdrOpenInMemory: pszName=%p:{%s} fFlags=%#x enmArch=%d cbImage=%#zx pfnRead=%p pfnDtor=%p pvUser=%p phLdrMod=%p pErrInfo=%p\n",
273 pszName, pszName, fFlags, enmArch, cbImage, pfnRead, pfnDtor, pvUser, phLdrMod, pErrInfo));
274
275 if (!pfnRead || !pfnDtor)
276 AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
277 if (!pfnDtor)
278 pfnDtor = rtldrRdrMemDefaultDtor;
279 else
280 AssertPtrReturn(pfnDtor, VERR_INVALID_POINTER);
281
282 /* The rest of the validations will call the destructor. */
283 AssertMsgReturnStmt(!(fFlags & ~RTLDR_O_VALID_MASK), ("%#x\n", fFlags),
284 pfnDtor(pvUser, cbImage), VERR_INVALID_PARAMETER);
285 AssertMsgReturnStmt(enmArch > RTLDRARCH_INVALID && enmArch < RTLDRARCH_END, ("%d\n", enmArch),
286 pfnDtor(pvUser, cbImage), VERR_INVALID_PARAMETER);
287 if (!pfnRead)
288 pfnRead = rtldrRdrMemDefaultReader;
289 else
290 AssertReturnStmt(RT_VALID_PTR(pfnRead), pfnDtor(pvUser, cbImage), VERR_INVALID_POINTER);
291 AssertReturnStmt(cbImage > 0, pfnDtor(pvUser, cbImage), VERR_INVALID_PARAMETER);
292
293 /*
294 * Resolve RTLDRARCH_HOST.
295 */
296 if (enmArch == RTLDRARCH_HOST)
297 enmArch = RTLdrGetHostArch();
298
299 /*
300 * Create file reader & invoke worker which identifies and calls the image interpreter.
301 */
302 PRTLDRREADER pReader = NULL; /* gcc may be wrong */
303 int rc = rtldrRdrMem_Create(&pReader, pszName, cbImage, pfnRead, pfnDtor, pvUser);
304 if (RT_SUCCESS(rc))
305 {
306 rc = RTLdrOpenWithReader(pReader, fFlags, enmArch, phLdrMod, pErrInfo);
307 if (RT_SUCCESS(rc))
308 {
309 LogFlow(("RTLdrOpen: return %Rrc *phLdrMod=%p\n", rc, *phLdrMod));
310 return rc;
311 }
312
313 pReader->pfnDestroy(pReader);
314 }
315 else
316 {
317 pfnDtor(pvUser, cbImage);
318 rc = RTErrInfoSetF(pErrInfo, rc, "rtldrRdrMem_Create failed: %Rrc", rc);
319 }
320 *phLdrMod = NIL_RTLDRMOD;
321
322 LogFlow(("RTLdrOpen: return %Rrc\n", rc));
323 return rc;
324}
325RT_EXPORT_SYMBOL(RTLdrOpenInMemory);
326
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette