1/* libthread_db helper functions for the remote server for GDB.
2   Copyright 2002
3   Free Software Foundation, Inc.
4
5   Contributed by MontaVista Software.
6
7   This file is part of GDB.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place - Suite 330,
22   Boston, MA 02111-1307, USA.  */
23
24#include "server.h"
25
26/* This file is currently tied to GNU/Linux.  It should scale well to
27   another libthread_db implementation, with the approriate gdbserver
28   hooks, but for now this means we can use GNU/Linux's target data.  */
29
30#include "linux-low.h"
31
32/* Correct for all GNU/Linux targets (for quite some time).  */
33#define GDB_GREGSET_T elf_gregset_t
34#define GDB_FPREGSET_T elf_fpregset_t
35
36#ifndef HAVE_ELF_FPREGSET_T
37/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
38   via <sys/procfs.h>.  */
39#ifdef HAVE_LINUX_ELF_H
40#include <linux/elf.h>
41#endif
42#endif
43
44#include "../gdb_proc_service.h"
45
46typedef struct ps_prochandle *gdb_ps_prochandle_t;
47typedef void *gdb_ps_read_buf_t;
48typedef const void *gdb_ps_write_buf_t;
49typedef size_t gdb_ps_size_t;
50
51/* FIXME redo this right */
52#if 0
53#ifndef HAVE_LINUX_REGSETS
54#error HAVE_LINUX_REGSETS required!
55#else
56static struct regset_info *
57gregset_info(void)
58{
59  int i = 0;
60
61  while (target_regsets[i].size != -1)
62    {
63      if (target_regsets[i].type == GENERAL_REGS)
64	break;
65      i++;
66    }
67
68  return &target_regsets[i];
69}
70
71static struct regset_info *
72fpregset_info(void)
73{
74  int i = 0;
75
76  while (target_regsets[i].size != -1)
77    {
78      if (target_regsets[i].type == FP_REGS)
79	break;
80      i++;
81    }
82
83  return &target_regsets[i];
84}
85#endif
86#endif
87
88/* Search for the symbol named NAME within the object named OBJ within
89   the target process PH.  If the symbol is found the address of the
90   symbol is stored in SYM_ADDR.  */
91
92ps_err_e
93ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
94		   const char *name, paddr_t *sym_addr)
95{
96  CORE_ADDR addr;
97
98  if (look_up_one_symbol (name, &addr) == 0)
99    return PS_NOSYM;
100
101  *sym_addr = (paddr_t) (unsigned long) addr;
102  return PS_OK;
103}
104
105/* Read SIZE bytes from the target process PH at address ADDR and copy
106   them into BUF.  */
107
108ps_err_e
109ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
110	   gdb_ps_read_buf_t buf, gdb_ps_size_t size)
111{
112  read_inferior_memory (addr, buf, size);
113  return PS_OK;
114}
115
116/* Write SIZE bytes from BUF into the target process PH at address ADDR.  */
117
118ps_err_e
119ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
120	    gdb_ps_write_buf_t buf, gdb_ps_size_t size)
121{
122  return write_inferior_memory (addr, buf, size);
123}
124
125/* Get the general registers of LWP LWPID within the target process PH
126   and store them in GREGSET.  */
127
128ps_err_e
129ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
130{
131#if 0
132  struct thread_info *reg_inferior, *save_inferior;
133  void *regcache;
134
135  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
136							  lwpid);
137  if (reg_inferior == NULL)
138    return PS_ERR;
139
140  save_inferior = current_inferior;
141  current_inferior = reg_inferior;
142
143  regcache = new_register_cache ();
144  the_target->fetch_registers (0, regcache);
145  gregset_info()->fill_function (gregset, regcache);
146  free_register_cache (regcache);
147
148  current_inferior = save_inferior;
149  return PS_OK;
150#endif
151  /* FIXME */
152  return PS_ERR;
153}
154
155/* Set the general registers of LWP LWPID within the target process PH
156   from GREGSET.  */
157
158ps_err_e
159ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
160{
161#if 0
162  struct thread_info *reg_inferior, *save_inferior;
163  void *regcache;
164
165  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
166  if (reg_inferior == NULL)
167    return PS_ERR;
168
169  save_inferior = current_inferior;
170  current_inferior = reg_inferior;
171
172  regcache = new_register_cache ();
173  gregset_info()->store_function (gregset, regcache);
174  the_target->store_registers (0, regcache);
175  free_register_cache (regcache);
176
177  current_inferior = save_inferior;
178
179  return PS_OK;
180#endif
181  /* FIXME */
182  return PS_ERR;
183}
184
185/* Get the floating-point registers of LWP LWPID within the target
186   process PH and store them in FPREGSET.  */
187
188ps_err_e
189ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
190	       gdb_prfpregset_t *fpregset)
191{
192#if 0
193  struct thread_info *reg_inferior, *save_inferior;
194  void *regcache;
195
196  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
197  if (reg_inferior == NULL)
198    return PS_ERR;
199
200  save_inferior = current_inferior;
201  current_inferior = reg_inferior;
202
203  regcache = new_register_cache ();
204  the_target->fetch_registers (0, regcache);
205  fpregset_info()->fill_function (fpregset, regcache);
206  free_register_cache (regcache);
207
208  current_inferior = save_inferior;
209
210  return PS_OK;
211#endif
212  /* FIXME */
213  return PS_ERR;
214}
215
216/* Set the floating-point registers of LWP LWPID within the target
217   process PH from FPREGSET.  */
218
219ps_err_e
220ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
221	       const gdb_prfpregset_t *fpregset)
222{
223#if 0
224  struct thread_info *reg_inferior, *save_inferior;
225  void *regcache;
226
227  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
228  if (reg_inferior == NULL)
229    return PS_ERR;
230
231  save_inferior = current_inferior;
232  current_inferior = reg_inferior;
233
234  regcache = new_register_cache ();
235  fpregset_info()->store_function (fpregset, regcache);
236  the_target->store_registers (0, regcache);
237  free_register_cache (regcache);
238
239  current_inferior = save_inferior;
240
241  return PS_OK;
242#endif
243  /* FIXME */
244  return PS_ERR;
245}
246
247/* Return overall process id of the target PH.  Special for GNU/Linux
248   -- not used on Solaris.  */
249
250pid_t
251ps_getpid (gdb_ps_prochandle_t ph)
252{
253  return ph->pid;
254}
255
256
257