]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/ddb/db_main.c
Merge from stable/11:
[FreeBSD/FreeBSD.git] / sys / ddb / db_main.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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/cons.h>
33 #include <sys/linker.h>
34 #include <sys/kdb.h>
35 #include <sys/kernel.h>
36 #include <sys/pcpu.h>
37 #include <sys/proc.h>
38 #include <sys/reboot.h>
39 #include <sys/sysctl.h>
40
41 #include <machine/kdb.h>
42 #include <machine/pcb.h>
43 #include <machine/setjmp.h>
44
45 #include <ddb/ddb.h>
46 #include <ddb/db_command.h>
47 #include <ddb/db_sym.h>
48
49 SYSCTL_NODE(_debug, OID_AUTO, ddb, CTLFLAG_RW, 0, "DDB settings");
50
51 static dbbe_init_f db_init;
52 static dbbe_trap_f db_trap;
53 static dbbe_trace_f db_trace_self_wrapper;
54 static dbbe_trace_thread_f db_trace_thread_wrapper;
55
56 KDB_BACKEND(ddb, db_init, db_trace_self_wrapper, db_trace_thread_wrapper,
57     db_trap);
58
59 /*
60  * Symbols can be loaded by specifying the exact addresses of
61  * the symtab and strtab in memory. This is used when loaded from
62  * boot loaders different than the native one (like Xen).
63  */
64 vm_offset_t ksymtab, kstrtab, ksymtab_size;
65
66 bool
67 X_db_line_at_pc(db_symtab_t *symtab, c_db_sym_t sym, char **file, int *line,
68     db_expr_t off)
69 {
70         return (false);
71 }
72
73 c_db_sym_t
74 X_db_lookup(db_symtab_t *symtab, const char *symbol)
75 {
76         c_linker_sym_t lsym;
77         Elf_Sym *sym;
78
79         if (symtab->private == NULL) {
80                 return ((c_db_sym_t)((!linker_ddb_lookup(symbol, &lsym))
81                         ? lsym : NULL));
82         } else {
83                 sym = (Elf_Sym *)symtab->start;
84                 while ((char *)sym < symtab->end) {
85                         if (sym->st_name != 0 &&
86                             !strcmp(symtab->private + sym->st_name, symbol))
87                                 return ((c_db_sym_t)sym);
88                         sym++;
89                 }
90         }
91         return (NULL);
92 }
93
94 c_db_sym_t
95 X_db_search_symbol(db_symtab_t *symtab, db_addr_t off, db_strategy_t strat,
96     db_expr_t *diffp)
97 {
98         c_linker_sym_t lsym;
99         Elf_Sym *sym, *match;
100         unsigned long diff;
101
102         if (symtab->private == NULL) {
103                 if (!linker_ddb_search_symbol((caddr_t)off, &lsym, &diff)) {
104                         *diffp = (db_expr_t)diff;
105                         return ((c_db_sym_t)lsym);
106                 }
107                 return (NULL);
108         }
109
110         diff = ~0UL;
111         match = NULL;
112         for (sym = (Elf_Sym*)symtab->start; (char*)sym < symtab->end; sym++) {
113                 if (sym->st_name == 0 || sym->st_shndx == SHN_UNDEF)
114                         continue;
115                 if (off < sym->st_value)
116                         continue;
117                 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
118                     ELF_ST_TYPE(sym->st_info) != STT_FUNC &&
119                     ELF_ST_TYPE(sym->st_info) != STT_NOTYPE)
120                         continue;
121                 if ((off - sym->st_value) > diff)
122                         continue;
123                 if ((off - sym->st_value) < diff) {
124                         diff = off - sym->st_value;
125                         match = sym;
126                 } else {
127                         if (match == NULL)
128                                 match = sym;
129                         else if (ELF_ST_BIND(match->st_info) == STB_LOCAL &&
130                             ELF_ST_BIND(sym->st_info) != STB_LOCAL)
131                                 match = sym;
132                 }
133                 if (diff == 0) {
134                         if (strat == DB_STGY_PROC &&
135                             ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
136                             ELF_ST_BIND(sym->st_info) != STB_LOCAL)
137                                 break;
138                         if (strat == DB_STGY_ANY &&
139                             ELF_ST_BIND(sym->st_info) != STB_LOCAL)
140                                 break;
141                 }
142         }
143
144         *diffp = (match == NULL) ? off : diff;
145         return ((c_db_sym_t)match);
146 }
147
148 bool
149 X_db_sym_numargs(db_symtab_t *symtab, c_db_sym_t sym, int *nargp,
150     char **argp)
151 {
152         return (false);
153 }
154
155 void
156 X_db_symbol_values(db_symtab_t *symtab, c_db_sym_t sym, const char **namep,
157     db_expr_t *valp)
158 {
159         linker_symval_t lval;
160
161         if (symtab->private == NULL) {
162                 linker_ddb_symbol_values((c_linker_sym_t)sym, &lval);
163                 if (namep != NULL)
164                         *namep = (const char*)lval.name;
165                 if (valp != NULL)
166                         *valp = (db_expr_t)lval.value;
167         } else {
168                 if (namep != NULL)
169                         *namep = (const char *)symtab->private +
170                             ((const Elf_Sym *)sym)->st_name;
171                 if (valp != NULL)
172                         *valp = (db_expr_t)((const Elf_Sym *)sym)->st_value;
173         }
174 }
175
176 int
177 db_fetch_ksymtab(vm_offset_t ksym_start, vm_offset_t ksym_end)
178 {
179         Elf_Size strsz;
180
181         if (ksym_end > ksym_start && ksym_start != 0) {
182                 ksymtab = ksym_start;
183                 ksymtab_size = *(Elf_Size*)ksymtab;
184                 ksymtab += sizeof(Elf_Size);
185                 kstrtab = ksymtab + ksymtab_size;
186                 strsz = *(Elf_Size*)kstrtab;
187                 kstrtab += sizeof(Elf_Size);
188                 if (kstrtab + strsz > ksym_end) {
189                         /* Sizes doesn't match, unset everything. */
190                         ksymtab = ksymtab_size = kstrtab = 0;
191                 }
192         }
193
194         if (ksymtab == 0 || ksymtab_size == 0 || kstrtab == 0)
195                 return (-1);
196
197         return (0);
198 }
199
200 static int
201 db_init(void)
202 {
203
204         db_command_init();
205
206         if (ksymtab != 0 && kstrtab != 0 && ksymtab_size != 0) {
207                 db_add_symbol_table((char *)ksymtab,
208                     (char *)(ksymtab + ksymtab_size), "elf", (char *)kstrtab);
209         }
210         db_add_symbol_table(NULL, NULL, "kld", NULL);
211         return (1);     /* We're the default debugger. */
212 }
213
214 static int
215 db_trap(int type, int code)
216 {
217         jmp_buf jb;
218         void *prev_jb;
219         bool bkpt, watchpt;
220         const char *why;
221
222         /*
223          * Don't handle the trap if the console is unavailable (i.e. it
224          * is in graphics mode).
225          */
226         if (cnunavailable())
227                 return (0);
228
229         if (db_stop_at_pc(type, code, &bkpt, &watchpt)) {
230                 if (db_inst_count) {
231                         db_printf("After %d instructions (%d loads, %d stores),\n",
232                             db_inst_count, db_load_count, db_store_count);
233                 }
234                 prev_jb = kdb_jmpbuf(jb);
235                 if (setjmp(jb) == 0) {
236                         db_dot = PC_REGS();
237                         db_print_thread();
238                         if (bkpt)
239                                 db_printf("Breakpoint at\t");
240                         else if (watchpt)
241                                 db_printf("Watchpoint at\t");
242                         else
243                                 db_printf("Stopped at\t");
244                         db_print_loc_and_inst(db_dot);
245                 }
246                 why = kdb_why;
247                 db_script_kdbenter(why != KDB_WHY_UNSET ? why : "unknown");
248                 db_command_loop();
249                 (void)kdb_jmpbuf(prev_jb);
250         }
251
252         db_restart_at_pc(watchpt);
253
254         return (1);
255 }
256
257 static void
258 db_trace_self_wrapper(void)
259 {
260         jmp_buf jb;
261         void *prev_jb;
262
263         prev_jb = kdb_jmpbuf(jb);
264         if (setjmp(jb) == 0)
265                 db_trace_self();
266         (void)kdb_jmpbuf(prev_jb);
267 }
268
269 static void
270 db_trace_thread_wrapper(struct thread *td)
271 {
272         jmp_buf jb;
273         void *prev_jb;
274
275         prev_jb = kdb_jmpbuf(jb);
276         if (setjmp(jb) == 0)
277                 db_trace_thread(td, -1);
278         (void)kdb_jmpbuf(prev_jb);
279 }