1/* GNU/Linux/x86 specific low level interface, for the in-process
2   agent library for GDB.
3
4   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
5
6   This file is part of GDB.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21#include "server.h"
22
23/* GDB register numbers.  */
24
25enum i386_gdb_regnum
26{
27  I386_EAX_REGNUM,		/* %eax */
28  I386_ECX_REGNUM,		/* %ecx */
29  I386_EDX_REGNUM,		/* %edx */
30  I386_EBX_REGNUM,		/* %ebx */
31  I386_ESP_REGNUM,		/* %esp */
32  I386_EBP_REGNUM,		/* %ebp */
33  I386_ESI_REGNUM,		/* %esi */
34  I386_EDI_REGNUM,		/* %edi */
35  I386_EIP_REGNUM,		/* %eip */
36  I386_EFLAGS_REGNUM,		/* %eflags */
37  I386_CS_REGNUM,		/* %cs */
38  I386_SS_REGNUM,		/* %ss */
39  I386_DS_REGNUM,		/* %ds */
40  I386_ES_REGNUM,		/* %es */
41  I386_FS_REGNUM,		/* %fs */
42  I386_GS_REGNUM,		/* %gs */
43  I386_ST0_REGNUM		/* %st(0) */
44};
45
46#define i386_num_regs 16
47
48/* Defined in auto-generated file i386-linux.c.  */
49void init_registers_i386_linux (void);
50
51#define FT_CR_EAX 15
52#define FT_CR_ECX 14
53#define FT_CR_EDX 13
54#define FT_CR_EBX 12
55#define FT_CR_UESP 11
56#define FT_CR_EBP 10
57#define FT_CR_ESI 9
58#define FT_CR_EDI 8
59#define FT_CR_EIP 7
60#define FT_CR_EFL 6
61#define FT_CR_DS 5
62#define FT_CR_ES 4
63#define FT_CR_FS 3
64#define FT_CR_GS 2
65#define FT_CR_SS 1
66#define FT_CR_CS 0
67
68/* Mapping between the general-purpose registers in jump tracepoint
69   format and GDB's register array layout.  */
70
71static const int i386_ft_collect_regmap[] =
72{
73  FT_CR_EAX * 4, FT_CR_ECX * 4, FT_CR_EDX * 4, FT_CR_EBX * 4,
74  FT_CR_UESP * 4, FT_CR_EBP * 4, FT_CR_ESI * 4, FT_CR_EDI * 4,
75  FT_CR_EIP * 4, FT_CR_EFL * 4, FT_CR_CS * 4, FT_CR_SS * 4,
76  FT_CR_DS * 4, FT_CR_ES * 4, FT_CR_FS * 4, FT_CR_GS * 4
77};
78
79void
80supply_fast_tracepoint_registers (struct regcache *regcache,
81				  const unsigned char *buf)
82{
83  int i;
84
85  for (i = 0; i < i386_num_regs; i++)
86    {
87      int regval;
88
89      if (i >= I386_CS_REGNUM && i <= I386_GS_REGNUM)
90	regval = *(short *) (((char *) buf) + i386_ft_collect_regmap[i]);
91      else
92	regval = *(int *) (((char *) buf) + i386_ft_collect_regmap[i]);
93
94      supply_register (regcache, i, &regval);
95    }
96}
97
98ULONGEST __attribute__ ((visibility("default"), used))
99gdb_agent_get_raw_reg (unsigned char *raw_regs, int regnum)
100{
101  /* This should maybe be allowed to return an error code, or perhaps
102     better, have the emit_reg detect this, and emit a constant zero,
103     or something.  */
104
105  if (regnum > i386_num_regs)
106    return 0;
107  else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM)
108    return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]);
109  else
110    return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]);
111}
112
113#ifdef HAVE_UST
114
115#include <ust/processor.h>
116
117/* "struct registers" is the UST object type holding the registers at
118   the time of the static tracepoint marker call.  This doesn't
119   contain EIP, but we know what it must have been (the marker
120   address).  */
121
122#define ST_REGENTRY(REG)			\
123  {						\
124    offsetof (struct registers, REG),		\
125    sizeof (((struct registers *) NULL)->REG)	\
126  }
127
128static struct
129{
130  int offset;
131  int size;
132} i386_st_collect_regmap[] =
133  {
134    ST_REGENTRY(eax),
135    ST_REGENTRY(ecx),
136    ST_REGENTRY(edx),
137    ST_REGENTRY(ebx),
138    ST_REGENTRY(esp),
139    ST_REGENTRY(ebp),
140    ST_REGENTRY(esi),
141    ST_REGENTRY(edi),
142    { -1, 0 }, /* eip */
143    ST_REGENTRY(eflags),
144    ST_REGENTRY(cs),
145    ST_REGENTRY(ss),
146  };
147
148#define i386_NUM_ST_COLLECT_GREGS \
149  (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0]))
150
151void
152supply_static_tracepoint_registers (struct regcache *regcache,
153				    const unsigned char *buf,
154				    CORE_ADDR pc)
155{
156  int i;
157  unsigned int newpc = pc;
158
159  supply_register (regcache, I386_EIP_REGNUM, &newpc);
160
161  for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++)
162    if (i386_st_collect_regmap[i].offset != -1)
163      {
164	switch (i386_st_collect_regmap[i].size)
165	  {
166	  case 4:
167	    supply_register (regcache, i,
168			     ((char *) buf)
169			     + i386_st_collect_regmap[i].offset);
170	    break;
171	  case 2:
172	    {
173	      unsigned long reg
174		= * (short *) (((char *) buf)
175			       + i386_st_collect_regmap[i].offset);
176	      reg &= 0xffff;
177	      supply_register (regcache, i, &reg);
178	    }
179	    break;
180	  default:
181	    internal_error (__FILE__, __LINE__, "unhandled register size: %d",
182			    i386_st_collect_regmap[i].size);
183	  }
184      }
185}
186
187#endif /* HAVE_UST */
188
189
190/* This is only needed because reg-i386-linux-lib.o references it.  We
191   may use it proper at some point.  */
192const char *gdbserver_xmltarget;
193
194void
195initialize_low_tracepoint (void)
196{
197  init_registers_i386_linux ();
198}
199