source: trunk/kLdr/kLdrRdrFile.c@ 3232

Last change on this file since 3232 was 2974, checked in by bird, 19 years ago

off_t -> KLDRFOFF.

  • Property svn:keywords set to Id
File size: 34.6 KB
RevLine 
[2826]1/* $Id: kLdrRdrFile.c 2974 2007-02-14 10:12:44Z bird $ */
[2825]2/** @file
3 *
4 * kLdr - The Dynamic Loader, file abstraction.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#ifdef __OS2__
32# define INCL_ERRORS
33# define INCL_BASE
34# include <os2.h>
35
36#elif defined(__WIN32__) || defined(__WIN64__) || defined(__WIN__)
[2861]37# define WIN32_NO_STATUS
[2825]38# include <Windows.h>
39# ifndef __WIN__
40# define __WIN__
41# endif
[2861]42# include <ntsecapi.h>
43# include <ntstatus.h>
[2825]44
[2883]45 /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
[2861]46 typedef LONG NTSTATUS;
47 #define NT_SUCCESS(x) ((x)>=0)
48
49 typedef struct _OBJECT_ATTRIBUTES
50 {
51 ULONG Length;
52 HANDLE RootDirectory;
53 PUNICODE_STRING ObjectName;
54 ULONG Attributes;
55 PVOID SecurityDescriptor;
56 PVOID SecurityQualityOfService;
57 } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
58
59 typedef enum _SECTION_INHERIT
60 {
61 ViewShare = 1,
62 ViewUnmap = 2
63 } SECTION_INHERIT;
64
65# define NTOSAPI __declspec(dllimport)
66# define NtCurrentProcess() GetCurrentProcess()
67
68# ifndef MEM_DOS_LIM
69# define MEM_DOS_LIM 0x40000000UL
70# endif
71
72 NTOSAPI
73 NTSTATUS
74 NTAPI
75 NtCreateSection(
76 OUT PHANDLE SectionHandle,
77 IN ACCESS_MASK DesiredAccess,
78 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
79 IN PLARGE_INTEGER SectionSize OPTIONAL,
80 IN ULONG Protect,
81 IN ULONG Attributes,
82 IN HANDLE FileHandle OPTIONAL
83 );
84
85 NTOSAPI
86 NTSTATUS
87 NTAPI
88 NtMapViewOfSection(
89 IN HANDLE SectionHandle,
90 IN HANDLE ProcessHandle,
91 IN OUT PVOID *BaseAddress,
92 IN ULONG ZeroBits,
93 IN ULONG CommitSize,
94 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
95 IN OUT PSIZE_T ViewSize,
96 IN SECTION_INHERIT InheritDisposition,
97 IN ULONG AllocationType,
98 IN ULONG Protect
99 );
100
101 NTOSAPI
102 NTSTATUS
103 NTAPI
104 NtUnmapViewOfSection(
105 IN HANDLE ProcessHandle,
106 IN PVOID BaseAddress
107 );
108
109 NTOSAPI
110 NTSTATUS
111 NTAPI
112 NtClose(
113 IN HANDLE Handle
114 );
115
116 NTOSAPI
117 NTSTATUS
118 NTAPI
119 ZwProtectVirtualMemory(
120 IN HANDLE ProcessHandle,
121 IN OUT PVOID *BaseAddress,
122 IN OUT PULONG ProtectSize,
123 IN ULONG NewProtect,
124 OUT PULONG OldProtect
125 );
126# define NtProtectVirtualMemory ZwProtectVirtualMemory
127
128 NTOSAPI
129 NTSTATUS
130 NTAPI
131 NtAllocateVirtualMemory(
132 IN HANDLE ProcessHandle,
133 IN OUT PVOID *BaseAddress,
134 IN ULONG ZeroBits,
135 IN OUT PULONG AllocationSize,
136 IN ULONG AllocationType,
137 IN ULONG Protect
138 );
139
140 NTOSAPI
141 NTSTATUS
142 NTAPI
143 NtFreeVirtualMemory(
144 IN HANDLE ProcessHandle,
145 IN OUT PVOID *BaseAddress,
146 IN OUT PULONG FreeSize,
147 IN ULONG FreeType
148 );
149
[2825]150#else
151# error "port me"
152#endif
153
154#include <kLdr.h>
155#include "kLdrHlp.h"
156
157
158/*******************************************************************************
[2861]159* Defined Constants And Macros *
160*******************************************************************************/
161/** @def KLDRRDRFILE_STRICT
162 * Define KLDRRDRFILE_STRICT to enabled strict checks in KLDRRDRFILE. */
163#define KLDRRDRFILE_STRICT 1
164
165/** @def KLDRRDRFILE_ASSERT
166 * Assert that an expression is true when KLDRRDRFILE_STRICT is defined.
167 */
168#ifdef KLDRRDRFILE_STRICT
169# define KLDRRDRFILE_ASSERT(expr) kldrHlpAssert(expr)
170#else
171# define KLDRRDRFILE_ASSERT(expr) do {} while (0)
172#endif
173
174
175/*******************************************************************************
[2825]176* Structures and Typedefs *
177*******************************************************************************/
178/**
[2860]179 * Prepared stuff.
180 */
181typedef struct KLDRRDRFILEPREP
182{
183 /** The address of the prepared region. */
184 void *pv;
185 /** The size of the prepared region. */
186 size_t cb;
187#if defined(__WIN__) || defined(__NT__)
188 /** Handle to the section created to map the file. */
189 HANDLE hSection;
190#endif
191} KLDRRDRFILEPREP, *PKLDRRDRFILEPREP;
192
193/**
[2825]194 * The file provier instance for native files.
195 */
196typedef struct KLDRRDRFILE
197{
198 /** The file reader vtable. */
[2860]199 KLDRRDR Core;
[2825]200 /** The file handle. */
201#ifdef __OS2__
[2860]202 HFILE File;
[2825]203#elif defined(__WIN__) || defined(__NT__)
[2860]204 HANDLE File;
[2825]205#else
206# error "Port me!"
207#endif
208 /** The current file offset. */
[2974]209 KLDRFOFF off;
[2825]210 /** The file size. */
[2974]211 KLDRFOFF cb;
[2860]212 /** Array where we stuff the mapping area data. */
213 KLDRRDRFILEPREP aPreps[4];
214 /** The number of current preps. */
215 uint32_t cPreps;
[2825]216 /** Number of mapping references. */
[2860]217 int32_t cMappings;
[2825]218 /** The memory mapping. */
[2860]219 void *pvMapping;
[2825]220 /** The filename. */
[2860]221 char szFilename[1];
[2825]222} KLDRRDRFILE, *PKLDRRDRFILE;
223
224
225/*******************************************************************************
226* Internal Functions *
227*******************************************************************************/
[2829]228static void kldrRdrFileDone(PKLDRRDR pRdr);
[2861]229static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
230static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
231static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
232static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
233static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments);
234static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments);
[2883]235static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
[2861]236static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
[2857]237static size_t kldrRdrFilePageSize(PKLDRRDR pRdr);
[2825]238static const char *kldrRdrFileName(PKLDRRDR pRdr);
[2974]239static KLDRFOFF kldrRdrFileTell(PKLDRRDR pRdr);
240static KLDRFOFF kldrRdrFileSize(PKLDRRDR pRdr);
[2825]241static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits);
242static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits);
[2974]243static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, KLDRFOFF off);
[2825]244static int kldrRdrFileDestroy(PKLDRRDR pRdr);
245static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename);
246
247
248/*******************************************************************************
249* Global Variables *
250*******************************************************************************/
251/** Native file provider operations. */
252const KLDRRDROPS g_kLdrRdrFileOps =
253{
254 "native file",
255 NULL,
256 kldrRdrFileCreate,
257 kldrRdrFileDestroy,
258 kldrRdrFileRead,
259 kldrRdrFileAllMap,
260 kldrRdrFileAllUnmap,
261 kldrRdrFileSize,
262 kldrRdrFileTell,
[2829]263 kldrRdrFileName,
[2857]264 kldrRdrFilePageSize,
[2829]265 kldrRdrFileMap,
[2861]266 kldrRdrFileRefresh,
[2829]267 kldrRdrFileProtect,
268 kldrRdrFileUnmap,
269 kldrRdrFileDone,
270 42
[2825]271};
272
273
[2861]274#if defined(__WIN__) || defined(__NT__)
275/**
276 * Converts a kLdr segment protection to NT protection for a mapping.
277 *
278 * @returns Nt page protection.
279 * @param enmProt kLdr protection.
280 */
281static ULONG kldrRdrFileGetNtMapProt(KLDRPROT enmProt)
[2829]282{
[2861]283 switch (enmProt)
284 {
285 case KLDRPROT_NOACCESS: return PAGE_NOACCESS;
286 case KLDRPROT_READONLY: return PAGE_READONLY;
287 case KLDRPROT_READWRITE: return PAGE_READWRITE;
288 case KLDRPROT_WRITECOPY: return PAGE_WRITECOPY;
289 case KLDRPROT_EXECUTE: return PAGE_EXECUTE;
290 case KLDRPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
291 case KLDRPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
292 case KLDRPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY;
293 default: return ~(ULONG)0;
294 }
[2829]295}
[2825]296
[2860]297
298/**
[2861]299 * Converts a kLdr segment protection to NT protection for a allocation.
[2860]300 *
[2861]301 * @returns Nt page protection.
302 * @param enmProt kLdr protection.
[2860]303 */
[2861]304static ULONG kldrRdrFileGetNtAllocProt(KLDRPROT enmProt)
[2860]305{
[2861]306 switch (enmProt)
307 {
308 case KLDRPROT_NOACCESS: return PAGE_NOACCESS;
309 case KLDRPROT_READONLY: return PAGE_READONLY;
310 case KLDRPROT_WRITECOPY:
311 case KLDRPROT_READWRITE: return PAGE_READWRITE;
312 case KLDRPROT_EXECUTE: return PAGE_EXECUTE;
313 case KLDRPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
314 case KLDRPROT_EXECUTE_WRITECOPY:
315 case KLDRPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
316 default: return ~(ULONG)0;
317 }
[2860]318}
[2861]319#endif
[2860]320
321
[2861]322/** @copydoc KLDRRDR::pfnDone */
323static void kldrRdrFileDone(PKLDRRDR pRdr)
324{
325}
326
327
[2860]328/**
[2861]329 * Finds a prepared mapping region.
[2860]330 *
331 * @returns Pointer to the aPrep entry.
332 * @param pFile The instance data.
[2861]333 * @param pv The base of the region.
[2860]334 */
[2861]335static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv)
[2860]336{
337 int32_t i = pFile->cPreps;
338 while (i-- > 0)
[2861]339 if (pFile->aPreps[i].pv == pv)
340 return &pFile->aPreps[i];
[2860]341 return NULL;
342}
343
344
[2861]345/** @copydoc KLDRRDR::pfnUnmap */
346static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
[2829]347{
[2860]348 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
[2861]349 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
350 int rc;
[2860]351 if (!pPrep)
352 return KLDR_ERR_INVALID_PARAMETER;
353
[2861]354#if defined(__WIN__) || defined(__NT__)
355 if (pPrep->hSection != NULL)
356 {
357 /** @todo implement me. */
358 return -1;
359 }
360#endif
361
362 rc = kldrRdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
363
364 /* remove the mapping data on success. */
365 if (!rc)
366 {
367 pRdrFile->cPreps--;
368 if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
369 *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
370 }
371 return rc;
[2829]372}
373
374
[2861]375/** Generic implementation of kldrRdrFileUnmap. */
376static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
[2829]377{
[2861]378 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
379 return kldrHlpPageFree(pPrep->pv, pPrep->cb);
[2829]380}
381
382
383/** @copydoc KLDRRDR::pfnProtect */
[2861]384static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
[2829]385{
[2860]386 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
[2861]387 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
[2860]388 if (!pPrep)
389 return KLDR_ERR_INVALID_PARAMETER;
390
[2861]391#if defined(__WIN__) || defined(__NT__)
392 if (pPrep->hSection != NULL)
393 {
394 /** @todo implement me. */
395 return -1;
396 }
397#endif
398
399 return kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
[2829]400}
401
402
[2861]403/** Generic implementation of kldrRdrFileProtect. */
404static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
[2857]405{
[2861]406 uint32_t i;
407
408 /*
409 * Iterate the segments and apply memory protection changes.
410 */
411 for (i = 0; i < cSegments; i++)
412 {
413 int rc;
414 void *pv;
415 KLDRPROT enmProt;
416
417 if (paSegments[i].RVA == NIL_KLDRADDR)
418 continue;
419
420 /* calc new protection. */
421 enmProt = paSegments[i].enmProt;
422 if (fUnprotectOrProtect)
423 {
424 switch (enmProt)
425 {
426 case KLDRPROT_NOACCESS:
427 case KLDRPROT_READONLY:
428 case KLDRPROT_READWRITE:
429 case KLDRPROT_WRITECOPY:
430 enmProt = KLDRPROT_READWRITE;
431 break;
432 case KLDRPROT_EXECUTE:
433 case KLDRPROT_EXECUTE_READ:
434 case KLDRPROT_EXECUTE_READWRITE:
435 case KLDRPROT_EXECUTE_WRITECOPY:
436 enmProt = KLDRPROT_EXECUTE_READWRITE;
437 break;
438 default:
439 KLDRRDRFILE_ASSERT(!"bad enmProt");
440 return -1;
441 }
442 }
443 else
444 {
445 /* copy on write -> normal write. */
446 if (enmProt == KLDRPROT_EXECUTE_WRITECOPY)
447 enmProt = KLDRPROT_EXECUTE_READWRITE;
448 else if (enmProt == KLDRPROT_WRITECOPY)
449 enmProt = KLDRPROT_READWRITE;
450 }
451
452 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
453
454 rc = kldrHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
455 if (rc)
456 break;
457 }
458
459 return 0;
460}
461
462
463/** @copydoc KLDRRDR::pfnRefresh */
464static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
465{
[2860]466 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
[2861]467 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
[2860]468 if (!pPrep)
469 return KLDR_ERR_INVALID_PARAMETER;
470
[2861]471#if defined(__WIN__) || defined(__NT__)
472 if (pPrep->hSection != NULL)
473 {
474 /** @todo implement me. */
475 return -1;
476 }
477#endif
478
479 return kldrRdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
[2857]480}
481
482
[2861]483/** Generic implementation of kldrRdrFileRefresh. */
484static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
485{
486 int rc;
487 int rc2;
488 uint32_t i;
489
490 /*
491 * Make everything writable again.
492 */
493 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
494 if (rc)
495 {
496 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
497 return rc;
498 }
499
500 /*
501 * Clear everything.
502 */
503 /** @todo only zero the areas not covered by raw file bits. */
504 kLdrHlpMemSet(pPrep->pv, 0, pPrep->cb);
505
506 /*
507 * Reload all the segments.
508 * We could possibly skip some segments, but we currently have
509 * no generic way of figuring out which at the moment.
510 */
511 for (i = 0; i < cSegments; i++)
512 {
513 void *pv;
514
515 if ( paSegments[i].RVA == NIL_KLDRADDR
[2970]516 || paSegments[i].cbFile <= 0)
[2861]517 continue;
518
519 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
520 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
521 if (rc)
522 break;
523 }
524
525 /*
526 * Protect the bits again.
527 */
528 rc2 = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
529 if (rc2 && rc)
530 rc = rc2;
531
532 return rc;
533}
534
535
[2829]536/** @copydoc KLDRRDR::pfnMap */
[2861]537static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
[2829]538{
[2860]539 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
[2861]540 PKLDRRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
541 KLDRSIZE cbTotal;
542 const size_t cbPage = pRdr->pOps->pfnPageSize(pRdr);
543 int rc;
544 uint32_t i;
[2860]545
[2861]546 if (pRdrFile->cPreps >= KLDR_ELEMENTS(pRdrFile->aPreps))
547 return KLDR_ERR_TOO_MANY_MAPPINGS;
548
549 /*
550 * Calc the total mapping space needed.
551 */
552 cbTotal = 0;
553 for (i = 0; i < cSegments; i++)
554 {
555 KLDRSIZE uRVASegmentEnd;
556 if (paSegments[i].RVA == NIL_KLDRADDR)
557 continue;
558 uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
559 if (cbTotal < uRVASegmentEnd)
560 cbTotal = uRVASegmentEnd;
561 }
562 pPrep->cb = (size_t)cbTotal;
563 if (pPrep->cb != cbTotal)
564 return KLDR_ERR_ADDRESS_OVERFLOW;
565 pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
566
567#if defined(__WIN__) || defined(__NT__)
568 /*
569 * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
570 * trying to map a PE image and the kernel can parse the file for it self, the
571 * API just isn't up to scratch.
572 *
573 * Problems:
574 * 1. Reserving memory for the views is risky because you can't reserve and
575 * map into the reserved space. So, other threads might grab the memory
576 * before we get to it.
577 * 2. The page aligning of file offsets makes it impossible to map most
578 * executable images since these are commonly sector aligned.
579 * 3. When mapping a read+execute file, its not possible to create section
580 * larger than the file since the section size is bound to the data file
581 * size. This wouldn't have been such a problem if it was possible to
582 * map views beyond the section restriction, i.e. have a file size and
583 * view size.
584 * 4. Only x86 can map views at page granularity it seems, and that only
585 * using an undocument flag. The default granularity is 64KB.
586 * 5. There is more crappyness here...
587 *
588 * So, first we'll have to check if we can the file using the crappy NT APIs.
589 * Chances are we can't.
590 */
591 for (i = 0; i < cSegments; i++)
592 {
593 if (paSegments[i].RVA == NIL_KLDRADDR)
594 continue;
595
596 /* The file backing of the segments must be page aligned. */
[2970]597 if ( paSegments[i].cbFile > 0
[2861]598 && paSegments[i].offFile & (cbPage - 1))
599 break;
600
601 /* Only page alignment gaps between the file size and the mapping size. */
[2970]602 if ( paSegments[i].cbFile > 0
[2861]603 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
604 break;
605
606 /* The mapping addresses of the segments must be page aligned.
607 * Non-x86 will probably require 64KB alignment here. */
608 if (paSegments[i].RVA & (cbPage - 1))
609 break;
610
611 /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
[2970]612 if ( paSegments[i].cbFile > 0
[2861]613 && (paSegments[i].RVA & 0xffff))
614 break;
615 }
616 /** @todo if this is a PE image, we might just try a SEC_IMAGE mapping. It'll work if the host and image machines matches. */
617 if (i == cSegments)
618 {
619 /* WOW! it may work out! Incredible! */
620 SIZE_T ViewSize;
621 LARGE_INTEGER SectionOffset;
622 LARGE_INTEGER MaxiumSize;
623 NTSTATUS Status;
624 PVOID pv;
625
626 MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
627 if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
628 MaxiumSize.QuadPart = cbTotal;
629
630 Status = NtCreateSection(&pPrep->hSection,
631 SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */
632 NULL, /* object attributes */
633 &MaxiumSize,
634 PAGE_EXECUTE_WRITECOPY, /* page attributes */
635 SEC_COMMIT, /* section attributes */
636 pRdrFile->File);
637 if (!NT_SUCCESS(Status))
638 return (int)Status;
639
640 /*
641 * Determin the base address.
642 */
643 if (fFixed)
644 pPrep->pv = *ppvBase;
645 else
646 {
647 pv = NULL;
648 ViewSize = (size_t)cbTotal;
649
650 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
651 &pv,
652 0, /* ZeroBits */
653 &ViewSize,
654 MEM_RESERVE,
655 PAGE_READONLY);
656 if (NT_SUCCESS(Status))
657 {
658 pPrep->pv = *ppvBase = pv;
659 ViewSize = 0;
660 Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
661 }
662 if (!NT_SUCCESS(Status))
663 {
664 NtClose(pPrep->hSection);
665 return Status;
666 }
667 }
668
669 /*
670 * Map the segments.
671 */
672 for (i = 0; i < cSegments; i++)
673 {
674 ULONG fPageProt;
675
676 if (paSegments[i].RVA == NIL_KLDRADDR)
677 continue;
678
679 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
[2970]680 if (paSegments[i].cbFile > 0)
[2861]681 {
682 SectionOffset.QuadPart = paSegments[i].offFile;
683 ViewSize = paSegments[i].cbFile;
684 fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt);
[2883]685 /* STATUS_MAPPED_ALIGNMENT
686 STATUS_CONFLICTING_ADDRESSES
687 STATUS_INVALID_VIEW_SIZE */
[2861]688 Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
689 &pv,
690 0, /* ZeroBits */
691 0, /* CommitSize */
692 &SectionOffset, /* SectionOffset */
693 &ViewSize,
694 ViewUnmap,
695 MEM_DOS_LIM, /* AllocationType */
696 fPageProt);
697 /* do we have to zero anything? */
698 if ( NT_SUCCESS(Status)
699 && 0/*later*/)
700 {
[2883]701 /*ULONG OldPageProt = 0;
702 NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
[2861]703 }
704 }
705 else
706 {
707 ViewSize = paSegments[i].cbMapped;
708 fPageProt = kldrRdrFileGetNtAllocProt(paSegments[i].enmProt);
709 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
710 &pv,
711 0, /* ZeroBits */
712 &ViewSize,
713 MEM_COMMIT,
714 fPageProt);
715 }
716 if (!NT_SUCCESS(Status))
717 break;
718 }
719
720 /*
721 * On success, commit the mapping and return.
722 */
723 if (NT_SUCCESS(Status))
724 {
725 pRdrFile->cPreps++;
726 return 0;
727 }
728
729 /* bail out and fall back on the generic code. */
730 while (i-- > 0)
731 {
732 PVOID pv;
733
734 if (paSegments[i].RVA == NIL_KLDRADDR)
735 continue;
736
737 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
[2970]738 if (paSegments[i].cbFile > 0)
[2861]739 NtUnmapViewOfSection(NtCurrentProcess(), pv);
740 else
741 NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
742 }
743 NtClose(pPrep->hSection);
744 }
745 /* else: fall back to the generic code */
746 pPrep->hSection = NULL;
747#endif
748
749 /*
750 * Use the generic map emulation.
751 */
752 pPrep->pv = fFixed ? *ppvBase : NULL;
753 rc = kldrRdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
754 if (!rc)
755 {
756 *ppvBase = pPrep->pv;
757 pRdrFile->cPreps++;
758 }
759
760 return rc;
[2829]761}
762
763
[2861]764/** Generic implementation of kldrRdrFileMap. */
765static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
[2829]766{
[2861]767 int rc;
768 uint32_t i;
[2829]769
[2861]770 /*
771 * Generic mapping code using kldrHlpPageAlloc(), kldrHlpPageFree() and kldrHlpPageProtect().
772 */
773 rc = kldrHlpPageAlloc(&pPrep->pv, pPrep->cb, KLDRPROT_EXECUTE_READWRITE, fFixed);
774 if (rc)
775 return rc;
[2829]776
[2861]777 /*
778 * Load the data.
779 */
780 for (i = 0; i < cSegments; i++)
781 {
782 void *pv;
[2829]783
[2861]784 if ( paSegments[i].RVA == NIL_KLDRADDR
[2970]785 || paSegments[i].cbFile <= 0)
[2861]786 continue;
787
788 pv = (uint8_t *)pPrep->pv + paSegments[i].RVA;
789 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
790 if (rc)
791 break;
792 }
793
794 /*
795 * Set segment protection.
796 */
797 if (!rc)
798 {
799 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
800 if (!rc)
801 return 0;
802 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
803 }
804
805 /* bailout */
806 kldrHlpPageFree(pPrep->pv, pPrep->cb);
807 return rc;
[2829]808}
809
810
[2857]811/** @copydoc KLDRRDR::pfnPageSize */
812static size_t kldrRdrFilePageSize(PKLDRRDR pRdr)
813{
814#ifdef __OS2__
815 /* The page size on OS/2 wont change anytime soon. :-) */
816 return 0x1000;
817
818#elif defined(__WIN__)
819 SYSTEM_INFO SysInfo;
820 GetSystemInfo(&SysInfo);
821 return SysInfo.dwPageSize;
822 /*return SysInfo.dwAllocationGranularity;*/
823#else
824# error "port me"
825#endif
826}
827
828
[2825]829/** @copydoc KLDRRDR::pfnName */
830static const char *kldrRdrFileName(PKLDRRDR pRdr)
831{
832 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
833 return &pRdrFile->szFilename[0];
834}
835
836
837/** @copydoc KLDRRDR::pfnTell */
[2974]838static KLDRFOFF kldrRdrFileTell(PKLDRRDR pRdr)
[2825]839{
840 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
841
842 /*
843 * If the offset is undefined, try figure out what it is.
844 */
845 if (pRdrFile->off == -1)
846 {
847#ifdef __OS2__
848 ULONG ulNew;
849 APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
850 if (rc)
851 return -1;
852 pRdrFile->off = ulNew;
853
854#elif defined(__WIN__)
855 LONG offHigh = 0;
856 LONG offLow;
857 int rc;
858
859 SetLastError(0);
[2858]860 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
[2825]861 rc = GetLastError();
862 if (rc)
863 return -1;
[2974]864 pRdrFile->off = ((KLDRFOFF)offHigh << 32) | offLow;
[2825]865
866#else
867# error "port me."
868#endif
869 }
870 return pRdrFile->off;
871}
872
873
874/** @copydoc KLDRRDR::pfnSize */
[2974]875static KLDRFOFF kldrRdrFileSize(PKLDRRDR pRdr)
[2825]876{
877 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
878 return pRdrFile->cb;
879}
880
881
882/** @copydoc KLDRRDR::pfnAllUnmap */
883static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits)
884{
885 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
886
887 /* check for underflow */
888 if (pRdrFile->cMappings <= 0)
889#if defined(__OS2__) || defined(__WIN__)
890 return ERROR_INVALID_PARAMETER;
891#else
892# error "port me"
893#endif
894
895 /* decrement usage counter, free mapping if no longer in use. */
896 if (!--pRdrFile->cMappings)
897 {
898 kldrHlpFree(pRdrFile->pvMapping);
899 pRdrFile->pvMapping = NULL;
900 }
901
902 return 0;
903}
904
905
906/** @copydoc KLDRRDR::pfnAllMap */
907static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits)
908{
909 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
910
911 /*
912 * Do we need to map it?
913 */
914 if (!pRdrFile->pvMapping)
915 {
916 int rc;
[2974]917 KLDRFOFF cb = pRdrFile->Core.pOps->pfnSize(pRdr);
[2825]918
919 pRdrFile->pvMapping = kldrHlpAlloc(cb);
920 if (!pRdrFile->pvMapping)
921#if defined(__OS2__) || defined(__WIN__)
922 return ERROR_NOT_ENOUGH_MEMORY;
923#else
924# error "port me"
925#endif
926 rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
927 if (rc)
928 {
929 kldrHlpFree(pRdrFile->pvMapping);
930 pRdrFile->pvMapping = NULL;
931 return rc;
932 }
933 pRdrFile->cMappings = 0;
934 }
935
[2963]936 *ppvBits = pRdrFile->pvMapping;
[2825]937 pRdrFile->cMappings++;
938 return 0;
939}
940
941
942/** @copydoc KLDRRDR::pfnRead */
[2974]943static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, KLDRFOFF off)
[2825]944{
945 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
946
947 /*
948 * Do a seek if needed.
949 */
950 if (pRdrFile->off != off)
951 {
952#ifdef __OS2__
953 ULONG ulNew;
[2858]954 APIRET rc;
955
956 rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
[2825]957 if (rc)
958 {
959 pRdrFile->off = -1;
960 return rc;
961 }
962
963#elif defined(__WIN__)
[2858]964 LONG offHigh;
965 LONG offLow;
966
[2974]967 offHigh = sizeof(KLDRFOFF) == 4 ? 0 : (off >> 32);
[2858]968 offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
[2825]969 if ( offLow != (LONG)off
[2974]970 || offHigh != (LONG)(sizeof(KLDRFOFF) == 4 ? 0 : (off >> 32)))
[2825]971 {
972 int rc = GetLastError();
973 if (!rc)
974 rc = ERROR_GEN_FAILURE;
975 pRdrFile->off = -1;
976 return rc;
977 }
978
979#else
980# error "port me."
981#endif
982 }
983
984 /*
985 * Do the read.
986 */
987#ifdef __OS2__
988 {
989 ULONG cbRead = 0;
990 APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
991 if (rc)
992 {
993 pRdrFile->off = -1;
994 return rc;
995 }
996 if (cbRead != cb)
997 {
998 pRdrFile->off = -1;
999 return ERROR_GEN_FAILURE;
1000 }
1001 }
1002
1003#elif defined(__WIN__)
1004 {
1005 DWORD cbRead = 0;
1006 if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
1007 {
1008 int rc = GetLastError();
1009 if (!rc)
1010 rc = ERROR_GEN_FAILURE;
1011 pRdrFile->off = -1;
1012 return rc;
1013 }
1014 if (cbRead != cb)
1015 {
1016 pRdrFile->off = -1;
1017 return ERROR_GEN_FAILURE;
1018 }
1019 }
1020
1021#else
1022# error "port me."
1023#endif
1024
1025 pRdrFile->off = off + cb;
1026 return 0;
1027}
1028
1029
1030/** @copydoc KLDRRDR::pfnDestroy */
1031static int kldrRdrFileDestroy(PKLDRRDR pRdr)
1032{
1033 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
1034 int rc;
1035#ifdef __OS2__
1036 rc = DosClose(pRdrFile->File);
1037
1038#elif defined(__WIN__)
[2858]1039 rc = 0;
[2825]1040 if (!CloseHandle(pRdrFile->File))
1041 rc = GetLastError();
1042
1043#else
1044# error "port me"
1045#endif
1046
1047 if (pRdrFile->pvMapping)
1048 {
1049 kldrHlpFree(pRdrFile->pvMapping);
1050 pRdrFile->pvMapping = NULL;
1051 }
1052
1053 kldrHlpFree(pRdr);
1054 return rc;
1055}
1056
1057
1058/** @copydoc KLDRRDROPS::pfnCreate */
1059static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename)
1060{
1061 size_t cchFilename;
1062 PKLDRRDRFILE pRdrFile;
1063
1064 /*
1065 * Open the file and determin its size.
1066 */
1067#ifdef __OS2__
[2858]1068 ULONG ulAction = 0;
1069 FILESTATUS3 Info;
1070 APIRET rc;
1071 HFILE File = 0;
[2974]1072 KLDRFOFF cb;
[2858]1073 char szFilename[CCHMAXPATH];
[2825]1074
1075 if ((uintptr_t)pszFilename >= 0x20000000)
1076 {
[2893]1077 char *psz;
1078 cchFilename = kLdrHlpStrLen(szFilename);
1079 psz = (char *)kLdrHlpAllocA(cchFilename + 1);
[2828]1080 kLdrHlpMemCopy(psz, pszFilename, cchFilename + 1);
[2825]1081 pszFilename = psz;
1082 }
1083 rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
1084 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
1085 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
1086 NULL);
1087 if (rc)
1088 return rc;
1089
[2883]1090 rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
[2858]1091 if (rc)
1092 {
1093 DosClose(File);
1094 return rc;
1095 }
1096
[2825]1097 rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
1098 if (rc)
1099 {
1100 DosClose(File);
1101 return rc;
1102 }
1103 cb = Info.cbFile;
1104
1105#elif defined(__WIN__)
1106 SECURITY_ATTRIBUTES SecAttr;
1107 DWORD High;
1108 DWORD Low;
1109 int rc;
1110 HANDLE File;
[2974]1111 KLDRFOFF cb;
[2858]1112 char szFilename[MAX_PATH];
[2825]1113
1114 SecAttr.bInheritHandle = FALSE;
1115 SecAttr.lpSecurityDescriptor = NULL;
1116 SecAttr.nLength = 0;
[2869]1117 File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
[2825]1118 if (File == INVALID_HANDLE_VALUE)
1119 return GetLastError();
1120
[2858]1121 if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
1122 {
1123 rc = GetLastError();
1124 CloseHandle(File);
1125 return rc;
1126 }
1127
[2825]1128 SetLastError(0);
1129 Low = GetFileSize(File, &High);
1130 rc = GetLastError();
1131 if (rc)
1132 {
1133 CloseHandle(File);
1134 return rc;
1135 }
[2974]1136 if (sizeof(KLDRFOFF) == 4)
[2858]1137 cb = High ? 0x7fffffff : Low;
1138 else
[2974]1139 cb = ((KLDRFOFF)High << 32) | Low;
[2825]1140
1141#else
1142# error "port me"
1143#endif
1144
1145
1146 /*
1147 * Allocate the reader instance.
1148 */
[2858]1149 cchFilename = kLdrHlpStrLen(szFilename);
[2825]1150 pRdrFile = (PKLDRRDRFILE)kldrHlpAlloc(sizeof(*pRdrFile) + cchFilename);
1151 if (!pRdrFile)
1152#if defined(__OS2__)
1153 {
1154 DosClose(File);
1155 return ERROR_NOT_ENOUGH_MEMORY;
1156 }
1157#elif defined(__WIN__)
1158 {
1159 CloseHandle(File);
1160 return ERROR_NOT_ENOUGH_MEMORY;
1161 }
1162#else
1163# error "port me"
1164#endif
1165
1166 /*
1167 * Initialize it and return successfully.
1168 */
[2858]1169 pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
[2825]1170 pRdrFile->Core.pOps = &g_kLdrRdrFileOps;
1171 pRdrFile->File = File;
[2858]1172 pRdrFile->cb = cb;
[2825]1173 pRdrFile->off = 0;
[2860]1174 pRdrFile->cMappings = 0;
1175 pRdrFile->cPreps = 0;
[2858]1176 kLdrHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
[2825]1177
1178 *ppRdr = &pRdrFile->Core;
1179 return 0;
1180}
1181
Note: See TracBrowser for help on using the repository browser.