Reformatted.
[chise/xemacs-chise.git.1] / src / unexnext.c
1 /* Dump Emacs in macho format.
2    Copyright (C) 1990-1993 Free Software Foundation, Inc.
3    Written by Bradley Taylor (btaylor@next.com).
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with:  NeXT port */
23
24 #include <stdio.h>
25 #include <libc.h>
26 #include <nlist.h>
27 #include <mach/mach.h>
28 #include <mach-o/ldsyms.h>
29 #include <mach-o/loader.h>
30
31 int malloc_cookie;
32
33 static void fatal_unexec(char *format, ...)
34    {
35    va_list ap;
36    
37    va_start(ap, format);
38    fprintf(stderr, "unexec: ");
39    vfprintf(stderr, format, ap);
40    fprintf(stderr, "\n");
41    va_end(ap);
42    exit(1);
43    }
44
45 static void mcopy(int ffd,int tfd,
46                   unsigned long fpos,unsigned long tpos,unsigned long len)
47    {
48    if ((ffd==-1)&&(tfd==-1))
49       {
50       char *f,*t,*e;
51       if (fpos>tpos)
52          {
53          f=(char *)fpos;
54          t=(char *)tpos;
55          e=(char *)(fpos+len);
56          while(f<e) *t++=*f++;
57          }
58       else if (tpos>fpos)
59          {
60          f=(char *)(fpos+len);
61          t=(char *)(tpos+len);
62          e=(char *)fpos;
63          while(f>e) *--t=*--f;         
64          }   
65       }
66    else if (ffd==-1)
67       {
68       if (lseek(tfd,tpos,L_SET)<0)
69          fatal_unexec("cannot seek target");
70       if (write(tfd,(void *)fpos,len)!=len)
71          fatal_unexec("cannot write target");
72       }
73    else if (tfd==-1)
74       {
75       if (lseek(ffd,fpos,L_SET)<0)
76          fatal_unexec("cannot seek source");
77       if (read(ffd,(void *)tpos,len)!=len)
78          fatal_unexec("cannot read source");
79       }
80    else
81       {
82       int bread;
83       char *buf=alloca(1<<16);
84       
85       if (lseek(ffd,fpos,L_SET)<0)
86          fatal_unexec("cannot seek source");
87       
88       if (lseek(tfd,tpos,L_SET)<0)
89          fatal_unexec("cannot seek target");
90       
91       while((len>0) && (bread=read(ffd,buf,MIN(1<<16,len)))>0)
92          {
93          if (bread<0)
94             fatal_unexec("cannot read source");
95          if (write(tfd,buf,bread)!=bread)
96             fatal_unexec("cannot write target");
97          len-=bread;
98          }
99       }
100    }
101
102 static void unexec_doit(int infd,int outfd)
103    {
104    int i,j,hpos,opos;
105    extern int malloc_freezedry(void);
106    struct region
107       {
108       struct region *next;
109       unsigned long addr;
110       unsigned long size;
111       vm_prot_t prot;
112       vm_prot_t mprot;
113       } *regions=0,*cregion,**pregions;
114    struct mach_header mh;
115    struct segment_command *lc,*sp;
116    struct symtab_command *st;
117    struct section *sect;
118
119    malloc_cookie=malloc_freezedry();
120    
121       {
122       vm_task_t task=task_self();
123       vm_address_t addr;
124       vm_size_t size;
125       vm_prot_t prot,mprot;
126       vm_inherit_t inhe;
127       boolean_t shrd;
128       port_t name;
129       vm_offset_t offset;
130       
131       for(addr=VM_MIN_ADDRESS,pregions=&regions;
132           vm_region(task,&addr,&size,&prot,&mprot,
133                     &inhe,&shrd,&name,&offset)==KERN_SUCCESS;
134           addr += size)
135          {
136          (*pregions)=alloca(sizeof(struct region));
137          (*pregions)->addr=addr;
138          (*pregions)->size=size;
139          (*pregions)->prot=prot;
140          (*pregions)->mprot=mprot;
141          (*pregions)->next=0;
142          pregions=&((*pregions)->next);
143          }
144       }
145    
146    for(cregion=regions;cregion;cregion=cregion->next)
147       while ((cregion->next) &&
148              (cregion->next->addr==cregion->addr+cregion->size) &&
149              (cregion->next->prot==cregion->prot) &&
150              (cregion->next->mprot==cregion->mprot))
151          {
152          cregion->size += cregion->next->size;
153          cregion->next = cregion->next->next;
154          }
155
156    mcopy(infd,-1,0,(unsigned long) &mh,sizeof(mh));
157    lc=alloca(mh.sizeofcmds);
158    mcopy(infd,-1,sizeof(mh),(unsigned long) lc,mh.sizeofcmds);
159    
160    for(pregions=&regions;*pregions;)
161       {
162       if (!((*pregions)->prot&VM_PROT_WRITE)
163           || ((*pregions)->addr>=0x3000000))
164          goto kill_region;
165       
166       for(sp=lc,i=0;
167           i<mh.ncmds;
168           i++,sp=(struct segment_command *)(((char *)sp)+sp->cmdsize))
169          {
170          unsigned long ob,oe;
171          if (sp->cmd!=LC_SEGMENT||(strcmp(sp->segname,SEG_DATA)==0)) continue;
172          ob=MAX((*pregions)->addr,sp->vmaddr);
173          oe=MIN((*pregions)->addr+(*pregions)->size,sp->vmaddr+sp->vmsize);
174          if (ob >= oe) continue;
175          if (ob==(*pregions)->addr)
176             if (oe==(*pregions)->addr+(*pregions)->size)
177                {
178                goto kill_region;
179                }
180             else
181                {
182                (*pregions)->addr=oe;
183                (*pregions)->size-=(oe-ob);
184                }
185          else
186             if (oe==(*pregions)->addr+(*pregions)->size)
187                {
188                (*pregions)->size-=(oe-ob);
189                }
190             else
191                {
192                cregion=alloca(sizeof(*cregion));
193                cregion->addr=oe;
194                cregion->size=((*pregions)->addr+(*pregions)->size)-oe;
195                cregion->prot=(*pregions)->prot;
196                cregion->mprot=(*pregions)->mprot;
197                cregion->next=(*pregions)->next;
198                (*pregions)->size=ob-(*pregions)->addr;
199                (*pregions)->next=cregion;
200                }
201          }
202       pregions=&((*pregions)->next);
203       continue;
204     kill_region:
205       *pregions=(*pregions)->next;
206       }
207
208    for(sp=lc,i=mh.ncmds,hpos=sizeof(mh),opos=0;
209        i>0;
210        i--,sp=(struct segment_command *)(((char *)sp)+sp->cmdsize))
211       switch (sp->cmd)
212          {
213        case LC_SEGMENT:
214          if (strcmp(sp->segname,SEG_DATA)==0)
215             {
216             mh.ncmds--;
217             j=sp->cmdsize;
218             while (regions)
219                {
220                mcopy(-1,outfd,regions->addr,opos,regions->size);
221                sp->cmd=LC_SEGMENT;
222                sp->cmdsize=sizeof(*sp);
223                strncpy(sp->segname,SEG_DATA,sizeof(sp->segname));
224                sp->vmaddr=regions->addr;
225                sp->vmsize=regions->size;
226                sp->filesize=regions->size;
227                sp->maxprot=regions->prot;
228                sp->initprot=regions->mprot;
229                sp->nsects=0;
230                sp->flags=0;
231                sp->fileoff=opos;
232                opos+=sp->filesize;
233                mcopy(-1,outfd,(unsigned long)sp,hpos,sp->cmdsize);
234                hpos+=sp->cmdsize;
235                mh.ncmds++;
236                regions=regions->next;
237                }
238             sp->cmdsize=j;
239             regions=0;
240             }
241          else if (strcmp(sp->segname,SEG_LINKEDIT)==0)
242             {
243             mh.ncmds--;
244             }
245          else
246             {
247             mcopy(infd,outfd,sp->fileoff,opos,sp->filesize);
248             sect=(struct section *) (((char *)sp)+sizeof(*sp));
249             for(j=0;j<sp->nsects;j++)
250                {
251                if (sect[j].offset!=0)
252                   sect[j].offset=(sect[j].offset-sp->fileoff)+opos;
253                if (sect[j].reloff!=0)
254                   sect[j].reloff=(sect[j].reloff-sp->fileoff)+opos;
255                }
256             sp->fileoff=opos;
257             opos+=sp->filesize;
258             mcopy(-1,outfd,(unsigned long)sp,hpos,sp->cmdsize);
259             hpos+=sp->cmdsize;
260             }
261          break;
262        case LC_SYMTAB:
263          st=(struct symtab_command *)sp;
264          
265          mcopy(infd,outfd,st->symoff,opos,st->nsyms*sizeof(struct nlist));
266          st->symoff=opos;
267          opos+=sizeof(struct nlist)*st->nsyms;
268          
269          mcopy(infd,outfd,st->stroff,opos,st->strsize);
270          ((struct symtab_command *)sp)->stroff=opos;
271          opos+=((struct symtab_command *)sp)->strsize;
272        default:
273          mcopy(-1,outfd,(unsigned long)sp,hpos,sp->cmdsize);
274          hpos+=sp->cmdsize;
275          }
276    mh.sizeofcmds=hpos-sizeof(mh);
277    mcopy(-1,outfd,(unsigned long) &mh,0,sizeof(mh));
278    }
279
280 void unexec(char *outfile,char *infile)
281    {
282    char tmpfile[MAXPATHLEN];
283    int infd,outfd;
284    
285    if ((infd=open(infile, O_RDONLY, 0))<0)
286       fatal_unexec("cannot open input file `%s'", infile);
287
288    strcpy(tmpfile,outfile);
289    strcat(tmpfile,"-temp");
290    
291    if ((outfd=open(tmpfile, O_RDWR|O_TRUNC|O_CREAT, 0755))<0)
292       fatal_unexec("cannot open temporary output file `%s'",tmpfile);
293
294    unexec_doit(infd,outfd);
295
296    close(infd);
297    close(outfd);
298    if (rename(tmpfile, outfile)<0)
299       {
300       unlink(tmpfile);
301       fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
302       }  
303    }