/[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.6 by roland, Mon Mar 11 01:18:30 2002 UTC revision 1.7 by roland, Mon Mar 11 08:52:04 2002 UTC
# Line 1  Line 1 
1    /* Write ELF core dump files for GNU Hurd.
2       Copyright (C) 2002 Free Software Foundation, Inc.
3       Written by Roland McGrath.
4    
5    This file is part of the GNU Hurd.
6    
7    The GNU Hurd is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11    
12    The GNU Hurd is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with the GNU Hurd; see the file COPYING.  If not, write to
19    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
20    
21  #include <hurd.h>  #include <hurd.h>
22  #include <elf.h>  #include <elf.h>
23  #include <link.h>  #include <link.h>
# Line 8  Line 28 
28  #include <sys/procfs.h>  #include <sys/procfs.h>
29  #include <stddef.h>  #include <stddef.h>
30    
   
 #define ELF_MACHINE     EM_386  /* XXX */  
   
31  #define ELF_CLASS       PASTE (ELFCLASS, __ELF_NATIVE_CLASS)  #define ELF_CLASS       PASTE (ELFCLASS, __ELF_NATIVE_CLASS)
32  #define PASTE(a, b)     PASTE_1 (a, b)  #define PASTE(a, b)     PASTE_1 (a, b)
33  #define PASTE_1(a, b)   a##b  #define PASTE_1(a, b)   a##b
# Line 22  Line 39 
39  #define ELF_DATA ELFDATA2LSB  #define ELF_DATA ELFDATA2LSB
40  #endif  #endif
41    
42    #include <mach/thread_status.h>
43    #include <assert.h>
44    
45    #ifdef i386_THREAD_STATE
46    # define ELF_MACHINE            EM_386
47    
48    /* There is a natural layout for this on x86, so it happens
49       that the canonical gregset_t from <sys/ucontext.h>
50       matches Mach's i386_thread_state exactly.  */
51    static inline void
52    fetch_thread_regset (thread_t thread, prgregset_t *gregs)
53    {
54      mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
55      assert (sizeof (struct i386_thread_state) == sizeof (prgregset_t));
56      assert (offsetof (struct i386_thread_state, gs) == REG_GS);
57      assert (offsetof (struct i386_thread_state, eip) == REG_EIP * 4);
58      assert (offsetof (struct i386_thread_state, ss) == REG_SS * 4);
59      (void) thread_get_state (thread, i386_THREAD_STATE,
60                               (thread_state_t) gregs, &count);
61    }
62    
63    static inline void
64    fetch_thread_fpregset (thread_t thread, prfpregset_t *fpregs)
65    {
66      struct i386_float_state st;
67      mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
68      error_t err = thread_get_state (thread, i386_FLOAT_STATE,
69                                      (thread_state_t) &st, &count);
70      if (err == 0 && st.initialized)
71        {
72          assert (sizeof *fpregs >= sizeof st.hw_state);
73          memcpy (fpregs, st.hw_state, sizeof st.hw_state);
74        }
75    }
76    
77    #else
78    # warning "do not understand this machine flavor, no registers in dumps"
79    # define ELF_MACHINE            EM_NONE
80    #endif
81    
82    
83  #define TIME_VALUE_TO_TIMESPEC(tv, ts) \  #define TIME_VALUE_TO_TIMESPEC(tv, ts) \
84    TIMEVAL_TO_TIMESPEC ((struct timeval *) (tv), (ts))    TIMEVAL_TO_TIMESPEC ((struct timeval *) (tv), (ts))
# Line 29  Line 86 
86  #define PAGES_TO_KB(x)  ((x) * (vm_page_size / 1024))  #define PAGES_TO_KB(x)  ((x) * (vm_page_size / 1024))
87  #define ENCODE_PCT(f)   ((uint16_t) ((f) * 32768.0))  #define ENCODE_PCT(f)   ((uint16_t) ((f) * 32768.0))
88    
89  extern process_t procserver;  extern process_t procserver;    /* crash.c */
90    
91  error_t  error_t
92  dump_core (task_t task, file_t file, off_t corelimit,  dump_core (task_t task, file_t file, off_t corelimit,
# Line 227  dump_core (task_t task, file_t file, off Line 284  dump_core (task_t task, file_t file, off
284    /* The psinfo_t note contains some process-global info we should get from    /* The psinfo_t note contains some process-global info we should get from
285       the proc server, but no thread-specific info like register state.  */       the proc server, but no thread-specific info like register state.  */
286    {    {
287      DEFINE_NOTE (psinfo_t) note;      DEFINE_NOTE (psinfo_t) psinfo;
288        DEFINE_NOTE (pstatus_t) pstatus;
289      int flags = PI_FETCH_TASKINFO | PI_FETCH_THREADS | PI_FETCH_THREAD_BASIC;      int flags = PI_FETCH_TASKINFO | PI_FETCH_THREADS | PI_FETCH_THREAD_BASIC;
290      char *waits = 0;      char *waits = 0;
291      mach_msg_type_number_t num_waits = 0;      mach_msg_type_number_t num_waits = 0;
292      char pibuf[offsetof (struct procinfo, threadinfos[2])];      char pibuf[offsetof (struct procinfo, threadinfos[2])];
293      struct procinfo *pi = (void *) &pibuf;      struct procinfo *pi = (void *) &pibuf;
294      mach_msg_type_number_t pi_size = sizeof pibuf;      mach_msg_type_number_t pi_size = sizeof pibuf;
295    
296        memset (&pstatus.data, 0, sizeof pstatus.data);
297        memset (&psinfo.data, 0, sizeof psinfo.data);
298        pstatus.data.pr_pid = psinfo.data.pr_pid = pid;
299    
300      err = proc_getprocinfo (procserver, pid, &flags,      err = proc_getprocinfo (procserver, pid, &flags,
301                              (procinfo_t *) &pi, &pi_size,                              (procinfo_t *) &pi, &pi_size,
302                              &waits, &num_waits);                              &waits, &num_waits);
# Line 241  dump_core (task_t task, file_t file, off Line 304  dump_core (task_t task, file_t file, off
304        {        {
305          if (num_waits != 0)          if (num_waits != 0)
306            munmap (waits, num_waits);            munmap (waits, num_waits);
307          memset (&note.data, 0, sizeof note.data);  
308          note.data.pr_flag = pi->state;          pstatus.data.pr_flags = psinfo.data.pr_flag = pi->state;
309          note.data.pr_nlwp = pi->nthreads;          pstatus.data.pr_nlwp = psinfo.data.pr_nlwp = pi->nthreads;
310          note.data.pr_pid = pid;          pstatus.data.pr_ppid = psinfo.data.pr_ppid = pi->ppid;
311          note.data.pr_ppid = pi->ppid;          pstatus.data.pr_pgid = psinfo.data.pr_pgid = pi->pgrp;
312          note.data.pr_pgid = pi->pgrp;          pstatus.data.pr_sid = psinfo.data.pr_sid = pi->session;
313          note.data.pr_sid = pi->session;  
314          note.data.pr_euid = pi->owner;          psinfo.data.pr_euid = pi->owner;
315          /* XXX struct procinfo should have these */          /* XXX struct procinfo should have these */
316          note.data.pr_egid = note.data.pr_gid = note.data.pr_uid = -1;          psinfo.data.pr_egid = psinfo.data.pr_gid = psinfo.data.pr_uid = -1;
317          note.data.pr_size = PAGES_TO_KB (pi->taskinfo.virtual_size);  
318          note.data.pr_rssize = PAGES_TO_KB (pi->taskinfo.resident_size);          psinfo.data.pr_size = PAGES_TO_KB (pi->taskinfo.virtual_size);
319            psinfo.data.pr_rssize = PAGES_TO_KB (pi->taskinfo.resident_size);
320    
321          {          {
322            /* Sum all the threads' cpu_usage fields.  */            /* Sum all the threads' cpu_usage fields.  */
323            integer_t cpu_usage = 0;            integer_t cpu_usage = 0;
324            for (i = 0; i < pi->nthreads; ++i)            for (i = 0; i < pi->nthreads; ++i)
325              cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;              cpu_usage += pi->threadinfos[i].pis_bi.cpu_usage;
326            note.data.pr_pctcpu = ENCODE_PCT ((float) cpu_usage            psinfo.data.pr_pctcpu = ENCODE_PCT ((float) cpu_usage
327                                              / (float) TH_USAGE_SCALE);                                                / (float) TH_USAGE_SCALE);
328          }          }
329          if (host_memory_size > 0.0)          if (host_memory_size > 0.0)
330            note.data.pr_pctmem = ENCODE_PCT ((float) pi->taskinfo.resident_size            psinfo.data.pr_pctmem
331                                              / host_memory_size);              = ENCODE_PCT
332                ((float) pi->taskinfo.resident_size / host_memory_size);
333    
334          TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.creation_time,          TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.creation_time,
335                                  &note.data.pr_start);                                  &psinfo.data.pr_start);
336    
337            TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time,
338                                    &pstatus.data.pr_utime);
339            TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.system_time,
340                                    &pstatus.data.pr_stime);
341            /* Sum the user and system time for pr_time.  */
342          timeradd ((const struct timeval *) &pi->taskinfo.user_time,          timeradd ((const struct timeval *) &pi->taskinfo.user_time,
343                    (const struct timeval *) &pi->taskinfo.system_time,                    (const struct timeval *) &pi->taskinfo.system_time,
344                    (struct timeval *) &pi->taskinfo.user_time);                    (struct timeval *) &pi->taskinfo.user_time);
345          TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, &note.data.pr_time);          TIME_VALUE_TO_TIMESPEC (&pi->taskinfo.user_time, &psinfo.data.pr_time);
346          /* XXX struct procinfo should have dead child info for pr_ctime */          /* XXX struct procinfo should have dead child info for pr_c[us]?time */
347          note.data.pr_wstat = pi->exitstatus;  
348            psinfo.data.pr_wstat = pi->exitstatus;
349    
350          if ((void *) pi != &pibuf)          if ((void *) pi != &pibuf)
351            munmap (pi, pi_size);            munmap (pi, pi_size);
352          }
353          {      if (err == 0)
354            /* We have to nab the process's own proc port to get the        {
355               proc server to tell us its registered arg locations.  */          /* We have to nab the process's own proc port to get the
356            process_t proc;             proc server to tell us its registered arg locations.  */
357            err = proc_task2proc (procserver, task, &proc);          process_t proc;
358            if (err == 0)          err = proc_task2proc (procserver, task, &proc);
359              {          if (err == 0)
360                err = proc_get_arg_locations (proc,            {
361                                              &note.data.pr_argv,              err = proc_get_arg_locations (proc,
362                                              &note.data.pr_envp);                                            &psinfo.data.pr_argv,
363                mach_port_deallocate (mach_task_self (), proc);                                            &psinfo.data.pr_envp);
364              }              mach_port_deallocate (mach_task_self (), proc);
365            err = 0;            }
         }  
366          {          {
367            /* Now fetch the arguments.  We could do this directly from the            /* Now fetch the arguments.  We could do this directly from the
368               task given the locations we now have.  But we are lazy and have               task given the locations we now have.  But we are lazy and have
369               the proc server do it for us.  */               the proc server do it for us.  */
370            char *data = note.data.pr_psargs;            char *data = psinfo.data.pr_psargs;
371            size_t datalen = sizeof note.data.pr_psargs;            size_t datalen = sizeof psinfo.data.pr_psargs;
372            err = proc_getprocargs (procserver, pid, &data, &datalen);            err = proc_getprocargs (procserver, pid, &data, &datalen);
373            if (err == 0)            if (err == 0)
374              {              {
375                note.data.pr_argc = argz_count (data, datalen);                psinfo.data.pr_argc = argz_count (data, datalen);
376                argz_stringify (data, datalen, ' ');                argz_stringify (data, datalen, ' ');
377                if (data != note.data.pr_psargs)                if (data != psinfo.data.pr_psargs)
378                  {                  {
379                    memcpy (note.data.pr_psargs, data,                    memcpy (psinfo.data.pr_psargs, data,
380                            sizeof note.data.pr_psargs);                            sizeof psinfo.data.pr_psargs);
381                    munmap (data, datalen);                    munmap (data, datalen);
382                  }                  }
383              }              }
384          }          }
385          err = WRITE_NOTE (NT_PSTATUS, note);          err = WRITE_NOTE (NT_PSINFO, psinfo);
386        }        }
387    
388  #if 0      err = WRITE_NOTE (NT_PSTATUS, pstatus) ?: err;
     note.data.pr_info.si_signo = signo;  
     note.data.pr_info.si_code = sigcode;  
     note.data.pr_info.si_errno = sigerror;  
 #endif  
