Path: utzoo!utgpu!water!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!mailrus!ames!scubed!warner From: warner@scubed.UUCP (Ken Warner) Newsgroups: comp.unix.questions Subject: Re: Core files ... it works Keywords: core data bss Message-ID: <797@scubed.UUCP> Date: 29 Jun 88 17:55:59 GMT References: <344@ajpo.sei.cmu.edu> <441@anagld.UUCP> <790@scubed.UUCP> <11954@mimsy.UUCP> <796@scubed.UUCP> <537@philmds.UUCP> Reply-To: warner@scubed.UUCP (Ken Warner) Followup-To: comp.unix.questions Organization: S-Cubed Lines: 329 In article <537@philmds.UUCP> leo@philmds.UUCP (L.J.M. de Wit) writes: >In article <796@scubed.UUCP> warner@scubed.UUCP (Ken Warner) writes: >|In article <11954@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >||In article <790@scubed.UUCP> warner@scubed.UUCP (Ken Warner) writes: >|||Is there a way to run a core file? >||It cannot be done portably, but with certain restrictions, it can >||almost always be done. >|[stuff deleted] >||Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris >|Well, I've looked at unexec() from emacs and then tried to write my own [stuff deleted] >You do not copy the BSS space nor any extension of the data space Yup! That was the problem. I've appended a copy of the current state of my effort below. It works. >I'm still wondering why you use 1 char writes? Pretty expensive I think. Yup again! It was only a prototype. Not production quality. >And I also would like to know what use this scheme has? Is it for [stuff deleted] > Leo. Well, if one had a custom shell for doing a particular job that took a long time, days perhaps, it would be nice to be able to stop and go home knowing one could restart again where one had left off. In many implementations, one can save a Lisp, Smalltalk or Emacs in a particular state. I thought it would be interesting to be able to save a C program, perhaps a custom shell, in a particular state. The next thing I want to do is save the stack and registers at a particular, known state and restore the stack and registers on start-up. I know this will take some start-up code. My questions: Where is the top of the stack, I know it starts at some high-memory location and grows down. How and where can a program find out the bounds of the stack. How can one get the contents of the registers, including the pc, fp and sp registers? How can these be restored? Below is a test program that shows my progress so far. It is Sun 3, OS 3.4,5 specific. I've no interest in making it portable right now. It first copies the text from the object file, its own name is argv[0] in the test program. Then it copies the data and bss segments from memory, sets the size of the data segment (hdr.a_data) to reflect the increase in size of the data segment, then sets the bss size (hdr.a_bss) to 0. Executing the test program and then the resulting executable will give a small demonstration of saving the values of static and dynamic variables. There is probably a bug lurking about somewhere; this isn't production quality code, but it is a start. The next thing I want to do is to save the stack and registers. They can also be saved in the bss segment and restored when the program is restarted. This should be some fun, eh? -------------------------------------------------------------------------------- #include#include #include #include #include #include #include extern int end; extern int edata; extern int etext; extern int first(); extern char *sbrk (); static struct exec hdr; first() { printf("first\n"); second(); fflush(stdout); } second() { printf("second\n"); third(); fflush(stdout); } third() { printf("third\n"); forth(); fflush(stdout); } forth() { printf("forth\n"); fflush(stdout); } int foo; char *string; main(argc,argv) int argc; char *argv[]; { struct exec hdr; int a_out; if ((a_out = open (argv[0], O_RDONLY)) < 0) { perror(argv[0]); } if (read (a_out, &hdr, sizeof(hdr)) != sizeof(hdr)) { perror(argv[0]); } close(a_out); #ifdef DEBUG if(foo == 9) printf("foo was initialized to %d\n",foo); else printf("foo was initialized to %d\n",foo); printf("N_TXTADDR(hdr) = %x\n",N_TXTADDR(hdr)); printf("N_DATADDR(hdr) = %x\n",N_DATADDR(hdr)); printf("N_BSSADDR(hdr) = %x\n",N_BSSADDR(hdr)); printf("sizeof(hdr) = %x\n",sizeof(hdr)); printf("a_machtype = %d\n",hdr.a_machtype); printf("a_magic = %o\n",hdr.a_magic); printf("a_text = %x\n",hdr.a_text); printf("a_data = %x\n",hdr.a_data); printf("a_bss = %x\n",hdr.a_bss); printf("a_syms = %x\n",hdr.a_syms); printf("a_entry = %x\n",hdr.a_entry); printf("a_trsize = %x\n",hdr.a_trsize); printf("a_drsize = %x\n",hdr.a_drsize); printf("sbrk(0) = %x\n",sbrk(0)); #endif if(foo == 9) printf("foo = %d and string = %s\n",foo,string); else { if((string = (char *)malloc(80 * sizeof(char))) == NULL) { perror("malloc"); exit(-1); } strcpy(string,"this is a test"); } foo = 9; unexec(argv[1],argv[0]); first(); second(); third(); forth(); exit(1); } /* **************************************************************** * unexec(new_name,a_name) where new_name is the name of the new executable * and a_name is the name of the file containing the currently executing * program * */ unexec (new_name, a_name) char *new_name, *a_name; { int new, a_out = -1; if (a_name && (a_out = open (a_name, O_RDONLY)) < 0) { perror (a_name); exit(-1); } if ((new = open (new_name, O_WRONLY|O_CREAT|O_TRUNC,0755)) < 0) { perror (new_name); exit(-1); } if (make_a_out(new, a_out,new_name,a_name) < 0) { close (new); unlink (new_name); /* Failed, unlink new a.out */ return -1; } close (new); close (a_out); return 0; } /* **************************************************************** * make_a_out */ static int make_a_out (new, a_out,new_name,a_name) int new, a_out; char *new_name,*a_name; { char buff[PAGSIZ]; unsigned int i,numrd,pos,bss_end; bzero(buff,PAGSIZ); if (read (a_out, &hdr, sizeof(hdr)) != sizeof hdr) { perror (a_out); return(-1); } if (N_BADMAG (hdr)) { printf("invalid magic number in %s", a_name); fflush(stdout); return(-1); } /* rewind a.out */ if(lseek (a_out,0,L_SET) == -1) { perror("lseek #1"); return(-1); } /*snarf and plop text from old a.out to new */ for(i=0;i 0) && (write(new,buff,numrd) == -1)) { perror("write #3"); return(-1); } break; } if(write(new,buff,PAGSIZ) != PAGSIZ) { perror("write #4"); return(-1); } } /*rewind to begining of file */ if(lseek (new,0,L_SET) == -1) { perror("lseek #3"); return(-1); } /* make size of data in header to include the bss space */ hdr.a_data = (int)bss_end - (int)N_DATADDR(hdr); hdr.a_bss = 0; /*write out the header if you changed anything */ if (write (new, &hdr, sizeof hdr) != sizeof hdr) { perror ("write #5"); return(-1); } return(0); }