]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/amd64/amd64/db_trace.c
This is the Linux generic soundcard driver, version 1.0c. Supports
[FreeBSD/FreeBSD.git] / sys / amd64 / amd64 / db_trace.c
1 /* 
2  * Mach Operating System
3  * Copyright (c) 1991,1990 Carnegie Mellon University
4  * All Rights Reserved.
5  * 
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  * 
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  * 
16  * Carnegie Mellon requests users of this software to return to
17  * 
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  * 
23  * any improvements or extensions that they make and grant Carnegie the
24  * rights to redistribute these changes.
25  *
26  *      $Id$
27  */
28
29 #include "param.h"
30 #include "proc.h"
31 #include <machine/db_machdep.h>
32
33 #include <ddb/db_access.h>
34 #include <ddb/db_sym.h>
35 #include <ddb/db_variables.h>
36
37 /*
38  * Machine register set.
39  */
40 struct db_variable db_regs[] = {
41         "cs",   (int *)&ddb_regs.tf_cs,  FCN_NULL,
42         "ds",   (int *)&ddb_regs.tf_ds,  FCN_NULL,
43         "es",   (int *)&ddb_regs.tf_es,  FCN_NULL,
44 #if 0
45         "fs",   (int *)&ddb_regs.tf_fs,  FCN_NULL,
46         "gs",   (int *)&ddb_regs.tf_gs,  FCN_NULL,
47 #endif
48         "ss",   (int *)&ddb_regs.tf_ss,  FCN_NULL,
49         "eax",  (int *)&ddb_regs.tf_eax, FCN_NULL,
50         "ecx",  (int *)&ddb_regs.tf_ecx, FCN_NULL,
51         "edx",  (int *)&ddb_regs.tf_edx, FCN_NULL,
52         "ebx",  (int *)&ddb_regs.tf_ebx, FCN_NULL,
53         "esp",  (int *)&ddb_regs.tf_esp,FCN_NULL,
54         "ebp",  (int *)&ddb_regs.tf_ebp, FCN_NULL,
55         "esi",  (int *)&ddb_regs.tf_esi, FCN_NULL,
56         "edi",  (int *)&ddb_regs.tf_edi, FCN_NULL,
57         "eip",  (int *)&ddb_regs.tf_eip, FCN_NULL,
58         "efl",  (int *)&ddb_regs.tf_eflags, FCN_NULL,
59 };
60 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
61
62 /*
63  * Stack trace.
64  */
65 #define INKERNEL(va)    (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
66
67 struct i386_frame {
68         struct i386_frame       *f_frame;
69         int                     f_retaddr;
70         int                     f_arg0;
71 };
72
73 #define TRAP            1
74 #define INTERRUPT       2
75
76 db_addr_t       db_trap_symbol_value = 0;
77 db_addr_t       db_kdintr_symbol_value = 0;
78 boolean_t       db_trace_symbols_found = FALSE;
79
80 void
81 db_find_trace_symbols()
82 {
83         db_expr_t       value;
84         if (db_value_of_name("_trap", &value))
85             db_trap_symbol_value = (db_addr_t) value;
86         if (db_value_of_name("_kdintr", &value))
87             db_kdintr_symbol_value = (db_addr_t) value;
88         db_trace_symbols_found = TRUE;
89 }
90
91 /*
92  * Figure out how many arguments were passed into the frame at "fp".
93  */
94 int
95 db_numargs(fp)
96         struct i386_frame *fp;
97 {
98         int     *argp;
99         int     inst;
100         int     args;
101         extern char     etext[];
102
103         argp = (int *)db_get_value((int)&fp->f_retaddr, 4, FALSE);
104         if (argp < (int *)VM_MIN_KERNEL_ADDRESS || argp > (int *)etext)
105             args = 5;
106         else {
107             inst = db_get_value((int)argp, 4, FALSE);
108             if ((inst & 0xff) == 0x59)  /* popl %ecx */
109                 args = 1;
110             else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
111                 args = ((inst >> 16) & 0xff) / 4;
112             else
113                 args = 5;
114         }
115         return (args);
116 }
117
118 /* 
119  * Figure out the next frame up in the call stack.  
120  * For trap(), we print the address of the faulting instruction and 
121  *   proceed with the calling frame.  We return the ip that faulted.
122  *   If the trap was caused by jumping through a bogus pointer, then
123  *   the next line in the backtrace will list some random function as 
124  *   being called.  It should get the argument list correct, though.  
125  *   It might be possible to dig out from the next frame up the name
126  *   of the function that faulted, but that could get hairy.
127  */
128 void
129 db_nextframe(fp, ip, argp, is_trap)
130         struct i386_frame **fp;         /* in/out */
131         db_addr_t       *ip;            /* out */
132         int *argp;                      /* in */
133         int is_trap;                    /* in */
134 {
135         struct i386_saved_state *saved_regs;
136
137         if (is_trap == 0) {
138             *ip = (db_addr_t)
139                         db_get_value((int) &(*fp)->f_retaddr, 4, FALSE);
140             *fp = (struct i386_frame *)
141                         db_get_value((int) &(*fp)->f_frame, 4, FALSE);
142         } else {
143             /*
144              * We know that trap() has 1 argument and we know that
145              * it is an (int *).
146              */
147             saved_regs = (struct i386_saved_state *)
148                         db_get_value((int)argp, 4, FALSE);
149             db_printf("--- trap (number %d) ---\n",
150                       saved_regs->tf_trapno & 0xffff);
151             db_printsym(saved_regs->tf_eip, DB_STGY_XTRN);
152             db_printf(":\n");
153             *fp = (struct i386_frame *)saved_regs->tf_ebp;
154             *ip = (db_addr_t)saved_regs->tf_eip;
155         }
156
157 }
158
159 void
160 db_stack_trace_cmd(addr, have_addr, count, modif)
161         db_expr_t       addr;
162         boolean_t       have_addr;
163         db_expr_t       count;
164         char            *modif;
165 {
166         struct i386_frame *frame, *lastframe;
167         int             *argp;
168         db_addr_t       callpc;
169         int             is_trap;
170         boolean_t       kernel_only = TRUE;
171         boolean_t       trace_thread = FALSE;
172
173         if (!db_trace_symbols_found)
174             db_find_trace_symbols();
175
176         {
177             register char *cp = modif;
178             register char c;
179
180             while ((c = *cp++) != 0) {
181                 if (c == 't')
182                     trace_thread = TRUE;
183                 if (c == 'u')
184                     kernel_only = FALSE;
185             }
186         }
187
188         if (count == -1)
189             count = 65535;
190
191         if (!have_addr) {
192             frame = (struct i386_frame *)ddb_regs.tf_ebp;
193             callpc = (db_addr_t)ddb_regs.tf_eip;
194         }
195         else if (trace_thread) {
196                 printf ("db_trace.c: can't trace thread\n");
197         }
198         else {
199             frame = (struct i386_frame *)addr;
200             callpc = (db_addr_t)db_get_value((int)&frame->f_retaddr, 4, FALSE);
201         }
202
203         lastframe = 0;
204         while (count-- && frame != 0) {
205             register int narg;
206             char *      name;
207             db_expr_t   offset;
208
209             if (INKERNEL((int)frame) && callpc == db_trap_symbol_value) {
210                 narg = 1;
211                 is_trap = TRAP;
212             }
213             else
214             if (INKERNEL((int)frame) && callpc == db_kdintr_symbol_value) {
215                 is_trap = INTERRUPT;
216                 narg = 0;
217             }
218             else {
219                 is_trap = 0;
220                 narg = db_numargs(frame);
221             }
222
223             db_find_sym_and_offset(callpc, &name, &offset);
224             db_printf("%s(", name);
225
226             argp = &frame->f_arg0;
227             while (narg) {
228                 db_printf("%x", db_get_value((int)argp, 4, FALSE));
229                 argp++;
230                 if (--narg != 0)
231                     db_printf(",");
232             }
233             db_printf(") at ");
234             db_printsym(callpc, DB_STGY_XTRN);
235             db_printf("\n");
236
237             lastframe = frame;
238             db_nextframe(&frame, &callpc, &frame->f_arg0, is_trap);
239
240             if (frame == 0) {
241                 /* end of chain */
242                 break;
243             }
244             if (INKERNEL((int)frame)) {
245                 /* staying in kernel */
246                 if (frame <= lastframe) {
247                     db_printf("Bad frame pointer: 0x%x\n", frame);
248                     break;
249                 }
250             }
251             else if (INKERNEL((int)lastframe)) {
252                 /* switch from user to kernel */
253                 if (kernel_only)
254                     break;      /* kernel stack only */
255             }
256             else {
257                 /* in user */
258                 if (frame <= lastframe) {
259                     db_printf("Bad frame pointer: 0x%x\n", frame);
260                     break;
261                 }
262             }
263         }
264 }