home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / debug / Common / RegionManager.m < prev    next >
Text File  |  1994-11-15  |  15KB  |  572 lines

  1. #import "RegionManager.h"
  2. #import <stdlib.h>
  3. #import <string.h>
  4. #import <mach/mach.h>
  5. #import <mach-o/loader.h>
  6. #import <mach-o/nlist.h>
  7. #import <mach/vm_param.h>
  8.  
  9. kern_return_t static inline vmRegion(task_t task, 
  10.                      vm_address_t address,
  11.                      Region *region)
  12. {
  13.     vm_offset_t    offset;
  14.     vm_prot_t maxProtection;
  15.     vm_inherit_t inheritance;
  16.     boolean_t shared;
  17.     port_t objectName;
  18.     region->reloc.address = address;
  19.     return vm_region(task,
  20.                  ®ion->reloc.address,
  21.              ®ion->reloc.size,
  22.              ®ion->protection,
  23.              &maxProtection,
  24.              &inheritance,
  25.              &shared,
  26.              &objectName,
  27.              &offset);
  28. }
  29.  
  30. @implementation RegionManager
  31.  
  32. -initTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
  33. {
  34.     vm_statistics_data_t vm_stats;
  35.     
  36.     task = theTask;
  37.     vm_statistics(theTask, &vm_stats);
  38.     pageSize = vm_stats.pagesize;
  39.     relocSize = sizeof(Region);
  40.     rmFlags.shouldSortRelocs = NO;
  41.     if (readInRegions)
  42.     [self readInAllRelocs];
  43.     else
  44.     rmFlags.invalid = YES;
  45.     return self;
  46. }
  47.  
  48. -(BOOL)isTask
  49. {
  50.     struct task_basic_info taskInfo;
  51.     unsigned int taskInfoCount;
  52.     BOOL ret;
  53.     
  54.     taskInfoCount = TASK_BASIC_INFO_COUNT;
  55.     ret = (task_info(task,
  56.                        TASK_BASIC_INFO,
  57.                (task_info_t)&taskInfo,
  58.                &taskInfoCount) == KERN_SUCCESS) ? YES : NO;
  59.     if (!ret && taskGoneCallBack)
  60.     (*taskGoneCallBack)();
  61.     return ret;
  62. }
  63.  
  64. -(void)setTaskGoneCallBack: (TaskGoneCallBack)theCallBack
  65. {
  66.     taskGoneCallBack = theCallBack;
  67. }
  68.  
  69. +newTask: (vm_task_t)theTask
  70. {
  71.     return [[super new] initTask: theTask readInRegions: YES];
  72. }
  73.  
  74. +newTask: (vm_task_t)theTask readInRegions: (BOOL)readInRegions
  75. {
  76.     return [[super new] initTask: theTask readInRegions: readInRegions];
  77. }
  78.  
  79. -invalidate
  80. {
  81.     if (rmFlags.invalid)
  82.     return self;
  83.     else {
  84.     Region *region;
  85.     int count;
  86.     if (relocs) {
  87.         for (count = numRelocs, region = (Region *)relocs;
  88.          count; 
  89.          count--, region++) {
  90.         if (region->reloc.rFlags.readIn)
  91.             vm_deallocate(task_self(),
  92.                   region->reloc.data,
  93.                   region->reloc.size);
  94.         }
  95.     }
  96.     if (pages) {
  97.         free(pages);
  98.         pages = NULL;
  99.     }
  100.     return [super invalidate];
  101.     }
  102. }
  103.  
  104. -(void)getStartPage: (void **)startPage andSize: (int *)sizePage
  105.          forPointer: (void *)start      andSize: (int)numBytes
  106. {
  107.     vm_address_t offset = ((vm_address_t)start % pageSize);
  108.     vm_address_t s = numBytes + offset;
  109.     
  110.     *startPage = start - offset;
  111.     *sizePage =  (s - (s % pageSize)) + pageSize;
  112. }
  113.         
  114. -(void)protectDataAt: (const void *)start for: (int)numBytes
  115. {
  116.     vm_address_t offset = ((vm_address_t)start % pageSize);
  117.     vm_address_t startPage = (vm_address_t)start - offset;
  118.     size_t sizePage = numBytes + offset;
  119.     
  120.     vm_protect(task, startPage, pageSize, NO, VM_PROT_READ);
  121. }
  122.  
  123. -(void)unProtectDataAt: (const void *)start for: (int)numBytes
  124. {
  125.     vm_address_t offset = ((vm_address_t)start % pageSize);
  126.     vm_address_t startPage = (vm_address_t)start - offset;
  127.     size_t sizePage = numBytes + offset;
  128.     
  129.     vm_protect(task, startPage, pageSize, NO, VM_PROT_READ | VM_PROT_WRITE);
  130. }
  131.  
  132. -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region markOnly: (BOOL)markOnly
  133. {
  134.     vm_address_t offset = ((vm_address_t)start % pageSize);
  135.     vm_address_t startPage = (vm_address_t)start - offset;
  136.     size_t sizePage = numBytes + offset;
  137.     pointer_t startData;
  138.     kern_return_t ret = 0;
  139.     unsigned char *pPage;
  140.     
  141.     if (markOnly) {
  142.     if (!region->pagesInvalid)
  143.         regionsInvalid++;
  144.     }
  145.     for (sizePage += (pageSize - (sizePage % pageSize)),
  146.          startData = region->reloc.data
  147.                      + ((pointer_t)startPage - region->reloc.address),
  148.          pPage = region->pages
  149.              + (((pointer_t)startPage - region->reloc.address) / pageSize);
  150.          sizePage && !ret;
  151.      sizePage -= pageSize, startData += pageSize, startPage += pageSize,
  152.      pPage++) {
  153.     if (markOnly) {
  154.         if (!(*pPage & PAGEINVALID)) {
  155.         *pPage |= PAGEINVALID;
  156.         region->pagesInvalid++;
  157.         }
  158.     } else {
  159.         *pPage &= ~PAGEINVALID;
  160.         if (*pPage & VM_PROT_WRITE)
  161.         ret = vm_write(task, startPage, startData, pageSize);
  162.         else {
  163.         vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
  164.         ret = vm_write(task, startPage, startData, pageSize);
  165.         vm_protect(task, startPage, pageSize, NO,
  166.                 (vm_prot_t)(*pPage & 0x7));
  167.         }
  168.     }
  169.     }
  170.     if (ret == KERN_SUCCESS)
  171.     return numBytes;
  172.     else {
  173.     [self isTask];
  174.     return 0;
  175.     }
  176. }
  177.  
  178. -(int)writeDataAt: (const void *)start for: (int)numBytes reloc: (Region *)region
  179. {
  180.     return [self writeDataAt: start for: numBytes reloc: region markOnly: NO];
  181. }
  182.  
  183. -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data markOnly: (BOOL)markOnly
  184. {
  185.     int numBytesInRegion;
  186.     Reloc *reloc = [self relocFor: start];
  187.     if (reloc) {
  188.         numBytesInRegion = reloc->maxAddress - (int)start;
  189.         if (numBytes > numBytesInRegion)
  190.         numBytes = numBytesInRegion;
  191.     if (numBytes == 1)
  192.         *(char *)(reloc->data + ((pointer_t)start - reloc->address))
  193.         = *(char *)data;
  194.     else
  195.         memcpy((void *)(reloc->data + ((pointer_t)start - reloc->address)),
  196.                data,
  197.            numBytes);
  198.     return [self writeDataAt: start for: numBytes  reloc: (Region *)reloc markOnly: markOnly];
  199.     } else
  200.     return 0;
  201. }
  202.  
  203. -(int)putDataAt: (void *)start for: (int)numBytes from: (const void *)data
  204. {
  205.     return [self putDataAt: start for: numBytes from: data markOnly: NO];
  206. }
  207.  
  208. -(void)flushMarkedPages
  209. {
  210.     int ret = 0;
  211.     while (regionsInvalid) {
  212.     int i;
  213.     Region *region;
  214.     
  215.     for (i = 0, region = (Region *)relocs;
  216.          i < numRelocs;
  217.          i++, ((void *)region) += relocSize) {
  218.         if (region->pagesInvalid) {
  219.         unsigned char *p = region->pages;
  220.         while (region->pagesInvalid) {
  221.             if (*p & PAGEINVALID) {
  222.             int numPage = p - region->pages;
  223.             pointer_t startPage, startData;
  224.             
  225.             startPage
  226.             = region->reloc.address + (numPage * pageSize);
  227.             startData
  228.             = region->reloc.data + (numPage * pageSize);
  229.             *p &= ~PAGEINVALID;
  230.             region->pagesInvalid--;
  231.             if (*p & VM_PROT_WRITE)
  232.                 ret = vm_write(task, startPage, startData, pageSize);
  233.             else {
  234.                 vm_protect(task, startPage, pageSize, NO, VM_PROT_WRITE);
  235.                 ret = vm_write(task, startPage, startData, pageSize);
  236.                 vm_protect(task, startPage, pageSize, NO,
  237.                     (vm_prot_t)(*p & 0x7));
  238.             }
  239.             }
  240.             p++;
  241.         }
  242.         regionsInvalid--;
  243.         }
  244.     }
  245.     }
  246.     if (ret) 
  247.     [self isTask];
  248. }
  249.  
  250. -(int)writeDataAt: (const void *)start for: (int)numBytes;
  251. {
  252.     Reloc *reloc = [self relocFor: start];
  253.     if (reloc)
  254.     return [self writeDataAt: start for: numBytes reloc: (Region *)reloc];
  255.     else
  256.     return NO;
  257. }
  258.  
  259. -(BOOL)readInReloc: (Reloc *)reloc
  260. {
  261.     kern_return_t ret;
  262.     unsigned int nData;
  263.     if (reloc->rFlags.readIn) {
  264.     return YES;
  265.     } else {
  266.     ret = vm_read(task, reloc->address, reloc->size, &reloc->data, &nData);
  267.     if (ret == KERN_SUCCESS) {
  268.         reloc->maxData = reloc->data + reloc->size;
  269.         reloc->displacement = reloc->data - reloc->address;
  270.         reloc->rFlags.readIn = YES;
  271.         return YES;
  272.     } else {
  273.         [self isTask];
  274.         return NO;
  275.     }
  276.     }
  277. }
  278.  
  279. -(void)combineRegions: (BOOL)combineRegions
  280. { dontCombineRegions = !combineRegions;}
  281.  
  282. -(void)_readInAllRelocs
  283. {
  284.     kern_return_t error = 0;
  285.     vm_address_t address = VM_MIN_ADDRESS;
  286.     Region *theRegion, *regions, *newRegion, *nextRegion, *lastRegion;
  287.     int count = 0, numPages = 0, numAlloced = 16, nPages;
  288.     unsigned char *thePage;
  289.     
  290.     if ([self isTask]) {
  291.     theRegion = regions = malloc(numAlloced * sizeof(Region));
  292.     bzero(regions, numAlloced * sizeof(Region));
  293.     while (!error) {
  294.         error = vmRegion(task, address, theRegion);
  295.         address = theRegion->reloc.address + theRegion->reloc.size;
  296.         if (!error) {
  297.         if (theRegion->protection & VM_PROT_READ) {
  298.             count++;
  299.             numPages += theRegion->reloc.size / pageSize;
  300.             if (count < numAlloced)
  301.             theRegion++;
  302.             else {
  303.             numAlloced *= 2;
  304.             regions = realloc(regions,
  305.                               numAlloced * sizeof(Region));
  306.             theRegion = regions + count;
  307.             bzero(theRegion, count * sizeof(Region));
  308.             }
  309.         }
  310.         if (address < theRegion->reloc.address)
  311.             error = KERN_NO_SPACE;
  312.         }
  313.     }
  314.     if (error == KERN_NO_SPACE) {
  315.         lastRegion = theRegion;
  316.     
  317.         pages = malloc(numPages);
  318.         for (theRegion = regions, thePage = pages;
  319.              theRegion < lastRegion;
  320.          theRegion++) {
  321.         theRegion->pages = thePage;
  322.         nPages = theRegion->reloc.size / pageSize;
  323.         while(nPages--)
  324.             *(thePage++) = (unsigned char)theRegion->protection;
  325.         }
  326.         
  327.         if (dontCombineRegions) {
  328.         for (theRegion = regions; theRegion < lastRegion; theRegion++)
  329.             theRegion->reloc.maxAddress
  330.             = theRegion->reloc.address + theRegion->reloc.size;
  331.         relocs = regions;
  332.         numRelocs = count;
  333.         } else {
  334.         relocs = malloc(count * sizeof(Region));
  335.         bzero(relocs, count * sizeof(Region));
  336.         for (theRegion = regions, newRegion = relocs;
  337.             theRegion < lastRegion;
  338.             theRegion = nextRegion, newRegion++) {
  339.             for (nextRegion = theRegion + 1;
  340.             (nextRegion < lastRegion
  341.             && ((theRegion->reloc.address + theRegion->reloc.size)
  342.                 == nextRegion->reloc.address));
  343.             nextRegion++) {
  344.             theRegion->reloc.size += nextRegion->reloc.size;
  345.             }
  346.             *newRegion = *theRegion;
  347.             newRegion->reloc.maxAddress
  348.             = newRegion->reloc.address + newRegion->reloc.size;
  349.         }
  350.         numRelocs = newRegion - (Region *)relocs;
  351.         relocs = realloc(relocs, numRelocs * sizeof(Region));
  352.         free(regions);
  353.         }
  354.         rmFlags.invalid = NO;
  355.     } else
  356.         free(regions);
  357.         
  358.     if (error != KERN_NO_SPACE) 
  359.         [self isTask];
  360.     } 
  361. }
  362.  
  363. -(struct mach_header *)getMachHeader
  364. {
  365.     Reloc *reloc;
  366.     int count;
  367.     struct mach_header *header, *foundHeader;
  368.  
  369.     if (rmFlags.invalid)
  370.     [self readInAllRelocs];
  371.     reloc = relocs;
  372.     for (foundHeader = NULL, count = 0;
  373.          !foundHeader && count < numRelocs;
  374.      count++) {
  375.     [self readInReloc: reloc];
  376.     header = [self pointerFor: (void *)reloc->address
  377.                      withSize: sizeof(*header)];
  378.     if (header
  379.         && (header->magic == MH_MAGIC)
  380.         && ([self pointerFor: (void *)reloc->address
  381.                     withSize: header->sizeofcmds]))
  382.         foundHeader = header;
  383.     else
  384.         ((void *)reloc) += relocSize;
  385.     }
  386.     return foundHeader;
  387. }
  388.  
  389. -(int)getNumMachHeaders
  390. {
  391.     struct mach_header *myHeader;
  392.     int numHeaders, i;
  393.     struct fvmlib_command *loadCmd;
  394.     if (myHeader = [self getMachHeader]) {
  395.     numHeaders = 1;
  396.     for (i = 0, loadCmd = (struct fvmlib_command *)(myHeader + 1);
  397.          i < myHeader->ncmds;
  398.          i++,
  399.          loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
  400.         if (loadCmd->cmd == LC_LOADFVMLIB)
  401.         numHeaders++;
  402.     }
  403.     } else
  404.     numHeaders = 0;
  405.     return numHeaders;
  406. }
  407.  
  408. -(struct mach_header **)getMachHeadersWithNames: (char ***)names
  409. {
  410.     struct mach_header *myHeader, **headers, *header;
  411.     char **theNames = NULL;
  412.     struct fvmlib_command *loadCmd;
  413.     int numHeaders, headerIndex;
  414.     numHeaders = [self getNumMachHeaders];
  415.     myHeader = [self getMachHeader];
  416.     headers = malloc((numHeaders + 1) * sizeof(*headers));
  417.     if (names) {
  418.     *names = theNames = malloc((numHeaders + 1) * sizeof(*theNames));
  419.     theNames[0] = NULL;
  420.     }
  421.     headers[0] = myHeader;
  422.     for (headerIndex = 1, loadCmd = (struct fvmlib_command *)(myHeader + 1); 
  423.      headerIndex < numHeaders;
  424.      loadCmd = ((void *)loadCmd + loadCmd->cmdsize)) {
  425.     if (loadCmd->cmd == LC_LOADFVMLIB) {
  426.         header = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr) 
  427.                          withSize: sizeof(*header)];
  428.         if (header)
  429.         headers[headerIndex]
  430.         = [self pointerFor: (void *)(loadCmd->fvmlib.header_addr)
  431.                       withSize: header->sizeofcmds];
  432.         if (names)
  433.         theNames[headerIndex]
  434.         = (char *)loadCmd
  435.                 + ((struct fvmlib_command *)loadCmd)
  436.                 ->fvmlib.name.offset; 
  437.         headerIndex++;
  438.     }
  439.     }
  440.     headers[numHeaders] = NULL;
  441.     if (names)
  442.     theNames[numHeaders] = NULL;
  443.     return headers;
  444. }
  445.  
  446. -(struct mach_header **)getMachHeaders
  447. {
  448.     return [self getMachHeadersWithNames: NULL];
  449. }
  450.  
  451. -(unsigned)getSlide
  452. {
  453.     return 0;
  454. }
  455.  
  456. -(struct mach_header*)copyLoadedImage:(struct mach_header*)header_addr
  457.               withSlide:(unsigned)slide
  458. {
  459.   struct load_command *cmd;
  460.   unsigned long fileSize = 0;
  461.   struct mach_header *header, *newHeader;
  462.   struct symtab_command *symtabCmd = 0;
  463.   kern_return_t r;
  464.   int i;
  465.   unsigned header_size;
  466.  
  467.  
  468.   header = [self pointerFor:header_addr 
  469.          withSize:sizeof (struct mach_header)];
  470.   header_size = header->sizeofcmds + sizeof (struct mach_header);
  471.   
  472.   header = [self pointerFor:header_addr
  473.          withSize:header_size];
  474.  
  475.   // get the size of the original file
  476.   for (cmd = (struct load_command *)(header + 1), i = 0;
  477.        i < header->ncmds;
  478.        ((void *)cmd) += cmd->cmdsize, i++) 
  479.     {
  480.       unsigned long topOff;
  481.  
  482.       if (cmd->cmd == LC_SEGMENT)
  483.     {
  484.       struct segment_command *segCmd = (struct segment_command *)cmd;
  485.       topOff = segCmd->fileoff + segCmd->filesize;
  486.       
  487.       if (topOff > fileSize)
  488.         fileSize = topOff;
  489.     }
  490.       else if (cmd->cmd == LC_SYMTAB)
  491.     {
  492.       symtabCmd = (struct symtab_command*)cmd;
  493.     }
  494.     }
  495.  
  496.   r = vm_allocate (task_self (), (vm_address_t*)&newHeader, fileSize, 1);
  497.   if (r != KERN_SUCCESS) [self error:"vm_allocate failed %d", r];
  498.  
  499.   // get the size of the original file
  500.   for (cmd = (struct load_command *)(header + 1), i = 0;
  501.        i < header->ncmds;
  502.        ((void *)cmd) += cmd->cmdsize, i++)
  503.     {
  504.       if (cmd->cmd == LC_SEGMENT)
  505.         {
  506.           struct segment_command *segCmd = (struct segment_command *)cmd;
  507.           void *segment = [self pointerFor:(char*)segCmd->vmaddr + slide
  508.                                   withSize:segCmd->filesize];
  509.  
  510.           // get size rounded up to page size...
  511.           vm_size_t size = segCmd->filesize;
  512.           if (size % vm_page_size != 0)
  513.             {
  514.               size += vm_page_size - (size % vm_page_size);
  515.             }
  516.  
  517.           if ((segCmd->fileoff % vm_page_size) == 0)
  518.             {
  519.               vm_copy (task_self (),
  520.                        (vm_address_t)segment,
  521.                        (vm_size_t)size,
  522.                        (vm_address_t)((void*)newHeader + segCmd->fileoff));
  523.             }
  524.           else
  525.             {
  526.               memcpy (segment, (void*)newHeader + segCmd->fileoff, size);
  527.             }
  528.         }
  529.     }
  530.  
  531.   // slide the image by modifying the load commands
  532.   for (cmd = (struct load_command *)(newHeader + 1), i = 0;
  533.        i < header->ncmds;
  534.        ((void *)cmd) += cmd->cmdsize, i++) 
  535.     {
  536.       if (cmd->cmd == LC_SEGMENT)
  537.       {
  538.     struct segment_command *segCmd = (struct segment_command *)cmd;
  539.  
  540.     {
  541.       int n;
  542.       struct section *sect;
  543.       segCmd->vmaddr += slide;
  544.       
  545.       for (sect = (struct section*) (segCmd + 1), n = 0; 
  546.            n < segCmd->nsects; 
  547.            sect += 1, n += 1)
  548.         {
  549.           sect->addr += slide;
  550.         }
  551.     }
  552.       }
  553.     }
  554.  
  555.   // now relocate the symbol table information
  556.   {
  557.     struct nlist* symtab = (struct nlist*) ((char*)newHeader 
  558.                         + symtabCmd->symoff);
  559.     for (i = 0; i < symtabCmd->nsyms; i++)
  560.       {
  561.     if (symtab[i].n_sect != NO_SECT)
  562.       {
  563.         symtab[i].n_value += slide;
  564.       }
  565.       }
  566.   }
  567.  
  568.   return newHeader;
  569. }
  570.  
  571. @end
  572.