source: trunk/kStuff/kLdr/kLdrRdrFile.c@ 3573

Last change on this file since 3573 was 3573, checked in by bird, 18 years ago

kHlp work...

  • Property svn:keywords set to Id
File size: 34.3 KB
Line 
1/* $Id: kLdrRdrFile.c 3573 2007-08-31 04:09:23Z 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 <k/kLdr.h>
155
156
157/*******************************************************************************
158* Defined Constants And Macros *
159*******************************************************************************/
160/** @def KLDRRDRFILE_STRICT
161 * Define KLDRRDRFILE_STRICT to enabled strict checks in KLDRRDRFILE. */
162#define KLDRRDRFILE_STRICT 1
163
164/** @def KLDRRDRFILE_ASSERT
165 * Assert that an expression is true when KLDRRDRFILE_STRICT is defined.
166 */
167#ifdef KLDRRDRFILE_STRICT
168# define KLDRRDRFILE_ASSERT(expr) kHlpAssert(expr)
169#else
170# define KLDRRDRFILE_ASSERT(expr) do {} while (0)
171#endif
172
173
174/*******************************************************************************
175* Structures and Typedefs *
176*******************************************************************************/
177/**
178 * Prepared stuff.
179 */
180typedef struct KLDRRDRFILEPREP
181{
182 /** The address of the prepared region. */
183 void *pv;
184 /** The size of the prepared region. */
185 KSIZE cb;
186#if defined(__WIN__) || defined(__NT__)
187 /** Handle to the section created to map the file. */
188 HANDLE hSection;
189#endif
190} KLDRRDRFILEPREP, *PKLDRRDRFILEPREP;
191
192/**
193 * The file provier instance for native files.
194 */
195typedef struct KLDRRDRFILE
196{
197 /** The file reader vtable. */
198 KLDRRDR Core;
199 /** The file handle. */
200#ifdef __OS2__
201 HFILE File;
202#elif defined(__WIN__) || defined(__NT__)
203 HANDLE File;
204#else
205# error "Port me!"
206#endif
207 /** The current file offset. */
208 KLDRFOFF off;
209 /** The file size. */
210 KLDRFOFF cb;
211 /** Array where we stuff the mapping area data. */
212 KLDRRDRFILEPREP aPreps[4];
213 /** The number of current preps. */
214 KU32 cPreps;
215 /** Number of mapping references. */
216 KI32 cMappings;
217 /** The memory mapping. */
218 void *pvMapping;
219 /** The filename. */
220 char szFilename[1];
221} KLDRRDRFILE, *PKLDRRDRFILE;
222
223
224/*******************************************************************************
225* Internal Functions *
226*******************************************************************************/
227static void kldrRdrFileDone(PKLDRRDR pRdr);
228static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
229static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
230static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
231static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect);
232static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments);
233static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments);
234static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
235static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed);
236static KSIZE kldrRdrFilePageSize(PKLDRRDR pRdr);
237static const char *kldrRdrFileName(PKLDRRDR pRdr);
238static KLDRFOFF kldrRdrFileTell(PKLDRRDR pRdr);
239static KLDRFOFF kldrRdrFileSize(PKLDRRDR pRdr);
240static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits);
241static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits);
242static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, KSIZE cb, KLDRFOFF off);
243static int kldrRdrFileDestroy(PKLDRRDR pRdr);
244static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename);
245
246
247/*******************************************************************************
248* Global Variables *
249*******************************************************************************/
250/** Native file provider operations. */
251const KLDRRDROPS g_kLdrRdrFileOps =
252{
253 "native file",
254 NULL,
255 kldrRdrFileCreate,
256 kldrRdrFileDestroy,
257 kldrRdrFileRead,
258 kldrRdrFileAllMap,
259 kldrRdrFileAllUnmap,
260 kldrRdrFileSize,
261 kldrRdrFileTell,
262 kldrRdrFileName,
263 kldrRdrFilePageSize,
264 kldrRdrFileMap,
265 kldrRdrFileRefresh,
266 kldrRdrFileProtect,
267 kldrRdrFileUnmap,
268 kldrRdrFileDone,
269 42
270};
271
272
273#if defined(__WIN__) || defined(__NT__)
274/**
275 * Converts a kLdr segment protection to NT protection for a mapping.
276 *
277 * @returns Nt page protection.
278 * @param enmProt kLdr protection.
279 */
280static ULONG kldrRdrFileGetNtMapProt(KPROT enmProt)
281{
282 switch (enmProt)
283 {
284 case KPROT_NOACCESS: return PAGE_NOACCESS;
285 case KPROT_READONLY: return PAGE_READONLY;
286 case KPROT_READWRITE: return PAGE_READWRITE;
287 case KPROT_WRITECOPY: return PAGE_WRITECOPY;
288 case KPROT_EXECUTE: return PAGE_EXECUTE;
289 case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
290 case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
291 case KPROT_EXECUTE_WRITECOPY: return PAGE_EXECUTE_WRITECOPY;
292 default: return ~(ULONG)0;
293 }
294}
295
296
297/**
298 * Converts a kLdr segment protection to NT protection for a allocation.
299 *
300 * @returns Nt page protection.
301 * @param enmProt kLdr protection.
302 */
303static ULONG kldrRdrFileGetNtAllocProt(KPROT enmProt)
304{
305 switch (enmProt)
306 {
307 case KPROT_NOACCESS: return PAGE_NOACCESS;
308 case KPROT_READONLY: return PAGE_READONLY;
309 case KPROT_WRITECOPY:
310 case KPROT_READWRITE: return PAGE_READWRITE;
311 case KPROT_EXECUTE: return PAGE_EXECUTE;
312 case KPROT_EXECUTE_READ: return PAGE_EXECUTE_READ;
313 case KPROT_EXECUTE_WRITECOPY:
314 case KPROT_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
315 default: return ~(ULONG)0;
316 }
317}
318#endif
319
320
321/** @copydoc KLDRRDR::pfnDone */
322static void kldrRdrFileDone(PKLDRRDR pRdr)
323{
324}
325
326
327/**
328 * Finds a prepared mapping region.
329 *
330 * @returns Pointer to the aPrep entry.
331 * @param pFile The instance data.
332 * @param pv The base of the region.
333 */
334static PKLDRRDRFILEPREP kldrRdrFileFindPrepExact(PKLDRRDRFILE pFile, void *pv)
335{
336 KI32 i = pFile->cPreps;
337 while (i-- > 0)
338 if (pFile->aPreps[i].pv == pv)
339 return &pFile->aPreps[i];
340 return NULL;
341}
342
343
344/** @copydoc KLDRRDR::pfnUnmap */
345static int kldrRdrFileUnmap(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
346{
347 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
348 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
349 int rc;
350 if (!pPrep)
351 return KLDR_ERR_INVALID_PARAMETER;
352
353#if defined(__WIN__) || defined(__NT__)
354 if (pPrep->hSection != NULL)
355 {
356 /** @todo implement me. */
357 return -1;
358 }
359#endif
360
361 rc = kldrRdrFileGenericUnmap(pRdr, pPrep, cSegments, paSegments);
362
363 /* remove the mapping data on success. */
364 if (!rc)
365 {
366 pRdrFile->cPreps--;
367 if (pPrep != &pRdrFile->aPreps[pRdrFile->cPreps])
368 *pPrep = pRdrFile->aPreps[pRdrFile->cPreps];
369 }
370 return rc;
371}
372
373
374/** Generic implementation of kldrRdrFileUnmap. */
375static int kldrRdrFileGenericUnmap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
376{
377 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
378 return kHlpPageFree(pPrep->pv, pPrep->cb);
379}
380
381
382/** @copydoc KLDRRDR::pfnProtect */
383static int kldrRdrFileProtect(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
384{
385 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
386 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
387 if (!pPrep)
388 return KLDR_ERR_INVALID_PARAMETER;
389
390#if defined(__WIN__) || defined(__NT__)
391 if (pPrep->hSection != NULL)
392 {
393 /** @todo implement me. */
394 return -1;
395 }
396#endif
397
398 return kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, fUnprotectOrProtect);
399}
400
401
402/** Generic implementation of kldrRdrFileProtect. */
403static int kldrRdrFileGenericProtect(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fUnprotectOrProtect)
404{
405 KU32 i;
406
407 /*
408 * Iterate the segments and apply memory protection changes.
409 */
410 for (i = 0; i < cSegments; i++)
411 {
412 int rc;
413 void *pv;
414 KPROT enmProt;
415
416 if (paSegments[i].RVA == NIL_KLDRADDR)
417 continue;
418
419 /* calc new protection. */
420 enmProt = paSegments[i].enmProt;
421 if (fUnprotectOrProtect)
422 {
423 switch (enmProt)
424 {
425 case KPROT_NOACCESS:
426 case KPROT_READONLY:
427 case KPROT_READWRITE:
428 case KPROT_WRITECOPY:
429 enmProt = KPROT_READWRITE;
430 break;
431 case KPROT_EXECUTE:
432 case KPROT_EXECUTE_READ:
433 case KPROT_EXECUTE_READWRITE:
434 case KPROT_EXECUTE_WRITECOPY:
435 enmProt = KPROT_EXECUTE_READWRITE;
436 break;
437 default:
438 KLDRRDRFILE_ASSERT(!"bad enmProt");
439 return -1;
440 }
441 }
442 else
443 {
444 /* copy on write -> normal write. */
445 if (enmProt == KPROT_EXECUTE_WRITECOPY)
446 enmProt = KPROT_EXECUTE_READWRITE;
447 else if (enmProt == KPROT_WRITECOPY)
448 enmProt = KPROT_READWRITE;
449 }
450
451 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
452
453 rc = kHlpPageProtect(pv, paSegments[i].cbMapped, enmProt);
454 if (rc)
455 break;
456 }
457
458 return 0;
459}
460
461
462/** @copydoc KLDRRDR::pfnRefresh */
463static int kldrRdrFileRefresh(PKLDRRDR pRdr, void *pvBase, KU32 cSegments, PCKLDRSEG paSegments)
464{
465 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
466 PKLDRRDRFILEPREP pPrep = kldrRdrFileFindPrepExact(pRdrFile, pvBase);
467 if (!pPrep)
468 return KLDR_ERR_INVALID_PARAMETER;
469
470#if defined(__WIN__) || defined(__NT__)
471 if (pPrep->hSection != NULL)
472 {
473 /** @todo implement me. */
474 return -1;
475 }
476#endif
477
478 return kldrRdrFileGenericRefresh(pRdr, pPrep, cSegments, paSegments);
479}
480
481
482/** Generic implementation of kldrRdrFileRefresh. */
483static int kldrRdrFileGenericRefresh(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments)
484{
485 int rc;
486 int rc2;
487 KU32 i;
488
489 /*
490 * Make everything writable again.
491 */
492 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
493 if (rc)
494 {
495 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
496 return rc;
497 }
498
499 /*
500 * Clear everything.
501 */
502 /** @todo only zero the areas not covered by raw file bits. */
503 kHlpMemSet(pPrep->pv, 0, pPrep->cb);
504
505 /*
506 * Reload all the segments.
507 * We could possibly skip some segments, but we currently have
508 * no generic way of figuring out which at the moment.
509 */
510 for (i = 0; i < cSegments; i++)
511 {
512 void *pv;
513
514 if ( paSegments[i].RVA == NIL_KLDRADDR
515 || paSegments[i].cbFile <= 0)
516 continue;
517
518 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
519 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
520 if (rc)
521 break;
522 }
523
524 /*
525 * Protect the bits again.
526 */
527 rc2 = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
528 if (rc2 && rc)
529 rc = rc2;
530
531 return rc;
532}
533
534
535/** @copydoc KLDRRDR::pfnMap */
536static int kldrRdrFileMap(PKLDRRDR pRdr, void **ppvBase, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
537{
538 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
539 PKLDRRDRFILEPREP pPrep = &pRdrFile->aPreps[pRdrFile->cPreps];
540 KLDRSIZE cbTotal;
541 const KSIZE cbPage = pRdr->pOps->pfnPageSize(pRdr);
542 int rc;
543 KU32 i;
544
545 if (pRdrFile->cPreps >= K_ELEMENTS(pRdrFile->aPreps))
546 return KLDR_ERR_TOO_MANY_MAPPINGS;
547
548 /*
549 * Calc the total mapping space needed.
550 */
551 cbTotal = 0;
552 for (i = 0; i < cSegments; i++)
553 {
554 KLDRSIZE uRVASegmentEnd;
555 if (paSegments[i].RVA == NIL_KLDRADDR)
556 continue;
557 uRVASegmentEnd = paSegments[i].RVA + paSegments[i].cbMapped;
558 if (cbTotal < uRVASegmentEnd)
559 cbTotal = uRVASegmentEnd;
560 }
561 pPrep->cb = (KSIZE)cbTotal;
562 if (pPrep->cb != cbTotal)
563 return KLDR_ERR_ADDRESS_OVERFLOW;
564 pPrep->cb = (pPrep->cb + (cbPage - 1)) & ~(cbPage- 1);
565
566#if defined(__WIN__) || defined(__NT__)
567 /*
568 * The NT memory mapped file API sucks in a lot of ways. Unless you're actually
569 * trying to map a PE image and the kernel can parse the file for it self, the
570 * API just isn't up to scratch.
571 *
572 * Problems:
573 * 1. Reserving memory for the views is risky because you can't reserve and
574 * map into the reserved space. So, other threads might grab the memory
575 * before we get to it.
576 * 2. The page aligning of file offsets makes it impossible to map most
577 * executable images since these are commonly sector aligned.
578 * 3. When mapping a read+execute file, its not possible to create section
579 * larger than the file since the section size is bound to the data file
580 * size. This wouldn't have been such a problem if it was possible to
581 * map views beyond the section restriction, i.e. have a file size and
582 * view size.
583 * 4. Only x86 can map views at page granularity it seems, and that only
584 * using an undocument flag. The default granularity is 64KB.
585 * 5. There is more crappyness here...
586 *
587 * So, first we'll have to check if we can the file using the crappy NT APIs.
588 * Chances are we can't.
589 */
590 for (i = 0; i < cSegments; i++)
591 {
592 if (paSegments[i].RVA == NIL_KLDRADDR)
593 continue;
594
595 /* The file backing of the segments must be page aligned. */
596 if ( paSegments[i].cbFile > 0
597 && paSegments[i].offFile & (cbPage - 1))
598 break;
599
600 /* Only page alignment gaps between the file size and the mapping size. */
601 if ( paSegments[i].cbFile > 0
602 && (paSegments[i].cbFile & ~(cbPage - 1)) != (paSegments[i].cbMapped & ~(cbPage - 1)) )
603 break;
604
605 /* The mapping addresses of the segments must be page aligned.
606 * Non-x86 will probably require 64KB alignment here. */
607 if (paSegments[i].RVA & (cbPage - 1))
608 break;
609
610 /* If we do have to allocate the segment it's RVA must be 64KB aligned. */
611 if ( paSegments[i].cbFile > 0
612 && (paSegments[i].RVA & 0xffff))
613 break;
614 }
615 /** @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. */
616 if (i == cSegments)
617 {
618 /* WOW! it may work out! Incredible! */
619 SIZE_T ViewSize;
620 LARGE_INTEGER SectionOffset;
621 LARGE_INTEGER MaxiumSize;
622 NTSTATUS Status;
623 PVOID pv;
624
625 MaxiumSize.QuadPart = pRdr->pOps->pfnSize(pRdr);
626 if (MaxiumSize.QuadPart > (LONGLONG)cbTotal)
627 MaxiumSize.QuadPart = cbTotal;
628
629 Status = NtCreateSection(&pPrep->hSection,
630 SECTION_MAP_EXECUTE | SECTION_MAP_READ, /* desired access */
631 NULL, /* object attributes */
632 &MaxiumSize,
633 PAGE_EXECUTE_WRITECOPY, /* page attributes */
634 SEC_COMMIT, /* section attributes */
635 pRdrFile->File);
636 if (!NT_SUCCESS(Status))
637 return (int)Status;
638
639 /*
640 * Determin the base address.
641 */
642 if (fFixed)
643 pPrep->pv = *ppvBase;
644 else
645 {
646 pv = NULL;
647 ViewSize = (KSIZE)cbTotal;
648
649 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
650 &pv,
651 0, /* ZeroBits */
652 &ViewSize,
653 MEM_RESERVE,
654 PAGE_READONLY);
655 if (NT_SUCCESS(Status))
656 {
657 pPrep->pv = *ppvBase = pv;
658 ViewSize = 0;
659 Status = NtFreeVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, MEM_RELEASE);
660 }
661 if (!NT_SUCCESS(Status))
662 {
663 NtClose(pPrep->hSection);
664 return Status;
665 }
666 }
667
668 /*
669 * Map the segments.
670 */
671 for (i = 0; i < cSegments; i++)
672 {
673 ULONG fPageProt;
674
675 if (paSegments[i].RVA == NIL_KLDRADDR)
676 continue;
677
678 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
679 if (paSegments[i].cbFile > 0)
680 {
681 SectionOffset.QuadPart = paSegments[i].offFile;
682 ViewSize = paSegments[i].cbFile;
683 fPageProt = kldrRdrFileGetNtMapProt(paSegments[i].enmProt);
684 /* STATUS_MAPPED_ALIGNMENT
685 STATUS_CONFLICTING_ADDRESSES
686 STATUS_INVALID_VIEW_SIZE */
687 Status = NtMapViewOfSection(pPrep->hSection, NtCurrentProcess(),
688 &pv,
689 0, /* ZeroBits */
690 0, /* CommitSize */
691 &SectionOffset, /* SectionOffset */
692 &ViewSize,
693 ViewUnmap,
694 MEM_DOS_LIM, /* AllocationType */
695 fPageProt);
696 /* do we have to zero anything? */
697 if ( NT_SUCCESS(Status)
698 && 0/*later*/)
699 {
700 /*ULONG OldPageProt = 0;
701 NtProtectVirtualMemory(NtCurrentProcess(), &pv, &ViewSize, , */
702 }
703 }
704 else
705 {
706 ViewSize = paSegments[i].cbMapped;
707 fPageProt = kldrRdrFileGetNtAllocProt(paSegments[i].enmProt);
708 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
709 &pv,
710 0, /* ZeroBits */
711 &ViewSize,
712 MEM_COMMIT,
713 fPageProt);
714 }
715 if (!NT_SUCCESS(Status))
716 break;
717 }
718
719 /*
720 * On success, commit the mapping and return.
721 */
722 if (NT_SUCCESS(Status))
723 {
724 pRdrFile->cPreps++;
725 return 0;
726 }
727
728 /* bail out and fall back on the generic code. */
729 while (i-- > 0)
730 {
731 PVOID pv;
732
733 if (paSegments[i].RVA == NIL_KLDRADDR)
734 continue;
735
736 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
737 if (paSegments[i].cbFile > 0)
738 NtUnmapViewOfSection(NtCurrentProcess(), pv);
739 else
740 NtFreeVirtualMemory(NtCurrentProcess(), &pv, NULL, MEM_RELEASE);
741 }
742 NtClose(pPrep->hSection);
743 }
744 /* else: fall back to the generic code */
745 pPrep->hSection = NULL;
746#endif
747
748 /*
749 * Use the generic map emulation.
750 */
751 pPrep->pv = fFixed ? *ppvBase : NULL;
752 rc = kldrRdrFileGenericMap(pRdr, pPrep, cSegments, paSegments, fFixed);
753 if (!rc)
754 {
755 *ppvBase = pPrep->pv;
756 pRdrFile->cPreps++;
757 }
758
759 return rc;
760}
761
762
763/** Generic implementation of kldrRdrFileMap. */
764static int kldrRdrFileGenericMap(PKLDRRDR pRdr, PKLDRRDRFILEPREP pPrep, KU32 cSegments, PCKLDRSEG paSegments, unsigned fFixed)
765{
766 int rc;
767 KU32 i;
768
769 /*
770 * Generic mapping code using kHlpPageAlloc(), kHlpPageFree() and kHlpPageProtect().
771 */
772 rc = kHlpPageAlloc(&pPrep->pv, pPrep->cb, KPROT_EXECUTE_READWRITE, fFixed);
773 if (rc)
774 return rc;
775
776 /*
777 * Load the data.
778 */
779 for (i = 0; i < cSegments; i++)
780 {
781 void *pv;
782
783 if ( paSegments[i].RVA == NIL_KLDRADDR
784 || paSegments[i].cbFile <= 0)
785 continue;
786
787 pv = (KU8 *)pPrep->pv + paSegments[i].RVA;
788 rc = pRdr->pOps->pfnRead(pRdr, pv, paSegments[i].cbFile, paSegments[i].offFile);
789 if (rc)
790 break;
791 }
792
793 /*
794 * Set segment protection.
795 */
796 if (!rc)
797 {
798 rc = kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 0 /* protect */);
799 if (!rc)
800 return 0;
801 kldrRdrFileGenericProtect(pRdr, pPrep, cSegments, paSegments, 1 /* unprotect */);
802 }
803
804 /* bailout */
805 kHlpPageFree(pPrep->pv, pPrep->cb);
806 return rc;
807}
808
809
810/** @copydoc KLDRRDR::pfnPageSize */
811static KSIZE kldrRdrFilePageSize(PKLDRRDR pRdr)
812{
813#ifdef __OS2__
814 /* The page size on OS/2 wont change anytime soon. :-) */
815 return 0x1000;
816
817#elif defined(__WIN__)
818 SYSTEM_INFO SysInfo;
819 GetSystemInfo(&SysInfo);
820 return SysInfo.dwPageSize;
821 /*return SysInfo.dwAllocationGranularity;*/
822#else
823# error "port me"
824#endif
825}
826
827
828/** @copydoc KLDRRDR::pfnName */
829static const char *kldrRdrFileName(PKLDRRDR pRdr)
830{
831 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
832 return &pRdrFile->szFilename[0];
833}
834
835
836/** @copydoc KLDRRDR::pfnTell */
837static KLDRFOFF kldrRdrFileTell(PKLDRRDR pRdr)
838{
839 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
840
841 /*
842 * If the offset is undefined, try figure out what it is.
843 */
844 if (pRdrFile->off == -1)
845 {
846#ifdef __OS2__
847 ULONG ulNew;
848 APIRET rc = DosSetFilePtr(pRdrFile->File, 0, FILE_CURRENT, &ulNew);
849 if (rc)
850 return -1;
851 pRdrFile->off = ulNew;
852
853#elif defined(__WIN__)
854 LONG offHigh = 0;
855 LONG offLow;
856 int rc;
857
858 SetLastError(0);
859 offLow = SetFilePointer(pRdrFile->File, 0, &offHigh, FILE_CURRENT);
860 rc = GetLastError();
861 if (rc)
862 return -1;
863 pRdrFile->off = ((KLDRFOFF)offHigh << 32) | offLow;
864
865#else
866# error "port me."
867#endif
868 }
869 return pRdrFile->off;
870}
871
872
873/** @copydoc KLDRRDR::pfnSize */
874static KLDRFOFF kldrRdrFileSize(PKLDRRDR pRdr)
875{
876 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
877 return pRdrFile->cb;
878}
879
880
881/** @copydoc KLDRRDR::pfnAllUnmap */
882static int kldrRdrFileAllUnmap(PKLDRRDR pRdr, const void *pvBits)
883{
884 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
885
886 /* check for underflow */
887 if (pRdrFile->cMappings <= 0)
888#if defined(__OS2__) || defined(__WIN__)
889 return ERROR_INVALID_PARAMETER;
890#else
891# error "port me"
892#endif
893
894 /* decrement usage counter, free mapping if no longer in use. */
895 if (!--pRdrFile->cMappings)
896 {
897 kHlpFree(pRdrFile->pvMapping);
898 pRdrFile->pvMapping = NULL;
899 }
900
901 return 0;
902}
903
904
905/** @copydoc KLDRRDR::pfnAllMap */
906static int kldrRdrFileAllMap(PKLDRRDR pRdr, const void **ppvBits)
907{
908 PKLDRRDRFILE pRdrFile = (PKLDRRDRFILE)pRdr;
909
910 /*
911 * Do we need to map it?
912 */
913 if (!pRdrFile->pvMapping)
914 {
915 int rc;
916 KLDRFOFF cb = pRdrFile->Core.pOps->pfnSize(pRdr);
917
918 pRdrFile->pvMapping = kHlpAlloc(cb);
919 if (!pRdrFile->pvMapping)
920#if defined(__OS2__) || defined(__WIN__)
921 return ERROR_NOT_ENOUGH_MEMORY;
922#else
923# error "port me"
924#endif
925 rc = pRdrFile->Core.pOps->pfnRead(pRdr, pRdrFile->pvMapping, cb, 0);
926 if (rc)
927 {
928 kHlpFree(pRdrFile->pvMapping);
929 pRdrFile->pvMapping = NULL;
930 return rc;
931 }
932 pRdrFile->cMappings = 0;
933 }
934
935 *ppvBits = pRdrFile->pvMapping;
936 pRdrFile->cMappings++;
937 return 0;
938}
939
940
941/** @copydoc KLDRRDR::pfnRead */
942static int kldrRdrFileRead(PKLDRRDR pRdr, void *pvBuf, KSIZE cb, KLDRFOFF 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(KLDRFOFF) == 4 ? 0 : (off >> 32);
967 offLow = SetFilePointer(pRdrFile->File, (LONG)off, &offHigh, FILE_BEGIN);
968 if ( offLow != (LONG)off
969 || offHigh != (LONG)(sizeof(KLDRFOFF) == 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 kHlpFree(pRdrFile->pvMapping);
1049 pRdrFile->pvMapping = NULL;
1050 }
1051
1052 kHlpFree(pRdr);
1053 return rc;
1054}
1055
1056
1057/** @copydoc KLDRRDROPS::pfnCreate */
1058static int kldrRdrFileCreate(PPKLDRRDR ppRdr, const char *pszFilename)
1059{
1060 KSIZE 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 KLDRFOFF cb;
1072 char szFilename[CCHMAXPATH];
1073
1074 if ((KUPTR)pszFilename >= 0x20000000)
1075 {
1076 char *psz;
1077 cchFilename = kHlpStrLen(szFilename);
1078 psz = (char *)kHlpAllocA(cchFilename + 1);
1079 kHlpMemCopy(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 KLDRFOFF 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(KLDRFOFF) == 4)
1136 cb = High ? 0x7fffffff : Low;
1137 else
1138 cb = ((KLDRFOFF)High << 32) | Low;
1139
1140#else
1141# error "port me"
1142#endif
1143
1144
1145 /*
1146 * Allocate the reader instance.
1147 */
1148 cchFilename = kHlpStrLen(szFilename);
1149 pRdrFile = (PKLDRRDRFILE)kHlpAlloc(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 kHlpMemCopy(&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.