/[hurd]/hurd/exec/elfcore.c
ViewVC logotype

Diff of /hurd/exec/elfcore.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by tb, Sat Jul 3 23:48:38 1999 UTC revision 1.3 by roland, Fri Mar 8 23:35:51 2002 UTC
# Line 1  Line 1 
1    #include <hurd.h>
2    #include <elf.h>
3    #include <link.h>
4    #include <string.h>
5    #include <sys/mman.h>
6    #include <sys/utsname.h>
7    
8    
9    #define ELF_MACHINE     EM_386  /* XXX */
10    
11    #define ELF_CLASS       PASTE (ELFCLASS, __ELF_NATIVE_CLASS)
12    #define PASTE(a, b)     PASTE_1 (a, b)
13    #define PASTE_1(a, b)   a##b
14    
15    #include <endian.h>
16    #if BYTE_ORDER == BIG_ENDIAN
17    #define ELF_DATA ELFDATA2MSB
18    #elif BYTE_ORDER == LITTLE_ENDIAN
19    #define ELF_DATA ELFDATA2LSB
20    #endif
21    
22    
23    error_t
24    dump_core (task_t task, file_t file, off_t corelimit,
25               int signo, long int sigcode, int sigerror)
26  {  {
27    processor_set_name_t pset;    error_t err;
28    host_t host;    ElfW(Phdr) *phdrs, *ph;
29    processor_set_basic_info_data_t pinfo;    ElfW(Ehdr) hdr =              /* ELF header for the core file.  */
30      {
31        e_ident:
32        {
33          [EI_MAG0] = ELFMAG0,
34          [EI_MAG1] = ELFMAG1,
35          [EI_MAG2] = ELFMAG2,
36          [EI_MAG3] = ELFMAG3,
37          [EI_CLASS] = ELF_CLASS,
38          [EI_DATA] = ELF_DATA,
39          [EI_VERSION] = EV_CURRENT,
40          [EI_OSABI] = ELFOSABI_SYSV,
41          [EI_ABIVERSION] = 0
42        },
43        e_type: ET_CORE,
44        e_version: EV_CURRENT,
45        e_machine: ELF_MACHINE,
46        e_ehsize: sizeof hdr,
47        e_phentsize: sizeof phdrs[0],
48        e_phoff: sizeof hdr,        /* Fill in e_phnum later.  */
49      };
50      off_t offset;
51      size_t wrote;
52    
53    thread_t *threads;    thread_t *threads;
54    size_t nthreads;    size_t nthreads, i;
55      off_t notestart;
56    
57    vm_address_t addr;    /* Helper macros for writing notes.  */
58    vm_size_t size;  #define DEFINE_NOTE(typename) struct { struct note_header hdr; typename data; }
59    vm_prot_t prot, maxprot;  #define WRITE_NOTE(type, var) ({                                              \
60    vm_inherit_t inherit;    (var).hdr = NOTE_HEADER ((type), sizeof (var));                             \
61    boolean_t shared;    write_note (&(var).hdr);                                                    \
62    memory_object_name_t objname;  })
63    vm_offset_t offset;    struct note_header
64      {
65    /* Figure out what flavor of machine the task is on.  */      ElfW(Nhdr) note;
66    if (err = task_get_assignment (task, &pset))      char name[4];
67      goto lose;    };
68    err = processor_set_info (pset, PROCESSOR_SET_BASIC_INFO, &host,  #define NOTE_HEADER(type, size) \
69                              &pinfo, PROCESSOR_SET_BASIC_INFO_COUNT);    ((struct note_header) { { 4, (size), (type) }, "CORE" })
70    mach_port_deallocate (mach_task_self (), pset);    inline error_t write_note (struct note_header *hdr)
71    if (err)      {
72      goto lose;        error_t err = 0;
73    err = bfd_mach_host_arch_mach (host, &arch, &machine, &e_machine);        char *data = (char *) hdr;
74    mach_port_deallocate (mach_task_self (), host);        size_t size = sizeof *hdr + hdr->note.n_descsz;
75          if (corelimit >= 0 && offset + size > corelimit)
76            size = corelimit - offset;
77          while (size > 0)
78            {
79              err = io_write (file, data, size, offset, &wrote);
80              if (err)
81                return err;
82              offset = (offset + wrote + 3) &~ 3; /* Pad it to word alignment.  */
83              if (wrote > size)
84                break;
85              data += wrote;
86              size -= wrote;
87            }
88          return err;
89        }
90    
91      struct vm_region_list
92      {
93        struct vm_region_list *next;
94        vm_prot_t protection;
95        vm_address_t start;
96        vm_size_t length;
97      };
98      struct vm_region_list *regions = NULL, **tailp = &regions, *r;
99      unsigned int nregions = 0;
100    
101      if (corelimit >= 0 && corelimit < sizeof hdr)
102        return EFBIG;
103    
104      {
105        /* Examine the task and record the locations of contiguous memory
106           segments that we will dump into the core file.  */
107    
108        vm_address_t region_address, last_region_address, last_region_end;
109        vm_prot_t last_protection;
110        inline void record_last_region (void)
111          {
112            if (last_region_end > last_region_address
113                && last_protection != VM_PROT_NONE)
114              {
115                struct vm_region_list *region = alloca (sizeof *region);
116                *tailp = region;
117                tailp = &region->next;
118                region->next = NULL;
119                region->start = last_region_address;
120                region->length = last_region_end - last_region_address;
121                region->protection = last_protection;
122                ++nregions;
123              }
124          }
125    
126        region_address = last_region_address = last_region_end = VM_MIN_ADDRESS;
127        last_protection = VM_PROT_NONE;
128        while (region_address < VM_MAX_ADDRESS)
129          {
130            vm_prot_t protection;
131            vm_prot_t max_protection;
132            vm_inherit_t inheritance;
133            boolean_t shared;
134            mach_port_t object_name;
135            vm_offset_t offset;
136            vm_size_t region_length = VM_MAX_ADDRESS - region_address;
137    
138            err = vm_region (task,
139                             &region_address,
140                             &region_length,
141                             &protection,
142                             &max_protection,
143                             &inheritance,
144                             &shared,
145                             &object_name,
146                             &offset);
147            if (err == KERN_NO_SPACE)
148              break;
149            if (err != KERN_SUCCESS)
150              return err;
151    
152            if (protection == last_protection && region_address == last_region_end)
153              /* This region is contiguous with and indistinguishable from
154                 the previous one, so we just extend that one.  */
155              last_region_end = region_address += region_length;
156            else
157              {
158                /* This region is distinct from the last one we saw,
159                   so record that previous one.  */
160                record_last_region ();
161                last_region_address = region_address;
162                last_region_end = region_address += region_length;
163                last_protection = protection;
164              }
165          }
166        /* Record the final region.  */
167        record_last_region ();
168      }
169    
170      /* Now we start laying out the file.  */
171      offset = round_page (sizeof hdr + ((nregions + 1) * sizeof *phdrs));
172    
173      /* Final check for tiny core limit.  From now on, we will simply truncate
174         the file at CORELIMIT but not change the contents of what we write.  */
175      if (corelimit >= 0 && corelimit < offset)
176        return EFBIG;
177    
178      /* Now we can complete the file header and write it.  */
179      hdr.e_phnum = nregions + 1;
180      err = io_write (file, (char *) &hdr, sizeof hdr, 0, &wrote);
181    if (err)    if (err)
182      goto lose;      return err;
183      if (wrote < sizeof hdr)
184        return EGRATUITOUS;         /* XXX */
185    
186    if (err = task_threads (task, &threads, &nthreads))    /* Now we can write the various notes.  */
187      goto lose;    notestart = offset;
188    
189    /* Create a BFD section to describe each contiguous chunk    /* First a dull note containing the results of `uname', a la Solaris.  */
190       of the task's address space with the same stats.  */    {
191    sec = NULL;      DEFINE_NOTE (struct utsname) note;
192    addr = 0;      if (uname (&note.data) == 0) /* XXX Use proc_uname on task's proc port?  */
193    while (!vm_region (task, &addr, &size, &prot, &maxprot,        err = WRITE_NOTE (NT_UTSNAME, note);
194                       &inherit, &shared, &objname, &offset))    }
195      {    if (err || (corelimit >= 0 && corelimit <= offset))
196        mach_port_deallocate (mach_task_self (), objname);      return err;
197    
198        if (prot != VM_PROT_NONE)  #if 0
199          {    /* The pstatus_t note should contain the death info and some process-global
200            flagword flags = SEC_NO_FLAGS;       info we should get from the proc server, but no thread-specific info
201         like register state.  We need to define this type.  */
202      {
203        DEFINE_NOTE (pstatus_t) note;
204        note.data.pr_info.si_signo = signo;
205        note.data.pr_info.si_code = sigcode;
206        note.data.pr_info.si_errno = sigerror;
207        err = WRITE_NOTE (NT_PSTATUS, note);
208      }
209      if (err || (corelimit >= 0 && corelimit <= offset))
210        return err;
211    #endif
212    
213            if (!(prot & VM_PROT_WRITE))    /* Now examine all the threads in the task.
214              flags |= SEC_READONLY;       For each thread we produce one or more notes.  */
215            if (!(prot & VM_PROT_EXECUTE))    err = task_threads (task, &threads, &nthreads);
216              flags |= SEC_DATA;    if (err)
217        return err;
218            if (sec != NULL &&    for (i = 0; i < nthreads; ++i)
219                (vm_address_t) (bfd_section_vma (bfd, sec) +      {
220                                bfd_section_size (bfd, sec)) == addr &&        {
221                flags == (bfd_get_section_flags (bfd, sec) &          /* lwpinfo_t a la Solaris gives thread's CPU time and such.  */
222                          (SEC_READONLY|SEC_DATA)))          DEFINE_NOTE (struct thread_basic_info) note;
223              /* Coalesce with the previous section.  */          mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
224              bfd_set_section_size (bfd, sec,          err = thread_info (threads[i], THREAD_BASIC_INFO,
225                                    bfd_section_size (bfd, sec) + size);                             (thread_info_t)&note.data, &count);
226            else          if (err == 0)
227              {            err = WRITE_NOTE (NT_LWPSINFO, note);
228                /* Make a new section (which might grow by          else                    /* Just skip it if we can't get the info.  */
229                   the next region being coalesced onto it). */            err = 0;
230                char *name = bfd_intuit_section_name (addr, size, &flags);        }
231                if (name == NULL)        if (err || (corelimit >= 0 && corelimit <= offset))
232                  {          break;
233                    /* No guess from BFD.  */  
234                    if (asprintf (&name, "[%p,%p) %c%c%c",  #ifdef WRITE_THREAD_NOTES
235                                  (void *) addr, (void *) (addr + size),        /* XXX Here would go the note flavors for machine thread states.  */
236                                  (prot & VM_PROT_READ) ? 'r' : '-',        err = WRITE_THREAD_NOTES (i, threads[i]);
237                                  (prot & VM_PROT_WRITE) ? 'w' : '-',  #endif
238                                  (prot & VM_PROT_EXECUTE) ? 'x' : '-') == -1)        if (err || (corelimit >= 0 && corelimit <= offset))
239                      goto lose;          break;
240                  }        mach_port_deallocate (mach_task_self (), threads[i]);
               sec = bfd_make_section (name);  
               bfd_set_section_flags (bfd, sec, flags);  
               bfd_set_section_vma (bfd, sec, addr);  
               bfd_set_section_size (bfd, sec, size);  
             }  
         }  
241      }      }
242      while (i < nthreads)
243        mach_port_deallocate (mach_task_self (), threads[i++]);
244      munmap (threads, nthreads * sizeof *threads);
245      if (err || (corelimit >= 0 && corelimit <= offset))
246        return err;
247    
248      /* Make an array of program headers and fill them in.
249         The first one describes the note segment.  */
250      ph = phdrs = alloca ((nregions + 1) * sizeof *phdrs);
251    
252    /* Write all the sections' data.  */    memset (ph, 0, sizeof *ph);
253    for (sec = bfd->sections; sec != NULL; sec = sec->next)    ph->p_type = PT_NOTE;
254      ph->p_offset = notestart;
255      ph->p_filesz = offset - notestart;
256      ++ph;
257    
258      /* Now make ELF program headers for each of the record memory regions.
259         Consistent with the Linux kernel, we create PT_LOAD headers with
260         p_filesz = 0 for the read-only segments that we are not dumping
261         into the file.  */
262      for (r = regions; r != NULL; r = r->next)
263      {      {
264        void *data;        memset (ph, 0, sizeof *ph);
265        err = vm_read (task, bfd_section_vma (bfd, sec),        ph->p_type = PT_LOAD;
266                       bfd_section_size (bfd, sec), &data);        ph->p_align = vm_page_size;
267        if (err)        ph->p_flags = (((r->protection & VM_PROT_READ) ? PF_R : 0)
268          /* XXX What to do?                       | ((r->protection & VM_PROT_WRITE) ? PF_W : 0)
269            1. lose                       | ((r->protection & VM_PROT_EXECUTE) ? PF_X : 0));
270            2. remove this section        ph->p_vaddr = r->start;
271            3. mark this section as having ungettable contents (how?)        ph->p_memsz = r->length;
272              */        ph->p_filesz = (r->protection & VM_PROT_WRITE) ? ph->p_memsz : 0;
273          goto lose;        ph->p_offset = offset;
274        err = bfd_set_section_contents (bfd, sec, data, 0,        offset += ph->p_filesz;
275                                        bfd_section_size (bfd, sec));        ++ph;
       munmap ((caddr_t) data, bfd_section_size (bfd, sec));  
       if (err)  
         goto bfdlose;  
276      }      }
277    
278      /* Now write the memory segment data.  */
279      for (ph = phdrs; ph < &phdrs[nregions]; ++ph)
280        if (ph->p_filesz > 0)
281          {
282            vm_address_t va = ph->p_vaddr;
283            vm_size_t sz = ph->p_memsz;
284            off_t ofs = ph->p_offset;
285            int wrote_any = 0;
286            do
287              {
288                pointer_t copied;
289                int copy_count;
290                err = vm_read (task, va, sz, &copied, &copy_count);
291                if (err == 0)
292                  {
293                    char *data = (void *) copied;
294                    size_t left = copy_count, wrote;
295    
296                    va += copy_count;
297                    sz -= copy_count;
298    
299                    do
300                      {
301                        if (corelimit >= 0 && ofs + left > corelimit)
302                          left = corelimit - ofs;
303                        err = io_write (file, data, left, ofs, &wrote);
304                        if (err)
305                          break;
306                        ofs += wrote;
307                        data += wrote;
308                        left -= wrote;
309                        if (ofs >= corelimit)
310                          break;
311                      } while (left > 0);
312    
313                    munmap ((void *) copied, copy_count);
314    
315                    if (left < copy_count)
316                      wrote_any = 1;
317                  }
318                else
319                  {
320                    /* Leave a hole in the file for pages we can't read.  */
321                    va += vm_page_size;
322                    sz -= vm_page_size;
323                    ofs += vm_page_size;
324                  }
325              } while (sz > 0 && (corelimit < 0 || ofs < corelimit));
326    
327            if (! wrote_any)
328              /* If we failed to write any contents at all,
329                 don't claim the big hole as the contents.  */
330              ph->p_filesz = 0;
331          }
332    
333      /* Finally, we go back and write the program headers.  */
334      err = io_write (file, (char *) phdrs, (nregions + 1) * sizeof phdrs[0],
335                      sizeof hdr, &wrote);
336    
337      return err;
338    }

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26