1b2b3ffcdSSimon Schubert /*
2b2b3ffcdSSimon Schubert * Copyright (c) 2004 Marcel Moolenaar
3b2b3ffcdSSimon Schubert * All rights reserved.
4b2b3ffcdSSimon Schubert *
5b2b3ffcdSSimon Schubert * Redistribution and use in source and binary forms, with or without
6b2b3ffcdSSimon Schubert * modification, are permitted provided that the following conditions
7b2b3ffcdSSimon Schubert * are met:
8b2b3ffcdSSimon Schubert *
9b2b3ffcdSSimon Schubert * 1. Redistributions of source code must retain the above copyright
10b2b3ffcdSSimon Schubert * notice, this list of conditions and the following disclaimer.
11b2b3ffcdSSimon Schubert * 2. Redistributions in binary form must reproduce the above copyright
12b2b3ffcdSSimon Schubert * notice, this list of conditions and the following disclaimer in the
13b2b3ffcdSSimon Schubert * documentation and/or other materials provided with the distribution.
14b2b3ffcdSSimon Schubert *
15b2b3ffcdSSimon Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16b2b3ffcdSSimon Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17b2b3ffcdSSimon Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18b2b3ffcdSSimon Schubert * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19b2b3ffcdSSimon Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20b2b3ffcdSSimon Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21b2b3ffcdSSimon Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22b2b3ffcdSSimon Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23b2b3ffcdSSimon Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24b2b3ffcdSSimon Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25b2b3ffcdSSimon Schubert *
26b2b3ffcdSSimon Schubert * $FreeBSD: src/gnu/usr.bin/gdb/kgdb/trgt_amd64.c,v 1.10 2008/05/01 20:36:48 jhb Exp $
27b2b3ffcdSSimon Schubert */
28b2b3ffcdSSimon Schubert
29b2b3ffcdSSimon Schubert #include <sys/cdefs.h>
30b2b3ffcdSSimon Schubert
31b2b3ffcdSSimon Schubert #include <sys/types.h>
32b2b3ffcdSSimon Schubert #include <sys/thread.h>
33b2b3ffcdSSimon Schubert #include <machine/pcb.h>
34b2b3ffcdSSimon Schubert #include <machine/frame.h>
35b2b3ffcdSSimon Schubert #include <err.h>
36b2b3ffcdSSimon Schubert #include <kvm.h>
37b2b3ffcdSSimon Schubert #include <string.h>
38b2b3ffcdSSimon Schubert
39b2b3ffcdSSimon Schubert #include <defs.h>
40b2b3ffcdSSimon Schubert #include <target.h>
41b2b3ffcdSSimon Schubert #include <gdbthread.h>
42b2b3ffcdSSimon Schubert #include <inferior.h>
43b2b3ffcdSSimon Schubert #include <regcache.h>
44b2b3ffcdSSimon Schubert #include <frame-unwind.h>
45b2b3ffcdSSimon Schubert #include <amd64-tdep.h>
46b2b3ffcdSSimon Schubert
47b2b3ffcdSSimon Schubert #include "kgdb.h"
48b2b3ffcdSSimon Schubert
49b2b3ffcdSSimon Schubert static int
50b2b3ffcdSSimon Schubert kgdb_trgt_trapframe_sniffer(const struct frame_unwind *self,
51b2b3ffcdSSimon Schubert struct frame_info *next_frame,
52b2b3ffcdSSimon Schubert void **this_prologue_cache);
53b2b3ffcdSSimon Schubert
54b2b3ffcdSSimon Schubert void
kgdb_trgt_fetch_registers(struct target_ops * target_ops,struct regcache * regcache,int regno)55b2b3ffcdSSimon Schubert kgdb_trgt_fetch_registers(struct target_ops *target_ops, struct regcache *regcache, int regno)
56b2b3ffcdSSimon Schubert {
57b2b3ffcdSSimon Schubert struct kthr *kt;
58b2b3ffcdSSimon Schubert struct pcb pcb;
59b2b3ffcdSSimon Schubert
60b2b3ffcdSSimon Schubert kt = kgdb_thr_lookup_tid(ptid_get_tid(inferior_ptid));
61b2b3ffcdSSimon Schubert if (kt == NULL) {
62b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, regno, NULL);
63b2b3ffcdSSimon Schubert return;
64b2b3ffcdSSimon Schubert }
65b2b3ffcdSSimon Schubert
66b2b3ffcdSSimon Schubert /*
67b2b3ffcdSSimon Schubert * kt->pcb == 0 is a marker for "non-dumping kernel thread".
68b2b3ffcdSSimon Schubert */
69b2b3ffcdSSimon Schubert if (kt->pcb == 0) {
70b2b3ffcdSSimon Schubert uintptr_t regs[7];
71b2b3ffcdSSimon Schubert uintptr_t addr;
72b2b3ffcdSSimon Schubert uintptr_t sp;
73b2b3ffcdSSimon Schubert
74b2b3ffcdSSimon Schubert addr = kt->kaddr + offsetof(struct thread, td_sp);
75b2b3ffcdSSimon Schubert kvm_read(kvm, addr, &sp, sizeof(sp));
76b2b3ffcdSSimon Schubert /*
77b2b3ffcdSSimon Schubert * Stack is:
78b2b3ffcdSSimon Schubert * -2 ret
79b2b3ffcdSSimon Schubert * -1 popfq
80b2b3ffcdSSimon Schubert * 0 popq %r15 edi
81b2b3ffcdSSimon Schubert * 1 popq %r14
82b2b3ffcdSSimon Schubert * 2 popq %r13
83b2b3ffcdSSimon Schubert * 3 popq %r12
84b2b3ffcdSSimon Schubert * 4 popq %rbx
85b2b3ffcdSSimon Schubert * 5 popq %rbp
86b2b3ffcdSSimon Schubert * 6 ret
87b2b3ffcdSSimon Schubert */
88b2b3ffcdSSimon Schubert if (kvm_read(kvm, sp + 2 * sizeof(regs[0]), regs, sizeof(regs)) != sizeof(regs)) {
89b2b3ffcdSSimon Schubert warnx("kvm_read: %s", kvm_geterr(kvm));
90b2b3ffcdSSimon Schubert memset(regs, 0, sizeof(regs));
91b2b3ffcdSSimon Schubert }
92b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 7, ®s[0]);
93b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 6, ®s[1]);
94b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 5, ®s[2]);
95b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 4, ®s[3]);
96b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RBX_REGNUM, ®s[4]);
97b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RBP_REGNUM, ®s[5]);
98b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RIP_REGNUM, ®s[6]);
99b2b3ffcdSSimon Schubert sp += 9 * sizeof(regs[0]);
100b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RSP_REGNUM, &sp);
101b2b3ffcdSSimon Schubert return;
102b2b3ffcdSSimon Schubert }
103b2b3ffcdSSimon Schubert
104b2b3ffcdSSimon Schubert if (kvm_read(kvm, kt->pcb, &pcb, sizeof(pcb)) != sizeof(pcb)) {
105b2b3ffcdSSimon Schubert warnx("kvm_read: %s", kvm_geterr(kvm));
106b2b3ffcdSSimon Schubert memset(&pcb, 0, sizeof(pcb));
107b2b3ffcdSSimon Schubert }
108b2b3ffcdSSimon Schubert
109b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RBX_REGNUM, (char *)&pcb.pcb_rbx);
110b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RBP_REGNUM, (char *)&pcb.pcb_rbp);
111b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RSP_REGNUM, (char *)&pcb.pcb_rsp);
112b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 4, (char *)&pcb.pcb_r12);
113b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 5, (char *)&pcb.pcb_r13);
114b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R8_REGNUM + 6, (char *)&pcb.pcb_r14);
115b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_R15_REGNUM, (char *)&pcb.pcb_r15);
116b2b3ffcdSSimon Schubert regcache_raw_supply(regcache, AMD64_RIP_REGNUM, (char *)&pcb.pcb_rip);
117b2b3ffcdSSimon Schubert }
118b2b3ffcdSSimon Schubert
119b2b3ffcdSSimon Schubert struct kgdb_frame_cache {
12071f9f020SMatthew Dillon int frame_type;
121b2b3ffcdSSimon Schubert CORE_ADDR pc;
122b2b3ffcdSSimon Schubert CORE_ADDR sp;
123b2b3ffcdSSimon Schubert };
124b2b3ffcdSSimon Schubert
12571f9f020SMatthew Dillon #define FT_NORMAL 1
12671f9f020SMatthew Dillon #define FT_INTRFRAME 2
12771f9f020SMatthew Dillon /*#define FT_INTRTRAPFRAME 3*/
12871f9f020SMatthew Dillon #define FT_TIMERFRAME 4
12971f9f020SMatthew Dillon #define FT_CALLTRAP 5
13071f9f020SMatthew Dillon
131b2b3ffcdSSimon Schubert static int kgdb_trgt_frame_offset[20] = {
132b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rax),
133b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rbx),
134b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rcx),
135b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rdx),
136b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rsi),
137b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rdi),
138b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rbp),
139b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rsp),
140b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r8),
141b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r9),
142b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r10),
143b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r11),
144b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r12),
145b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r13),
146b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r14),
147b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_r15),
148b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rip),
149b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_rflags),
150b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_cs),
151b2b3ffcdSSimon Schubert offsetof(struct trapframe, tf_ss)
152b2b3ffcdSSimon Schubert };
153b2b3ffcdSSimon Schubert
154b2b3ffcdSSimon Schubert static struct kgdb_frame_cache *
kgdb_trgt_frame_cache(struct frame_info * next_frame,void ** this_cache)155b2b3ffcdSSimon Schubert kgdb_trgt_frame_cache(struct frame_info *next_frame, void **this_cache)
156b2b3ffcdSSimon Schubert {
157b2b3ffcdSSimon Schubert struct kgdb_frame_cache *cache;
158*c33252afSJohn Marino const char *pname;
159b2b3ffcdSSimon Schubert
160b2b3ffcdSSimon Schubert cache = *this_cache;
161b2b3ffcdSSimon Schubert if (cache == NULL) {
162b2b3ffcdSSimon Schubert cache = FRAME_OBSTACK_ZALLOC(struct kgdb_frame_cache);
163b2b3ffcdSSimon Schubert *this_cache = cache;
164b2b3ffcdSSimon Schubert cache->pc = get_frame_address_in_block(next_frame);
16571f9f020SMatthew Dillon cache->sp = get_frame_sp(next_frame);
16671f9f020SMatthew Dillon find_pc_partial_function(cache->pc, &pname, NULL, NULL);
16771f9f020SMatthew Dillon
16871f9f020SMatthew Dillon if (strcmp(pname, "calltrap") == 0)
16971f9f020SMatthew Dillon cache->frame_type = FT_CALLTRAP;
17071f9f020SMatthew Dillon else if (pname[0] != 'X')
17171f9f020SMatthew Dillon cache->frame_type = FT_NORMAL;
17271f9f020SMatthew Dillon else if (strcmp(pname, "Xtimerint") == 0)
17371f9f020SMatthew Dillon cache->frame_type = FT_TIMERFRAME;
17471f9f020SMatthew Dillon else
17571f9f020SMatthew Dillon cache->frame_type = FT_INTRFRAME;
176b2b3ffcdSSimon Schubert }
177b2b3ffcdSSimon Schubert return (cache);
178b2b3ffcdSSimon Schubert }
179b2b3ffcdSSimon Schubert
180b2b3ffcdSSimon Schubert static void
kgdb_trgt_trapframe_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)181b2b3ffcdSSimon Schubert kgdb_trgt_trapframe_this_id(struct frame_info *next_frame, void **this_cache,
182b2b3ffcdSSimon Schubert struct frame_id *this_id)
183b2b3ffcdSSimon Schubert {
184b2b3ffcdSSimon Schubert struct kgdb_frame_cache *cache;
185b2b3ffcdSSimon Schubert
186b2b3ffcdSSimon Schubert cache = kgdb_trgt_frame_cache(next_frame, this_cache);
187b2b3ffcdSSimon Schubert *this_id = frame_id_build(cache->sp, cache->pc);
188b2b3ffcdSSimon Schubert }
189b2b3ffcdSSimon Schubert
190b2b3ffcdSSimon Schubert static struct value *
kgdb_trgt_trapframe_prev_register(struct frame_info * next_frame,void ** this_cache,int regnum)191b2b3ffcdSSimon Schubert kgdb_trgt_trapframe_prev_register(struct frame_info *next_frame,
192b2b3ffcdSSimon Schubert void **this_cache, int regnum)
193b2b3ffcdSSimon Schubert {
194b2b3ffcdSSimon Schubert CORE_ADDR addrp;
195b2b3ffcdSSimon Schubert struct kgdb_frame_cache *cache;
196b2b3ffcdSSimon Schubert int ofs;
197b2b3ffcdSSimon Schubert
198b2b3ffcdSSimon Schubert if (regnum < AMD64_RAX_REGNUM || regnum > AMD64_EFLAGS_REGNUM + 2)
199b2b3ffcdSSimon Schubert return frame_unwind_got_register(next_frame, regnum, regnum);
200b2b3ffcdSSimon Schubert
201b2b3ffcdSSimon Schubert ofs = kgdb_trgt_frame_offset[regnum];
202b2b3ffcdSSimon Schubert
203b2b3ffcdSSimon Schubert cache = kgdb_trgt_frame_cache(next_frame, this_cache);
204b2b3ffcdSSimon Schubert
20571f9f020SMatthew Dillon switch (cache->frame_type) {
20671f9f020SMatthew Dillon case FT_NORMAL:
20771f9f020SMatthew Dillon break;
20871f9f020SMatthew Dillon case FT_INTRFRAME:
20971f9f020SMatthew Dillon ofs += 8;
21071f9f020SMatthew Dillon break;
21171f9f020SMatthew Dillon case FT_TIMERFRAME:
21271f9f020SMatthew Dillon break;
21371f9f020SMatthew Dillon /*
21471f9f020SMatthew Dillon case FT_INTRTRAPFRAME:
21571f9f020SMatthew Dillon ofs -= ofs_fix;
21671f9f020SMatthew Dillon break;
21771f9f020SMatthew Dillon */
21871f9f020SMatthew Dillon case FT_CALLTRAP:
21971f9f020SMatthew Dillon ofs += 0;
22071f9f020SMatthew Dillon break;
22171f9f020SMatthew Dillon default:
22271f9f020SMatthew Dillon fprintf_unfiltered(gdb_stderr, "Correct FT_XXX frame offsets "
22371f9f020SMatthew Dillon "for %d\n", cache->frame_type);
22471f9f020SMatthew Dillon break;
22571f9f020SMatthew Dillon }
22671f9f020SMatthew Dillon
227b2b3ffcdSSimon Schubert addrp = cache->sp + ofs;
228b2b3ffcdSSimon Schubert return frame_unwind_got_memory(next_frame, regnum, addrp);
229b2b3ffcdSSimon Schubert }
230b2b3ffcdSSimon Schubert
2310c3d3a6fSJohn Marino static enum unwind_stop_reason
kgdb_trgt_trapframe_unwind_reason(struct frame_info * next_frame,void ** this_cache)2320c3d3a6fSJohn Marino kgdb_trgt_trapframe_unwind_reason(struct frame_info *next_frame,
2330c3d3a6fSJohn Marino void **this_cache)
2340c3d3a6fSJohn Marino {
2350c3d3a6fSJohn Marino /* XXX marino : populate logic to determine unwind stoppage */
2360c3d3a6fSJohn Marino return UNWIND_NO_REASON;
2370c3d3a6fSJohn Marino }
2380c3d3a6fSJohn Marino
239b2b3ffcdSSimon Schubert const struct frame_unwind kgdb_trgt_trapframe_unwind = {
240b2b3ffcdSSimon Schubert NORMAL_FRAME,
2410c3d3a6fSJohn Marino &kgdb_trgt_trapframe_unwind_reason,
242b2b3ffcdSSimon Schubert &kgdb_trgt_trapframe_this_id,
243b2b3ffcdSSimon Schubert &kgdb_trgt_trapframe_prev_register,
244b2b3ffcdSSimon Schubert .sniffer = kgdb_trgt_trapframe_sniffer
245b2b3ffcdSSimon Schubert };
246b2b3ffcdSSimon Schubert
247b2b3ffcdSSimon Schubert static int
kgdb_trgt_trapframe_sniffer(const struct frame_unwind * self,struct frame_info * next_frame,void ** this_prologue_cache)248b2b3ffcdSSimon Schubert kgdb_trgt_trapframe_sniffer(const struct frame_unwind *self,
249b2b3ffcdSSimon Schubert struct frame_info *next_frame,
250b2b3ffcdSSimon Schubert void **this_prologue_cache)
251b2b3ffcdSSimon Schubert {
252*c33252afSJohn Marino const char *pname;
253b2b3ffcdSSimon Schubert CORE_ADDR pc;
254b2b3ffcdSSimon Schubert
255b2b3ffcdSSimon Schubert pc = get_frame_address_in_block(next_frame);
256b2b3ffcdSSimon Schubert pname = NULL;
257b2b3ffcdSSimon Schubert find_pc_partial_function(pc, &pname, NULL, NULL);
258b2b3ffcdSSimon Schubert if (pname == NULL)
259b2b3ffcdSSimon Schubert return (0);
260b2b3ffcdSSimon Schubert if (strcmp(pname, "calltrap") == 0 ||
261b2b3ffcdSSimon Schubert strcmp(pname, "dblfault_handler") == 0 ||
262b2b3ffcdSSimon Schubert strcmp(pname, "nmi_calltrap") == 0 ||
263b2b3ffcdSSimon Schubert (pname[0] == 'X' && pname[1] != '_'))
264b2b3ffcdSSimon Schubert return (1);
265b2b3ffcdSSimon Schubert return (0);
266b2b3ffcdSSimon Schubert }
267