source: trunk/kLdr/kLdrRdrFile.c@ 2893

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

made it compile again.

  • Property svn:keywords set to Id
File size: 34.5 KB
Line 
1/* $Id: kLdrRdrFile.c 2893 2006-12-22 18:01:38Z bird $ */
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__)
37# define WIN32_NO_STATUS
38# include <Windows.h>
39# ifndef __WIN__
40# define __WIN__
41# endif
42# include <ntsecapi.h>
43# include <ntstatus.h>
44
45 /** @todo find a non-conflicting header with NTSTATUS, NTAPI, ++ */
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
150#else
151# error "port me"
152#endif
153
154#include <kLdr.h>
155#include "kLdrHlp.h"
156
157
158/*******************************************************************************
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/*******************************************************************************
176* Structures and Typedefs *
177*******************************************************************************/
178/**
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/**
194 * The file provier instance for native files.
195 */
196typedef struct KLDRRDRFILE
197{
198 /** The file reader vtable. */
199 KLDRRDR Core;
200 /** The file handle. */
201#ifdef __OS2__
202 HFILE File;
203#elif defined(__WIN__) || defined(__NT__)
204 HANDLE File;
205#else
206# error "Port me!"
207#endif
208 /** The current file offset. */
209 off_t off;
210 /** The file size. */
211 off_t cb;
212 /** Array where we stuff the mapping area data. */
213 KLDRRDRFILEPREP aPreps[4];
214 /** The number of current preps. */
215 uint32_t cPreps;
216 /** Number of mapping references. */
217 int32_t cMappings;
218 /** The memory mapping. */
219 void *pvMapping;
220 /** The filename. */
221 char szFilename[1];
222} KLDRRDRFILE, *PKLDRRDRFILE;
223
224
225/*******************************************************************************
226* Internal Functions *
227*******************************************************************************/
228static void kldrRdrFileDone(PKLDRRDR pRdr);
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);
235static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
236static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed);
237static size_t kldrRdrFilePageSize(PKLDRRDR pRdr);
238static const char *kldrRdrFileName(PKLDRRDR pRdr);
239static off_t kldrRdrFileTell(PKLDRRDR pRdr);
240static off_t kldrRdrFileSize(PKLDRRDR pRdr);
241static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits);
242static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits);
243static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off);
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,
263 kldrRdrFileName,
264 kldrRdrFilePageSize,
265 kldrRdrFileMap,
266 kldrRdrFileRefresh,
267 kldrRdrFileProtect,
268 kldrRdrFileUnmap,
269 kldrRdrFileDone,
270 42
271};
272
273
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)
282{
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 }
295}
296
297
298/**
299 * Converts a kLdr segment protection to NT protection for a allocation.
300 *
301 * @returns Nt page protection.
302 * @param enmProt kLdr protection.
303 */
304static ULONG kldrRdrFileGetNtAllocProt(KLDRPROT enmProt)
305{
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 }
318}
319#endif
320
321
322/** @copydoc KLDRRDR::pfnDone */
323static void kldrRdrFileDone(PKLDRRDR pRdr)
324{
325}
326
327
328/**
329 * Finds a prepared mapping region.
330 *
331 * @returns Pointer to the aPrep entry.
332 * @param pFile The instance data.
333 * @param pv The base of the region.
334 */
335static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv)
336{
337 int32_t i = pFile->cPreps;
338 while (i-- > 0)
339 if (pFile->aPreps[i].pv == pv)
340 return &pFile->aPreps[i];
341 return NULL;
342}
343
344
345/** @copydoc KLDRRDR::pfnUnmap */
346static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments)
347{
348 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
349 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
350 int rc;
351 if (!pPrep)
352 return KLDR_ERR_INVALID_PARAMETER;
353
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;
372}
373
374
375/** Generic implementation of kldrRdrFileUnmap. */
376static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments)
377{
378 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
379 return kldrHlpPageFree(pPrep->pv, pPrep->cb);
380}
381
382
383/** @copydoc KLDRRDR::pfnProtect */
384static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
385{
386 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
387 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
388 if (!pPrep)
389 return KLDR_ERR_INVALID_PARAMETER;
390
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);
400}
401
402
403/** Generic implementation of kldrRdrFileProtect. */
404static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
405{
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{
466 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
467 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
468 if (!pPrep)
469 return KLDR_ERR_INVALID_PARAMETER;
470
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);
480}
481
482
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
516 || !paSegments[i].cbFile)
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
536/** @copydoc KLDRRDR::pfnMap */
537static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
538{
539 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
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;
545
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. */
597 if ( paSegments[i].cbFile
598 && paSegments[i].offFile & (cbPage - 1))
599 break;
600
601 /* Only page alignment gaps between the file size and the mapping size. */
602 if ( paSegments[i].cbFile
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. */
612 if ( !paSegments[i].cbFile
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;
680 if (paSegments[i].cbFile)
681 {
682 SectionOffset.QuadPart = paSegments[i].offFile;
683 ViewSize = paSegments[i].cbFile;
684 fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt);
685 /* STATUS_MAPPED_ALIGNMENT
686 STATUS_CONFLICTING_ADDRESSES
687 STATUS_INVALID_VIEW_SIZE */
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 {
701 /*ULONG OldPageProt = 0;
702 NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
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;
738 if (paSegments[i].cbFile)
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;
761}
762
763
764/** Generic implementation of kldrRdrFileMap. */
765static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, uint32_t cSegments, PCKLDRSEG paSegments, unsigned fFixed)
766{
767 int rc;
768 uint32_t i;
769
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;
776
777 /*
778 * Load the data.
779 */
780 for (i = 0; i < cSegments; i++)
781 {
782 void *pv;
783
784 if ( paSegments[i].RVA == NIL_KLDRADDR
785 || !paSegments[i].cbFile)
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;
808}
809
810
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
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 */
838static off_t kldrRdrFileTell(PKLDRRDR pRdr)
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);
860 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
861 rc = GetLastError();
862 if (rc)
863 return -1;
864 pRdrFile->off = ((off_t)offHigh << 32) | offLow;
865
866#else
867# error "port me."
868#endif
869 }
870 return pRdrFile->off;
871}
872
873
874/** @copydoc KLDRRDR::pfnSize */
875static off_t kldrRdrFileSize(PKLDRRDR pRdr)
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;
917 off_t cb = pRdrFile->Core.pOps->pfnSize(pRdr);
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
936 pRdrFile->cMappings++;
937 return 0;
938}
939
940
941/** @copydoc KLDRRDR::pfnRead */
942static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, size_t cb, off_t off)
943{
944 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
945
946 /*
947 * Do a seek if needed.
948 */
949 if (pRdrFile->off != off)
950 {
951#ifdef __OS2__
952 ULONG ulNew;
953 APIRET rc;
954
955 rc = DosSetFilePtr(pRdrFile->File, off, FILE_BEGIN, &ulNew);
956 if (rc)
957 {
958 pRdrFile->off = -1;
959 return rc;
960 }
961
962#elif defined(__WIN__)
963 LONG offHigh;
964 LONG offLow;
965
966 offHigh = sizeof(off_t) == 4 ? 0 : (off >> 32);
967 offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
968 if ( offLow != (LONG)off
969 || offHigh != (LONG)(sizeof(off_t) == 4 ? 0 : (off >> 32)))
970 {
971 int rc = GetLastError();
972 if (!rc)
973 rc = ERROR_GEN_FAILURE;
974 pRdrFile->off = -1;
975 return rc;
976 }
977
978#else
979# error "port me."
980#endif
981 }
982
983 /*
984 * Do the read.
985 */
986#ifdef __OS2__
987 {
988 ULONG cbRead = 0;
989 APIRET rc = DosRead(pRdrFile->File, pvBuf, cb, &cbRead);
990 if (rc)
991 {
992 pRdrFile->off = -1;
993 return rc;
994 }
995 if (cbRead != cb)
996 {
997 pRdrFile->off = -1;
998 return ERROR_GEN_FAILURE;
999 }
1000 }
1001
1002#elif defined(__WIN__)
1003 {
1004 DWORD cbRead = 0;
1005 if (!ReadFile(pRdrFile->File, pvBuf, cb, &cbRead, NULL))
1006 {
1007 int rc = GetLastError();
1008 if (!rc)
1009 rc = ERROR_GEN_FAILURE;
1010 pRdrFile->off = -1;
1011 return rc;
1012 }
1013 if (cbRead != cb)
1014 {
1015 pRdrFile->off = -1;
1016 return ERROR_GEN_FAILURE;
1017 }
1018 }
1019
1020#else
1021# error "port me."
1022#endif
1023
1024 pRdrFile->off = off + cb;
1025 return 0;
1026}
1027
1028
1029/** @copydoc KLDRRDR::pfnDestroy */
1030static int kldrRdrFileDestroy(PKLDRRDR pRdr)
1031{
1032 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
1033 int rc;
1034#ifdef __OS2__
1035 rc = DosClose(pRdrFile->File);
1036
1037#elif defined(__WIN__)
1038 rc = 0;
1039 if (!CloseHandle(pRdrFile->File))
1040 rc = GetLastError();
1041
1042#else
1043# error "port me"
1044#endif
1045
1046 if (pRdrFile->pvMapping)
1047 {
1048 kldrHlpFree(pRdrFile->pvMapping);
1049 pRdrFile->pvMapping = NULL;
1050 }
1051
1052 kldrHlpFree(pRdr);
1053 return rc;
1054}
1055
1056
1057/** @copydoc KLDRRDROPS::pfnCreate */
1058static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename)
1059{
1060 size_t cchFilename;
1061 PKLDRRDRFILE pRdrFile;
1062
1063 /*
1064 * Open the file and determin its size.
1065 */
1066#ifdef __OS2__
1067 ULONG ulAction = 0;
1068 FILESTATUS3 Info;
1069 APIRET rc;
1070 HFILE File = 0;
1071 off_t cb;
1072 char szFilename[CCHMAXPATH];
1073
1074 if ((uintptr_t)pszFilename >= 0x20000000)
1075 {
1076 char *psz;
1077 cchFilename = kLdrHlpStrLen(szFilename);
1078 psz = (char *)kLdrHlpAllocA(cchFilename + 1);
1079 kLdrHlpMemCopy(psz, pszFilename, cchFilename + 1);
1080 pszFilename = psz;
1081 }
1082 rc = DosOpen((PCSZ)pszFilename, &File, &ulAction, 0, FILE_NORMAL,
1083 OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
1084 OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY | OPEN_FLAGS_RANDOMSEQUENTIAL,
1085 NULL);
1086 if (rc)
1087 return rc;
1088
1089 rc = DosQueryPathInfo((PCSZ)pszFilename, FIL_QUERYFULLNAME, szFilename, sizeof(szFilename));
1090 if (rc)
1091 {
1092 DosClose(File);
1093 return rc;
1094 }
1095
1096 rc = DosQueryFileInfo(File, FIL_STANDARD, &Info, sizeof(Info));
1097 if (rc)
1098 {
1099 DosClose(File);
1100 return rc;
1101 }
1102 cb = Info.cbFile;
1103
1104#elif defined(__WIN__)
1105 SECURITY_ATTRIBUTES SecAttr;
1106 DWORD High;
1107 DWORD Low;
1108 int rc;
1109 HANDLE File;
1110 off_t cb;
1111 char szFilename[MAX_PATH];
1112
1113 SecAttr.bInheritHandle = FALSE;
1114 SecAttr.lpSecurityDescriptor = NULL;
1115 SecAttr.nLength = 0;
1116 File = CreateFile(pszFilename, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, &SecAttr, OPEN_EXISTING, 0, NULL);
1117 if (File == INVALID_HANDLE_VALUE)
1118 return GetLastError();
1119
1120 if (!GetFullPathName(pszFilename, sizeof(szFilename), szFilename, NULL))
1121 {
1122 rc = GetLastError();
1123 CloseHandle(File);
1124 return rc;
1125 }
1126
1127 SetLastError(0);
1128 Low = GetFileSize(File, &High);
1129 rc = GetLastError();
1130 if (rc)
1131 {
1132 CloseHandle(File);
1133 return rc;
1134 }
1135 if (sizeof(off_t) == 4)
1136 cb = High ? 0x7fffffff : Low;
1137 else
1138 cb = ((off_t)High << 32) | Low;
1139
1140#else
1141# error "port me"
1142#endif
1143
1144
1145 /*
1146 * Allocate the reader instance.
1147 */
1148 cchFilename = kLdrHlpStrLen(szFilename);
1149 pRdrFile = (PKLDRRDRFILE)kldrHlpAlloc(sizeof(*pRdrFile) + cchFilename);
1150 if (!pRdrFile)
1151#if defined(__OS2__)
1152 {
1153 DosClose(File);
1154 return ERROR_NOT_ENOUGH_MEMORY;
1155 }
1156#elif defined(__WIN__)
1157 {
1158 CloseHandle(File);
1159 return ERROR_NOT_ENOUGH_MEMORY;
1160 }
1161#else
1162# error "port me"
1163#endif
1164
1165 /*
1166 * Initialize it and return successfully.
1167 */
1168 pRdrFile->Core.u32Magic = KLDRRDR_MAGIC;
1169 pRdrFile->Core.pOps = &g_kLdrRdrFileOps;
1170 pRdrFile->File = File;
1171 pRdrFile->cb = cb;
1172 pRdrFile->off = 0;
1173 pRdrFile->cMappings = 0;
1174 pRdrFile->cPreps = 0;
1175 kLdrHlpMemCopy(&pRdrFile->szFilename[0], szFilename, cchFilename + 1);
1176
1177 *ppRdr = &pRdrFile->Core;
1178 return 0;
1179}
1180
Note: See TracBrowser for help on using the repository browser.