Index: src/gdb/frame.h =================================================================== --- src.orig/gdb/frame.h 2004-09-08 10:26:20.000000000 +0530 +++ src/gdb/frame.h 2004-10-01 12:59:38.000000000 +0530 @@ -382,7 +382,10 @@ SIGTRAMP_FRAME, /* Sentinel or registers frame. This frame obtains register values direct from the inferior's registers. */ - SENTINEL_FRAME + SENTINEL_FRAME, + /* Kernel context switch frame. Shouldn't be printed in info threads + * listing. */ + CONTEXT_FRAME }; extern enum frame_type get_frame_type (struct frame_info *); Index: src/gdb/stack.c =================================================================== --- src.orig/gdb/stack.c 2004-08-03 06:27:26.000000000 +0530 +++ src/gdb/stack.c 2004-10-01 12:59:38.000000000 +0530 @@ -45,6 +45,7 @@ #include "dictionary.h" #include "reggroups.h" #include "regcache.h" +#include "objfiles.h" /* Prototypes for exported functions. */ @@ -420,9 +421,14 @@ struct symtab_and_line sal; int source_print; int location_print; + CORE_ADDR pc; + struct frame_id fid; + struct minimal_symbol *schedbegin; + struct minimal_symbol *schedend; if (get_frame_type (fi) == DUMMY_FRAME - || get_frame_type (fi) == SIGTRAMP_FRAME) + || get_frame_type (fi) == SIGTRAMP_FRAME + || (get_frame_type (fi) == CONTEXT_FRAME && print_level != 0)) { struct cleanup *uiout_cleanup = make_cleanup_ui_out_tuple_begin_end (uiout, "frame"); @@ -455,12 +461,38 @@ annotate_signal_handler_caller (); ui_out_field_string (uiout, "func", ""); } + else if (get_frame_type (fi) == CONTEXT_FRAME) + { + annotate_context_entry (); + ui_out_field_string (uiout, "func", ""); + } ui_out_text (uiout, "\n"); annotate_frame_end (); do_cleanups (uiout_cleanup); return; } + /* Don't print context switch and scheduler frames if we are at level 0. */ + if (get_frame_type (fi) == CONTEXT_FRAME) + { + schedbegin = lookup_minimal_symbol("__sched_text_start", NULL, + symfile_objfile); + schedend = lookup_minimal_symbol("__sched_text_end", NULL, + symfile_objfile); + if (schedbegin && schedend) + while ((fi = get_prev_frame(fi)) != NULL) + { + fid = get_frame_id(fi); + pc = 0; + if (!fid.code_addr_p) + break; + pc = get_frame_id(fi).code_addr; + if (SYMBOL_VALUE_ADDRESS(schedbegin) >= pc) + break; + if (SYMBOL_VALUE_ADDRESS(schedend) <= pc) + break; + } + } /* If fi is not the innermost frame, that normally means that fi->pc points to *after* the call instruction, and we want to get the Index: src/gdb/annotate.c =================================================================== --- src.orig/gdb/annotate.c 2004-04-22 05:22:19.000000000 +0530 +++ src/gdb/annotate.c 2004-10-01 12:59:38.000000000 +0530 @@ -453,6 +453,13 @@ } void +annotate_context_entry (void) +{ + if (annotation_level == 2) + printf_filtered ("\n\032\032context-switch\n"); +} + +void annotate_frame_address (void) { if (annotation_level == 2) Index: src/gdb/annotate.h =================================================================== --- src.orig/gdb/annotate.h 2004-04-22 05:22:19.000000000 +0530 +++ src/gdb/annotate.h 2004-10-01 12:59:38.000000000 +0530 @@ -81,6 +81,7 @@ extern void annotate_frame_begin (int, CORE_ADDR); extern void annotate_function_call (void); extern void annotate_signal_handler_caller (void); +extern void annotate_context_entry (void); extern void annotate_frame_address (void); extern void annotate_frame_address_end (void); extern void annotate_frame_function_name (void); Index: src/gdb/i386-lk-tdep.c =================================================================== --- src.orig/gdb/i386-lk-tdep.c 2004-10-01 12:58:49.000000000 +0530 +++ src/gdb/i386-lk-tdep.c 2004-10-01 12:59:38.000000000 +0530 @@ -20,14 +20,16 @@ #include "defs.h" #include "osabi.h" +#include "frame-unwind.h" #include "i386-tdep.h" -#include "i386-linux-tdep.h" +#include "lk-tdep.h" static void i386_lk_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct context_unwind_data *unwind_data; /* Linux kernel has an elf vmlinux file and uses elf format modules. */ i386_elf_init_abi (info, gdbarch); @@ -37,6 +39,12 @@ set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p); tdep->jb_pc_offset = 20; /* From . */ + unwind_data = (struct context_unwind_data *) + context_frame_unwinder.unwind_data; + /* From kernel/include/asm-i386/system.h */ + unwind_data->pcshift = 2; + unwind_data->spshift = 8; + frame_unwind_prepend_unwinder (gdbarch, &context_frame_unwinder); } /* Provide a prototype to silence -Wmissing-prototypes. */ Index: src/gdb/lk-tdep.c =================================================================== --- src.orig/gdb/lk-tdep.c 2003-01-30 15:54:37.000000000 +0530 +++ src/gdb/lk-tdep.c 2004-10-01 12:59:38.000000000 +0530 @@ -0,0 +1,120 @@ +/* Target-dependent code for Linux kernel. + + Copyright 2004 LinSysSoft Technologies Pvt. Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "frame.h" +#include "gdbarch.h" +#include "frame-unwind.h" +#include "gdb_assert.h" +#include "symtab.h" +#include "objfiles.h" +#include "lk-tdep.h" + +/* Identifier for a context frame is composed of simply the sp and pc derived + * from next frame, which is a sentinel frame */ +static void +context_frame_this_id (struct frame_info *next_frame, void **this_cache, + struct frame_id *this_id) +{ + int optimized; + enum lval_type lvalp; + CORE_ADDR addr; + int realnum; + CORE_ADDR ipaddr; + CORE_ADDR spaddr; + + frame_register_unwind(next_frame, SP_REGNUM, &optimized, &lvalp, &addr, + &realnum, &spaddr); + frame_register_unwind(next_frame, PC_REGNUM, &optimized, &lvalp, &addr, + &realnum, &ipaddr); + (*this_id) = frame_id_build(spaddr, ipaddr); +} + +/* + * The pc of the frame previous to a context frame is reported at the + * instruction just past the last instruction of switch_to kernel macro. The + * sp may also need some adjustments because the switch_to macro may contain + * code that changes sp + */ +static void +context_frame_prev_register (struct frame_info *next_frame, void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct context_unwind_data *unwind_dat = (struct context_unwind_data *) + context_frame_unwinder.unwind_data; + frame_register_unwind(next_frame, regnum, optimizedp, lvalp, addrp, + realnump, valuep); + if (regnum == PC_REGNUM) + { + *addrp = 0; + if (valuep) + (*(CORE_ADDR*)valuep) += unwind_data->pcshift; + } + else if (regnum == SP_REGNUM) + { + *addrp = 0; + if (valuep) + (*(CORE_ADDR*)valuep) += unwind_data->spshift; + } +} + +/* If pc is in the section .sched.text and if the next frame is a sentinel + * frame, it has to be a context switch call frame */ +static const struct frame_unwind * +context_frame_sniffer (struct frame_unwind *self, + struct frame_info *next_frame, + void **this_prologue_cache) +{ + CORE_ADDR pc; + struct minimal_symbol *s; + + if (get_frame_type(next_frame) == SENTINEL_FRAME) + { + pc = frame_pc_unwind(next_frame); + s = lookup_minimal_symbol("__sched_text_start", NULL, symfile_objfile); + if (s && SYMBOL_VALUE_ADDRESS(s) >= pc) + return NULL; + s = lookup_minimal_symbol("__sched_text_end", NULL, symfile_objfile); + if (s && SYMBOL_VALUE_ADDRESS(s) <= pc) + return NULL; + return &context_frame_unwinder; + } + return NULL; +} + +static struct context_unwind_data context_unwind_data; + +const struct frame_unwind context_frame_unwinder = +{ + CONTEXT_FRAME, + context_frame_this_id, + context_frame_prev_register, + (struct frame_data *)&context_unwind_data, + context_frame_sniffer +}; + +/* Provide a prototype to silence -Wmissing-prototypes. */ +extern void _initialize_lk_tdep (void); + +void +_initialize_lk_tdep (void) +{ +} Index: src/gdb/config/i386/lk.mt =================================================================== --- src.orig/gdb/config/i386/lk.mt 2004-10-01 12:58:49.000000000 +0530 +++ src/gdb/config/i386/lk.mt 2004-10-01 12:59:38.000000000 +0530 @@ -1,3 +1,3 @@ # Target: Intel i386 running Linux kernel -TDEPFILES = i386-tdep.o i386-lk-tdep.o i387-tdep.o +TDEPFILES = i386-tdep.o i386-lk-tdep.o i387-tdep.o lk-tdep.o TM_FILE= tm-lk.h Index: src/gdb/config/i386/x86-64lk.mt =================================================================== --- src.orig/gdb/config/i386/x86-64lk.mt 2004-10-01 12:58:49.000000000 +0530 +++ src/gdb/config/i386/x86-64lk.mt 2004-10-01 12:59:38.000000000 +0530 @@ -1,5 +1,5 @@ # Target: AMD x86-64 running Linux Kernel -TDEPFILES= x86-64-tdep.o x86-64-lk-tdep.o \ +TDEPFILES= x86-64-tdep.o x86-64-lk-tdep.o lk-tdep.o \ i386-tdep.o i387-tdep.o i386-lk-tdep.o GDB_MULTI_ARCH=GDB_MULTI_ARCH_TM Index: src/gdb/lk-tdep.h =================================================================== --- src.orig/gdb/lk-tdep.h 2003-01-30 15:54:37.000000000 +0530 +++ src/gdb/lk-tdep.h 2004-10-01 12:59:38.000000000 +0530 @@ -0,0 +1,38 @@ +/* Target-dependent code for Linux kernel. + + Copyright 2004 LinSysSoft Technologies Pvt. Ltd. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef LK_TDEP_H +#define LK_TDEP_H + +/* CONTEXT_FRAME unwind data */ +struct context_unwind_data +{ + /* These two fields record the difference between pc and sp of context + * and the previous frame (the schedule kernel function) + * We use these fields and the pc and sp of the frame next to the + * context frame (sentinel frame) to figure out the pc and sp of the + * schedule function frame. + */ + int pcshift; + int spshift; +}; + +extern const struct frame_unwind context_frame_unwinder; + +#endif /* #ifndef LK_TDEP_H */ Index: src/gdb/x86-64-lk-tdep.c =================================================================== --- src.orig/gdb/x86-64-lk-tdep.c 2004-10-01 12:58:49.000000000 +0530 +++ src/gdb/x86-64-lk-tdep.c 2004-10-01 12:59:38.000000000 +0530 @@ -22,14 +22,22 @@ #include "osabi.h" #include "x86-64-tdep.h" -#include "x86-64-linux-tdep.h" - +#include "lk-tdep.h" static void x86_64_lk_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct context_unwind_data *unwind_data; + x86_64_init_abi (info, gdbarch); + + unwind_data = (struct context_unwind_data *) + context_frame_unwinder->unwind_data; + /* From kernel/include/asm-x86_64/system.h */ + unwind_data->pcshift = 33; + unwind_data->spshift = TODO; + frame_unwind_prepend_unwinder (gdbarch, &context_frame_unwinder); } /* Provide a prototype to silence -Wmissing-prototypes. */