389    }    }
390    if (err || (corelimit >= 0 && corelimit <= offset))    if (err || (corelimit >= 0 && corelimit <= offset))
391      return err;      return err;
# Line 328  dump_core (task_t task, file_t file, off Line 397  dump_core (task_t task, file_t file, off
397      return err;      return err;
398    for (i = 0; i < nthreads; ++i)    for (i = 0; i < nthreads; ++i)
399      {      {
400        {        DEFINE_NOTE (lwpstatus_t) note;
401          /* lwpinfo_t a la Solaris gives thread's CPU time and such.  */        memset (&note.data, 0, sizeof note.data);
402          DEFINE_NOTE (struct thread_basic_info) note;        note.data.pr_lwpid = i;
403          mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;  
404          err = thread_info (threads[i], THREAD_BASIC_INFO,        /* We have to write the death signal into every thread's record, even
405                             (thread_info_t)&note.data, &count);           though only one thread really took the signal.  This is both because
406          if (err == 0)           we don't know which thread it was, and because GDB blindly uses the
407            err = WRITE_NOTE (NT_LWPSINFO, note);           value from each record to clobber the last (even if it's zero).  */
408          else                    /* Just skip it if we can't get the info.  */        note.data.pr_cursig = signo;
409            err = 0;        note.data.pr_info.si_signo = signo;
410        }        note.data.pr_info.si_code = sigcode;
411        if (err || (corelimit >= 0 && corelimit <= offset))        note.data.pr_info.si_errno = sigerror;
         break;  
412    
413  #ifdef WRITE_THREAD_NOTES        fetch_thread_regset (threads[i], &note.data.pr_reg);
414        /* XXX Here would go the note flavors for machine thread states.  */        fetch_thread_fpregset (threads[i], &note.data.pr_fpreg);
415        err = WRITE_THREAD_NOTES (i, threads[i]);  
416  #endif        err = WRITE_NOTE (NT_LWPSTATUS, note);
417        if (err || (corelimit >= 0 && corelimit <= offset))        if (err || (corelimit >= 0 && corelimit <= offset))
418          break;          break;
419    
420        mach_port_deallocate (mach_task_self (), threads[i]);        mach_port_deallocate (mach_task_self (), threads[i]);
421      }      }
422      /* If we broke out of the loop early, deallocate remaining thread ports.  */
423    while (i < nthreads)    while (i < nthreads)
424      mach_port_deallocate (mach_task_self (), threads[i++]);      mach_port_deallocate (mach_task_self (), threads[i++]);
425    munmap (threads, nthreads * sizeof *threads);    munmap (threads, nthreads * sizeof *threads);

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7

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