VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use