1/* Native-dependent code for AMD64.
2
3   Copyright 2003, 2004 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program 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 of the License, or
10   (at your option) any later version.
11
12   This program 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 this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.  */
21
22#include "defs.h"
23#include "gdbarch.h"
24#include "regcache.h"
25
26#include "gdb_assert.h"
27#include "gdb_string.h"
28
29#include "i386-tdep.h"
30#include "amd64-tdep.h"
31
32/* The following bits of code help with implementing debugging 32-bit
33   code natively on AMD64.  The idea is to define two mappings between
34   the register number as used by GDB and the register set used by the
35   host to represent the general-purpose registers; one for 32-bit
36   code and one for 64-bit code.  The mappings are specified by the
37   follwing variables and consist of an array of offsets within the
38   register set indexed by register number, and the number of
39   registers supported by the mapping.  We don't need mappings for the
40   floating-point and SSE registers, since the difference between
41   64-bit and 32-bit variants are negligable.  The difference in the
42   number of SSE registers is already handled by the target code.  */
43
44/* General-purpose register mapping for native 32-bit code.  */
45int *amd64_native_gregset32_reg_offset;
46int amd64_native_gregset32_num_regs = I386_NUM_GREGS;
47
48/* General-purpose register mapping for native 64-bit code.  */
49int *amd64_native_gregset64_reg_offset;
50int amd64_native_gregset64_num_regs = AMD64_NUM_GREGS;
51
52/* Return the offset of REGNUM within the appropriate native
53   general-purpose register set.  */
54
55static int
56amd64_native_gregset_reg_offset (int regnum)
57{
58  int *reg_offset = amd64_native_gregset64_reg_offset;
59  int num_regs = amd64_native_gregset64_num_regs;
60
61  gdb_assert (regnum >= 0);
62
63  if (gdbarch_ptr_bit (current_gdbarch) == 32)
64    {
65      reg_offset = amd64_native_gregset32_reg_offset;
66      num_regs = amd64_native_gregset32_num_regs;
67    }
68
69  if (num_regs > NUM_REGS)
70    num_regs = NUM_REGS;
71
72  if (regnum < num_regs && regnum < NUM_REGS)
73    return reg_offset[regnum];
74
75  return -1;
76}
77
78/* Return whether the native general-purpose register set supplies
79   register REGNUM.  */
80
81int
82amd64_native_gregset_supplies_p (int regnum)
83{
84  return (amd64_native_gregset_reg_offset (regnum) != -1);
85}
86
87
88/* Supply register REGNUM, whose contents are store in BUF, to
89   REGCACHE.  If REGNUM is -1, supply all appropriate registers.  */
90
91void
92amd64_supply_native_gregset (struct regcache *regcache,
93			     const void *gregs, int regnum)
94{
95  const char *regs = gregs;
96  struct gdbarch *gdbarch = get_regcache_arch (regcache);
97  int num_regs = amd64_native_gregset64_num_regs;
98  int i;
99
100  if (gdbarch_ptr_bit (gdbarch) == 32)
101    num_regs = amd64_native_gregset32_num_regs;
102
103  if (num_regs > NUM_REGS)
104    num_regs = NUM_REGS;
105
106  for (i = 0; i < num_regs; i++)
107    {
108      if (regnum == -1 || regnum == i)
109	{
110	  int offset = amd64_native_gregset_reg_offset (i);
111
112	  if (offset != -1)
113	    regcache_raw_supply (regcache, i, regs + offset);
114	}
115    }
116}
117
118/* Collect register REGNUM from REGCACHE and store its contents in
119   GREGS.  If REGNUM is -1, collect and store all appropriate
120   registers.  */
121
122void
123amd64_collect_native_gregset (const struct regcache *regcache,
124			      void *gregs, int regnum)
125{
126  char *regs = gregs;
127  struct gdbarch *gdbarch = get_regcache_arch (regcache);
128  int num_regs = amd64_native_gregset64_num_regs;
129  int i;
130
131  if (gdbarch_ptr_bit (gdbarch) == 32)
132    {
133      num_regs = amd64_native_gregset32_num_regs;
134
135      /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and
136         %eip get zero-extended to 64 bits.  */
137      for (i = 0; i <= I386_EIP_REGNUM; i++)
138	{
139	  if (regnum == -1 || regnum == i)
140	    memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
141	}
142      /* Ditto for %cs, %ss, %ds, %es, %fs, and %gs.  */
143      for (i = I386_CS_REGNUM; i <= I386_GS_REGNUM; i++)
144	{
145	  if (regnum == -1 || regnum == i)
146	    memset (regs + amd64_native_gregset_reg_offset (i), 0, 8);
147	}
148    }
149
150  if (num_regs > NUM_REGS)
151    num_regs = NUM_REGS;
152
153  for (i = 0; i < num_regs; i++)
154    {
155      if (regnum == -1 || regnum == i)
156	{
157	  int offset = amd64_native_gregset_reg_offset (i);
158
159	  if (offset != -1)
160	    regcache_raw_collect (regcache, i, regs + offset);
161	}
162    }
163}
164