2003-08-11 Michael Snyder <msnyder@redhat.com>
[platform/upstream/binutils.git] / gdb / i386-interix-nat.c
1 /* Native-dependent code for Interix running on i386's, for GDB.
2    Copyright 2002 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "defs.h"
21
22 #include <sys/procfs.h>
23 #include <inferior.h>
24 #include <fcntl.h>
25
26 #include <i386-tdep.h>
27 #include "gdb_string.h"
28 #include "gdbcore.h"
29 #include "gregset.h"
30 #include "regcache.h"
31
32 typedef unsigned long greg_t;
33
34 /* This is a duplicate of the table in i386-linux-nat.c.  */
35
36 static int regmap[] = {
37   EAX, ECX, EDX, EBX,
38   UESP, EBP, ESI, EDI,
39   EIP, EFL, CS, SS,
40   DS, ES, FS, GS,
41 };
42
43 /* Forward declarations.  */
44 extern void _initialize_core_interix (void);
45 extern initialize_file_ftype _initialize_core_interix;
46
47 /*  Given a pointer to a general register set in /proc format (gregset_t *),
48     unpack the register contents and supply them as gdb's idea of the current
49     register values.  */
50
51 void
52 supply_gregset (gregset_t *gregsetp)
53 {
54   int regi;
55   greg_t *regp = (greg_t *) & gregsetp->gregs;
56
57   for (regi = 0; regi < I386_NUM_GREGS; regi++)
58     {
59       supply_register (regi, (char *) (regp + regmap[regi]));
60     }
61 }
62
63 /* Store GDB's value for REGNO in *GREGSETP.  If REGNO is -1, do all
64    of them.  */
65
66 void
67 fill_gregset (gregset_t *gregsetp, int regno)
68 {
69   int regi;
70   greg_t *regp = (greg_t *) gregsetp->gregs;
71
72   for (regi = 0; regi < I386_NUM_GREGS; regi++)
73     if (regno == -1 || regi == regno)
74       regcache_collect (regi, (void *) (regp + regmap[regi]));
75 }
76
77 /* Fill GDB's register file with the floating-point register values in
78    *FPREGSETP.  */
79
80 void
81 supply_fpregset (fpregset_t *fpregsetp)
82 {
83   i387_supply_fsave ((char *) fpregsetp);
84 }
85
86 /* Given a pointer to a floating point register set in (fpregset_t *)
87    format, update all of the registers from gdb's idea of the current
88    floating point register set.  */
89
90 void
91 fill_fpregset (fpregset_t *fpregsetp, int regno)
92 {
93   i387_fill_fsave ((char *) fpregsetp, regno);
94 }
95
96 /* Read the values of either the general register set (WHICH equals 0)
97    or the floating point register set (WHICH equals 2) from the core
98    file data (pointed to by CORE_REG_SECT), and update gdb's idea of
99    their current values.  The CORE_REG_SIZE parameter is compared to
100    the size of the gregset or fpgregset structures (as appropriate) to
101    validate the size of the structure from the core file.  The
102    REG_ADDR parameter is ignored.  */
103
104 static void
105 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
106                       CORE_ADDR reg_addr)
107 {
108   gdb_gregset_t gregset;
109   gdb_fpregset_t fpregset;
110
111   if (which == 0)
112     {
113       if (core_reg_size != sizeof (gregset))
114         {
115           warning ("wrong size gregset struct in core file");
116         }
117       else
118         {
119           memcpy ((char *) &gregset, core_reg_sect, sizeof (gregset));
120           supply_gregset (&gregset);
121         }
122     }
123   else if (which == 2)
124     {
125       if (core_reg_size != sizeof (fpregset))
126         {
127           warning ("wrong size fpregset struct in core file");
128         }
129       else
130         {
131           memcpy ((char *) &fpregset, core_reg_sect, sizeof (fpregset));
132           supply_fpregset (&fpregset);
133         }
134     }
135 }
136
137 #include <setjmp.h>
138
139 static struct core_fns interix_core_fns =
140 {
141   bfd_target_coff_flavour,      /* core_flavour (more or less) */
142   default_check_format,         /* check_format */
143   default_core_sniffer,         /* core_sniffer */
144   fetch_core_registers,         /* core_read_registers */
145   NULL                          /* next */
146 };
147
148 void
149 _initialize_core_interix (void)
150 {
151   add_core_fns (&interix_core_fns);
152 }
153
154 /* We don't have a /proc/pid/file or /proc/pid/exe to read a link from,
155    so read it from the same place ps gets the name.  */
156
157 char *
158 child_pid_to_exec_file (int pid)
159 {
160   char *path;
161   char *buf;
162   int fd, c;
163   char *p;
164
165   xasprintf (&path, "/proc/%d/stat", pid);
166   buf = xcalloc (MAXPATHLEN + 1, sizeof (char));
167   make_cleanup (xfree, path);
168   make_cleanup (xfree, buf);
169
170   fd = open (path, O_RDONLY);
171
172   if (fd < 0)
173     return NULL;
174
175   /* Skip over "Argv0\t".  */
176   lseek (fd, 6, SEEK_SET);
177
178   c = read (fd, buf, MAXPATHLEN);
179   close (fd);
180
181   if (c < 0)
182     return NULL;
183
184   buf[c] = '\0';                /* Ensure null termination.  */
185   p = strchr (buf, '\n');
186   if (p != NULL)
187     *p = '\0';
188
189   return buf;
190 }