Index: gdb/remote.c =================================================================== --- gdb/remote.c (revision 4) +++ gdb/remote.c (working copy) @@ -3,6 +3,7 @@ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2009 Caz Yokoyama, caz at caztech dot com. This file is part of GDB. @@ -2595,6 +2596,7 @@ remote_open_1 (char *name, int from_tty, struct target_ops *target, int extended_p, int async_p) { + extern int debugvmlinux; struct remote_state *rs = get_remote_state (); if (name == 0) error (_("To open a remote debug connection, you need to specify what\n" @@ -2685,6 +2687,11 @@ use_threadinfo_query = 1; use_threadextra_query = 1; + if (debugvmlinux) { + serial_send_break(remote_desc); + serial_write(remote_desc, "g", 1); + } + /* The first packet we send to the target is the optional "supported packets" request. If the target can answer this, it will tell us which later probes to skip. */ @@ -3261,14 +3268,21 @@ static void remote_stop (void) { + extern int debugkernel; + /* Send a break or a ^C, depending on user preference. */ if (remote_debug) fprintf_unfiltered (gdb_stdlog, "remote_stop called\n"); - if (remote_break) + if (debugkernel) { serial_send_break (remote_desc); - else - serial_write (remote_desc, "\003", 1); + serial_write (remote_desc, "g", 1); + } else { + if (remote_break) + serial_send_break (remote_desc); + else + serial_write (remote_desc, "\003", 1); + } } /* Ask the user what to do when an interrupt is received. */ Index: gdb/dwarf2read.c =================================================================== --- gdb/dwarf2read.c (revision 4) +++ gdb/dwarf2read.c (working copy) @@ -2,6 +2,7 @@ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2009 Caz Yokoyama, caz at caztech dot com. Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, Inc. with support from Florida State University (under contract @@ -1701,6 +1702,7 @@ struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; struct partial_die_info *pdi; + extern int debugvmlinux; /* Now, march along the PDI's, descending into ones which have interesting children but skipping the children of the other ones, @@ -1775,6 +1777,13 @@ /* If the die has a sibling, skip to the sibling. */ pdi = pdi->die_sibling; + + if (debugvmlinux) { + if (pdi != NULL && pdi->highpc >= 0xffffffffff000000) { + if (pdi->die_sibling != NULL) + pdi = pdi->die_sibling; + } + } } } Index: gdb/ChangeLog-2009 =================================================================== --- gdb/ChangeLog-2009 (revision 0) +++ gdb/ChangeLog-2009 (revision 12) @@ -0,0 +1,7 @@ +2009-01-09 Caz Yokoyama + + * remote.c send Magic SysRq, i.e. BREAK g when for kgdb light. + * dwarf2read.c work around for doubtfull high address in 2.6.27.8 kernel + * main.c set whether debugging kernel + * amd64-linux-tdep.c add x86_64 linux kernel OS abi + * solib-svr4.c read symbol tables of loadable modules. Index: gdb/main.c =================================================================== --- gdb/main.c (revision 4) +++ gdb/main.c (working copy) @@ -3,6 +3,7 @@ Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2009 Caz Yokoyama, caz at caztech dot com. This file is part of GDB. @@ -62,6 +63,10 @@ /* System root path, used to find libraries etc. */ char *gdb_sysroot = 0; +/* Whether debugging a kernel */ +int debugkernel = 0; +int debugvmlinux = 0; /* debugging vmlinx? */ + struct ui_file *gdb_stdout; struct ui_file *gdb_stderr; struct ui_file *gdb_stdlog; @@ -131,6 +136,7 @@ char *pid_or_core_arg = NULL; char *cdarg = NULL; char *ttyarg = NULL; + char *filename, *dir; /* These are static so that we can take their address in an initializer. */ static int print_help; @@ -679,6 +685,17 @@ quit_pre_print = error_pre_print; warning_pre_print = _("\nwarning: "); + if (symarg != NULL) { + for (filename = symarg; + (dir = strchr(filename, '/')) != NULL; + filename = dir + 1) ; + /* only require the given characters to match, so that longer filenames + will still match */ + if (strncmp(filename, LINUX_KERNEL_NAME_STEM, + strlen(LINUX_KERNEL_NAME_STEM)) == 0) + debugvmlinux = 1; + } + /* Read and execute $HOME/.gdbinit file, if it exists. This is done *before* all the command line arguments are processed; it sets global parameters, which are independent of what file you are Index: gdb/solib-svr4.c =================================================================== --- gdb/solib-svr4.c (revision 4) +++ gdb/solib-svr4.c (working copy) @@ -2,6 +2,7 @@ Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + Copyright (C) 2009 Caz Yokoyama, caz at caztech dot com. This file is part of GDB. @@ -45,6 +46,7 @@ static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); +static struct so_list *kernel_current_sos (void); /* Link map info to include in an allocated so_list entry */ @@ -90,6 +92,7 @@ #ifdef SOLIB_BKPT_NAME SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ #endif + "module_event", "_start", "__start", "main", @@ -103,6 +106,113 @@ NULL }; +/* Macro to extract an address from a solib structure. When GDB is + configured for some 32-bit targets (e.g. Solaris 2.7 sparc), BFD is + configured to handle 64-bit targets, so CORE_ADDR is 64 bits. We + have to extract only the significant bits of addresses to get the + right address when accessing the core file BFD. + + Assume that the address is unsigned. */ + +#define SOLIB_EXTRACT_ADDRESS(MEMBER) \ + extract_unsigned_integer (&(MEMBER), sizeof (MEMBER)) + + +/* Kernel debugging structures */ +extern int debugkernel; + +struct list_head { + CORE_ADDR next; + CORE_ADDR prev; +}; + +#define MODULE_NAME_LEN (64 - sizeof(CORE_ADDR)) + +#define MAX_SECTNAME 31 + +struct mod_section { + CORE_ADDR address; + char name[MAX_SECTNAME + 1]; +}; + +/* taken from kernel source code */ +typedef unsigned int __kernel_mode_t; +typedef __kernel_mode_t mode_t; + +struct module; + +struct attribute { + const char *name; + struct module *owner; + mode_t mode; +}; + +struct attribute_group { + const char *name; + struct attribute **attrs; +}; + +struct module_attribute { + struct attribute attr; + ssize_t (*show)(struct module_attribute *, struct module *, char *); + ssize_t (*store)(struct module_attribute *, struct module *, + const char *, size_t count); + void (*setup)(struct module *, const char *); + int (*test)(struct module *); + void (*free)(struct module *); +}; + +#define MODULE_SECT_NAME_LEN 32 +struct module_sect_attr +{ + struct module_attribute mattr; + char name[MODULE_SECT_NAME_LEN]; + unsigned long address; +}; + +struct module_sect_attrs +{ + struct attribute_group grp; + struct module_sect_attr attrs[0]; +}; +#define NUM_SECTIONS 1 // number of sections + +struct attribute_group_2_6_27 { + const char *name; + mode_t (*is_visible)(); + struct attribute **attrs; +}; + +struct module_sect_attr_2_6_27 +{ + struct module_attribute mattr; + char *name; + unsigned long address; +}; + +struct module_sect_attrs_2_6_27 +{ + struct attribute_group_2_6_27 grp; + unsigned int nsections; + struct module_sect_attr_2_6_27 attrs[0]; +}; + +struct module +{ + CORE_ADDR unused_state; + struct list_head list; + char name[MODULE_NAME_LEN]; +}; + +struct kern_lm_info { + unsigned int nsections; + struct module_sect_attr module_sect_attr[0]; +}; + +#define OFFSET(structure, field) ((CORE_ADDR)(&((struct structure *)0)->field)) + +/* local data declarations */ + /* link map access functions */ static CORE_ADDR @@ -714,10 +824,18 @@ struct so_list **link_ptr = &head; CORE_ADDR ldsomap = 0; + if (debugkernel) + { + return kernel_current_sos(); + } + /* Always locate the debug struct, in case it has moved. */ debug_base = 0; locate_base (); + /* Make sure we've looked up the inferior's dynamic linker's base + structure. */ + /* If we can't find the dynamic linker's base structure, this must not be a dynamically linked executable. Hmm. */ if (! debug_base) @@ -1411,6 +1529,11 @@ if (!enable_break ()) return; + if (debugkernel) + { + solib_add (NULL, 0, NULL, 1); + } + #if defined(_SCO_DS) /* SCO needs the loop below, other systems should be using the special shared library breakpoints and the shared library breakpoint @@ -1481,10 +1604,32 @@ svr4_relocate_section_addresses (struct so_list *so, struct section_table *sec) { - sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so, - sec->bfd)); - sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR_CHECK (so, - sec->bfd)); + if (debugkernel) + { + int i; + struct kern_lm_info *kern_lm_info = + (struct kern_lm_info *)so->lm_info->lm; + for (i = 0; i < kern_lm_info->nsections; i++) + { + if (!strcmp(kern_lm_info->module_sect_attr[i].name, + sec->the_bfd_section->name)) + { + CORE_ADDR sect_addr = extract_typed_address( + (gdb_byte *)&kern_lm_info->module_sect_attr[i].address, + builtin_type_void_data_ptr); + sec->addr = sec->addr + sect_addr; + sec->endaddr = sec->endaddr + sect_addr; + break; + } + } + } + else + { + sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so, + sec->bfd)); + sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR_CHECK (so, + sec->bfd)); + } } @@ -1670,4 +1815,152 @@ svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code; svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; svr4_so_ops.same = svr4_same; + + /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ + current_target_so_ops = &svr4_so_ops; } + +/* Scans the list of modules in a kernel and finds out section addresses for + * those symbols */ +static struct so_list *kernel_current_sos(void) +{ + enum kversion {v2_6_18, v2_6_27}; + short n; + struct expression *expr; + struct value *val; + unsigned int offset_sect_attrs; + enum kversion kv; + struct symbol *modules; + CORE_ADDR modlistaddr; + CORE_ADDR modnameaddr; + struct so_list *head = 0; + struct so_list **link_ptr = &head; + + expr = parse_expression("&((struct module *)0)->sect_attrs"); + val = evaluate_expression(expr); + offset_sect_attrs = val->aligner.force_longest_align; + expr = parse_expression("&((struct module_sect_attrs *)0)->attrs[1]"); + val = evaluate_expression(expr); + if (val->aligner.force_longest_align == (int)&((struct module_sect_attrs *)0)->attrs[1]) { + kv = v2_6_18; + } else if (val->aligner.force_longest_align == + (int)&((struct module_sect_attrs_2_6_27 *)0)->attrs[1]) { + kv = v2_6_27; + } else { + warning("struct module_sect_attrs is not the one of v2_6_18 nor v2_6_27"); + goto nolist; + } + + modules = lookup_symbol("modules", NULL, VAR_DOMAIN, NULL, NULL); + if (modules == NULL) + goto nolist; + + /* Pointer to first module */ + modlistaddr = read_memory_typed_address(SYMBOL_VALUE_ADDRESS(modules), + builtin_type_void_data_ptr); + while (modlistaddr != SYMBOL_VALUE_ADDRESS(modules)) { + struct so_list *new = (struct so_list *) xmalloc (sizeof (struct so_list)); + struct cleanup *old_chain = make_cleanup (xfree, new); + char *buffer; + int errcode; + CORE_ADDR mod_struct_addr; + CORE_ADDR mod_addr_sections; + struct kern_lm_info *kern_lm_info; + unsigned int nsections; + struct module_sect_attr_2_6_27 *attr_2_6_27; + + memset (new, 0, sizeof (*new)); + + mod_struct_addr = modlistaddr - OFFSET(module, list); + + /* Read module name */ + target_read_string(mod_struct_addr + OFFSET(module, name), &buffer, + MODULE_NAME_LEN, &errcode); + if (errcode || !strlen(buffer)) + { + warning("Couldn't read module name"); + do_cleanups (old_chain); + goto next_mod; + } + strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); + new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; + strcpy (new->so_original_name, new->so_name); + new->next = 0; + + new->lm_info = xmalloc(sizeof (struct lm_info)); + make_cleanup(xfree, new->lm_info); + + mod_addr_sections = read_memory_typed_address(mod_struct_addr + offset_sect_attrs, + builtin_type_void_data_ptr); + switch (kv) { + case v2_6_18: + new->lm_info->lm = xmalloc(sizeof(struct kern_lm_info) + + sizeof(struct module_sect_attr) * + NUM_SECTIONS); + make_cleanup(xfree, new->lm_info->lm); + kern_lm_info = (struct kern_lm_info *)new->lm_info->lm; + kern_lm_info->nsections = NUM_SECTIONS; + if (target_read_memory(mod_addr_sections + OFFSET(module_sect_attrs, attrs), + (char *)kern_lm_info->module_sect_attr, + sizeof(struct module_sect_attr) * NUM_SECTIONS) != 0) { + warning("can't read module_sects in module %s", new->so_name); + do_cleanups(old_chain); + goto next_mod; + } + if (strcmp(kern_lm_info->module_sect_attr[0].name, ".text") != 0) { + warning("The first section is not .text: %s", kern_lm_info->module_sect_attr[0].name); + do_cleanups(old_chain); + goto next_mod; + } + break; + case v2_6_27: + nsections = read_memory_unsigned_integer(mod_addr_sections + + OFFSET(module_sect_attrs_2_6_27, nsections), + sizeof(nsections)); + new->lm_info->lm = xmalloc(sizeof(struct kern_lm_info) + + sizeof(struct module_sect_attr) * + nsections); + make_cleanup(xfree, new->lm_info->lm); + kern_lm_info = (struct kern_lm_info *)new->lm_info->lm; + attr_2_6_27 = (struct module_sect_attr_2_6_27 *)malloc( + sizeof(*attr_2_6_27) * + nsections); + memset(attr_2_6_27, 0, sizeof(*attr_2_6_27) * nsections); + if (target_read_memory(mod_addr_sections + OFFSET(module_sect_attrs_2_6_27, attrs), + (char *)attr_2_6_27, + sizeof(*attr_2_6_27) * nsections) != 0) { + warning("can't read attr_attr_2_6_27 in module %s for v2_6_27", new->so_name); + do_cleanups(old_chain); + goto next_mod; + } + for (n = 0; n < nsections; n++) { + if (target_read_memory((CORE_ADDR)attr_2_6_27[n].name, + kern_lm_info->module_sect_attr[n].name, + MODULE_SECT_NAME_LEN) != 0) { + warning("can't read attr_attr_2_6_27 in module %s for v2_6_27", new->so_name); + do_cleanups(old_chain); + goto next_mod; + } + kern_lm_info->module_sect_attr[n].name[MODULE_SECT_NAME_LEN - 1] = '\0'; + kern_lm_info->module_sect_attr[n].address = attr_2_6_27[n].address; + } + kern_lm_info->nsections = nsections; + free(attr_2_6_27); + break; + } + *link_ptr = new; + link_ptr = &new->next; + if (strlen(new->so_name) <= SO_NAME_MAX_PATH_SIZE - 2) { + strcat(new->so_name, ".ko"); + } + xfree(buffer); + discard_cleanups(old_chain); + + next_mod: + modlistaddr = read_memory_typed_address(modlistaddr, builtin_type_void_data_ptr); + } + return head; + + nolist: + return NULL; +} Index: gdb/ada-lang.c =================================================================== --- gdb/ada-lang.c (revision 4) +++ gdb/ada-lang.c (working copy) @@ -3834,7 +3834,7 @@ /* The following is taken from the structure-return code in call_function_by_hand. FIXME: Therefore, some refactoring seems indicated. */ - if (gdbarch_inner_than (current_gdbarch, 1, 2)) + if (gdbarch_inner_than(current_gdbarch, 1, 2, 0, 0)) { /* Stack grows downward. Align SP and VALUE_ADDRESS (val) after reserving sufficient space. */ Index: gdb/value.c =================================================================== --- gdb/value.c (revision 4) +++ gdb/value.c (working copy) @@ -40,142 +40,6 @@ void _initialize_values (void); -struct value -{ - /* Type of value; either not an lval, or one of the various - different possible kinds of lval. */ - enum lval_type lval; - - /* Is it modifiable? Only relevant if lval != not_lval. */ - int modifiable; - - /* Location of value (if lval). */ - union - { - /* If lval == lval_memory, this is the address in the inferior. - If lval == lval_register, this is the byte offset into the - registers structure. */ - CORE_ADDR address; - - /* Pointer to internal variable. */ - struct internalvar *internalvar; - } location; - - /* Describes offset of a value within lval of a structure in bytes. - If lval == lval_memory, this is an offset to the address. If - lval == lval_register, this is a further offset from - location.address within the registers structure. Note also the - member embedded_offset below. */ - int offset; - - /* Only used for bitfields; number of bits contained in them. */ - int bitsize; - - /* Only used for bitfields; position of start of field. For - gdbarch_bits_big_endian=0 targets, it is the position of the LSB. For - gdbarch_bits_big_endian=1 targets, it is the position of the MSB. */ - int bitpos; - - /* Frame register value is relative to. This will be described in - the lval enum above as "lval_register". */ - struct frame_id frame_id; - - /* Type of the value. */ - struct type *type; - - /* If a value represents a C++ object, then the `type' field gives - the object's compile-time type. If the object actually belongs - to some class derived from `type', perhaps with other base - classes and additional members, then `type' is just a subobject - of the real thing, and the full object is probably larger than - `type' would suggest. - - If `type' is a dynamic class (i.e. one with a vtable), then GDB - can actually determine the object's run-time type by looking at - the run-time type information in the vtable. When this - information is available, we may elect to read in the entire - object, for several reasons: - - - When printing the value, the user would probably rather see the - full object, not just the limited portion apparent from the - compile-time type. - - - If `type' has virtual base classes, then even printing `type' - alone may require reaching outside the `type' portion of the - object to wherever the virtual base class has been stored. - - When we store the entire object, `enclosing_type' is the run-time - type -- the complete object -- and `embedded_offset' is the - offset of `type' within that larger type, in bytes. The - value_contents() macro takes `embedded_offset' into account, so - most GDB code continues to see the `type' portion of the value, - just as the inferior would. - - If `type' is a pointer to an object, then `enclosing_type' is a - pointer to the object's run-time type, and `pointed_to_offset' is - the offset in bytes from the full object to the pointed-to object - -- that is, the value `embedded_offset' would have if we followed - the pointer and fetched the complete object. (I don't really see - the point. Why not just determine the run-time type when you - indirect, and avoid the special case? The contents don't matter - until you indirect anyway.) - - If we're not doing anything fancy, `enclosing_type' is equal to - `type', and `embedded_offset' is zero, so everything works - normally. */ - struct type *enclosing_type; - int embedded_offset; - int pointed_to_offset; - - /* Values are stored in a chain, so that they can be deleted easily - over calls to the inferior. Values assigned to internal - variables or put into the value history are taken off this - list. */ - struct value *next; - - /* Register number if the value is from a register. */ - short regnum; - - /* If zero, contents of this value are in the contents field. If - nonzero, contents are in inferior memory at address in the - location.address field plus the offset field (and the lval field - should be lval_memory). - - WARNING: This field is used by the code which handles watchpoints - (see breakpoint.c) to decide whether a particular value can be - watched by hardware watchpoints. If the lazy flag is set for - some member of a value chain, it is assumed that this member of - the chain doesn't need to be watched as part of watching the - value itself. This is how GDB avoids watching the entire struct - or array when the user wants to watch a single struct member or - array element. If you ever change the way lazy flag is set and - reset, be sure to consider this use as well! */ - char lazy; - - /* If nonzero, this is the value of a variable which does not - actually exist in the program. */ - char optimized_out; - - /* If value is a variable, is it initialized or not. */ - int initialized; - - /* Actual contents of the value. For use of this value; setting it - uses the stuff above. Not valid if lazy is nonzero. Target - byte-order. We force it to be aligned properly for any possible - value. Note that a value therefore extends beyond what is - declared here. */ - union - { - gdb_byte contents[1]; - DOUBLEST force_doublest_align; - LONGEST force_longest_align; - CORE_ADDR force_core_addr_align; - void *force_pointer_align; - } aligner; - /* Do not add any new members here -- contents above will trash - them. */ -}; - /* Prototypes for local functions. */ static void show_values (char *, int); Index: gdb/value.h =================================================================== --- gdb/value.h (revision 4) +++ gdb/value.h (working copy) @@ -554,4 +554,140 @@ extern struct value *value_of_local (const char *name, int complain); +struct value +{ + /* Type of value; either not an lval, or one of the various + different possible kinds of lval. */ + enum lval_type lval; + + /* Is it modifiable? Only relevant if lval != not_lval. */ + int modifiable; + + /* Location of value (if lval). */ + union + { + /* If lval == lval_memory, this is the address in the inferior. + If lval == lval_register, this is the byte offset into the + registers structure. */ + CORE_ADDR address; + + /* Pointer to internal variable. */ + struct internalvar *internalvar; + } location; + + /* Describes offset of a value within lval of a structure in bytes. + If lval == lval_memory, this is an offset to the address. If + lval == lval_register, this is a further offset from + location.address within the registers structure. Note also the + member embedded_offset below. */ + int offset; + + /* Only used for bitfields; number of bits contained in them. */ + int bitsize; + + /* Only used for bitfields; position of start of field. For + gdbarch_bits_big_endian=0 targets, it is the position of the LSB. For + gdbarch_bits_big_endian=1 targets, it is the position of the MSB. */ + int bitpos; + + /* Frame register value is relative to. This will be described in + the lval enum above as "lval_register". */ + struct frame_id frame_id; + + /* Type of the value. */ + struct type *type; + + /* If a value represents a C++ object, then the `type' field gives + the object's compile-time type. If the object actually belongs + to some class derived from `type', perhaps with other base + classes and additional members, then `type' is just a subobject + of the real thing, and the full object is probably larger than + `type' would suggest. + + If `type' is a dynamic class (i.e. one with a vtable), then GDB + can actually determine the object's run-time type by looking at + the run-time type information in the vtable. When this + information is available, we may elect to read in the entire + object, for several reasons: + + - When printing the value, the user would probably rather see the + full object, not just the limited portion apparent from the + compile-time type. + + - If `type' has virtual base classes, then even printing `type' + alone may require reaching outside the `type' portion of the + object to wherever the virtual base class has been stored. + + When we store the entire object, `enclosing_type' is the run-time + type -- the complete object -- and `embedded_offset' is the + offset of `type' within that larger type, in bytes. The + value_contents() macro takes `embedded_offset' into account, so + most GDB code continues to see the `type' portion of the value, + just as the inferior would. + + If `type' is a pointer to an object, then `enclosing_type' is a + pointer to the object's run-time type, and `pointed_to_offset' is + the offset in bytes from the full object to the pointed-to object + -- that is, the value `embedded_offset' would have if we followed + the pointer and fetched the complete object. (I don't really see + the point. Why not just determine the run-time type when you + indirect, and avoid the special case? The contents don't matter + until you indirect anyway.) + + If we're not doing anything fancy, `enclosing_type' is equal to + `type', and `embedded_offset' is zero, so everything works + normally. */ + struct type *enclosing_type; + int embedded_offset; + int pointed_to_offset; + + /* Values are stored in a chain, so that they can be deleted easily + over calls to the inferior. Values assigned to internal + variables or put into the value history are taken off this + list. */ + struct value *next; + + /* Register number if the value is from a register. */ + short regnum; + + /* If zero, contents of this value are in the contents field. If + nonzero, contents are in inferior memory at address in the + location.address field plus the offset field (and the lval field + should be lval_memory). + + WARNING: This field is used by the code which handles watchpoints + (see breakpoint.c) to decide whether a particular value can be + watched by hardware watchpoints. If the lazy flag is set for + some member of a value chain, it is assumed that this member of + the chain doesn't need to be watched as part of watching the + value itself. This is how GDB avoids watching the entire struct + or array when the user wants to watch a single struct member or + array element. If you ever change the way lazy flag is set and + reset, be sure to consider this use as well! */ + char lazy; + + /* If nonzero, this is the value of a variable which does not + actually exist in the program. */ + char optimized_out; + + /* If value is a variable, is it initialized or not. */ + int initialized; + + /* Actual contents of the value. For use of this value; setting it + uses the stuff above. Not valid if lazy is nonzero. Target + byte-order. We force it to be aligned properly for any possible + value. Note that a value therefore extends beyond what is + declared here. */ + union + { + gdb_byte contents[1]; + DOUBLEST force_doublest_align; + LONGEST force_longest_align; + CORE_ADDR force_core_addr_align; + void *force_pointer_align; + } aligner; + /* Do not add any new members here -- contents above will trash + them. */ +}; + #endif /* !defined (VALUE_H) */ Index: gdb/infcall.c =================================================================== --- gdb/infcall.c (revision 4) +++ gdb/infcall.c (working copy) @@ -283,7 +283,7 @@ sp = gdbarch_frame_align (gdbarch, sp); /* Allocate space for, and then position the breakpoint on the stack. */ - if (gdbarch_inner_than (gdbarch, 1, 2)) + if (gdbarch_inner_than (gdbarch, 1, 2, 0, 0)) { CORE_ADDR bppc = sp; gdbarch_breakpoint_from_pc (gdbarch, &bppc, &bplen); @@ -407,7 +407,7 @@ address. AMD64 called that region the "red zone". Skip at least the "red zone" size before allocating any space on the stack. */ - if (gdbarch_inner_than (gdbarch, 1, 2)) + if (gdbarch_inner_than (gdbarch, 1, 2, 0, 0)) sp -= gdbarch_frame_red_zone_size (gdbarch); else sp += gdbarch_frame_red_zone_size (gdbarch); @@ -435,16 +435,16 @@ to pay :-). */ if (sp == old_sp) { - if (gdbarch_inner_than (gdbarch, 1, 2)) + if (gdbarch_inner_than (gdbarch, 1, 2, 0, 0)) /* Stack grows down. */ sp = gdbarch_frame_align (gdbarch, old_sp - 1); else /* Stack grows up. */ sp = gdbarch_frame_align (gdbarch, old_sp + 1); } - gdb_assert ((gdbarch_inner_than (gdbarch, 1, 2) + gdb_assert ((gdbarch_inner_than (gdbarch, 1, 2, 0, 0) && sp <= old_sp) - || (gdbarch_inner_than (gdbarch, 2, 1) + || (gdbarch_inner_than (gdbarch, 2, 1, 0, 0) && sp >= old_sp)); } else @@ -505,7 +505,7 @@ case ON_STACK: /* "dummy_addr" is here just to keep old targets happy. New targets return that same information via "sp" and "bp_addr". */ - if (gdbarch_inner_than (gdbarch, 1, 2)) + if (gdbarch_inner_than (gdbarch, 1, 2, 0, 0)) { sp = push_dummy_code (gdbarch, sp, funaddr, args, nargs, target_values_type, @@ -598,7 +598,7 @@ if (struct_return || lang_struct_return) { int len = TYPE_LENGTH (values_type); - if (gdbarch_inner_than (gdbarch, 1, 2)) + if (gdbarch_inner_than (gdbarch, 1, 2, 0, 0)) { /* Stack grows downward. Align STRUCT_ADDR and SP after making space for the return value. */ Index: gdb/gdbarch.c =================================================================== --- gdb/gdbarch.c (revision 4) +++ gdb/gdbarch.c (working copy) @@ -542,8 +542,7 @@ /* Skip verify of return_value, has predicate */ if (gdbarch->skip_prologue == 0) fprintf_unfiltered (log, "\n\tskip_prologue"); - if (gdbarch->inner_than == 0) - fprintf_unfiltered (log, "\n\tinner_than"); + /* Skip verify of inner_than */ if (gdbarch->breakpoint_from_pc == 0) fprintf_unfiltered (log, "\n\tbreakpoint_from_pc"); /* Skip verify of adjust_breakpoint_address, has predicate */ @@ -781,6 +780,10 @@ "gdbarch_dump: in_solib_return_trampoline = <0x%lx>\n", (long) gdbarch->in_solib_return_trampoline); fprintf_unfiltered (file, + "gdbarch_dump: %s # %s\n", + "INNER_THAN(lhs, rhs)", + XSTRING (INNER_THAN (lhs, rhs, 0, 0))); + fprintf_unfiltered (file, "gdbarch_dump: inner_than = <0x%lx>\n", (long) gdbarch->inner_than); fprintf_unfiltered (file, @@ -2075,13 +2078,14 @@ } int -gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs) +gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhsf, CORE_ADDR rhsf, + CORE_ADDR lhsc, CORE_ADDR rhsc) { gdb_assert (gdbarch != NULL); gdb_assert (gdbarch->inner_than != NULL); if (gdbarch_debug >= 2) fprintf_unfiltered (gdb_stdlog, "gdbarch_inner_than called\n"); - return gdbarch->inner_than (lhs, rhs); + return gdbarch->inner_than (lhsf, rhsf, lhsc, rhsc); } void Index: gdb/gdbarch.h =================================================================== --- gdb/gdbarch.h (revision 4) +++ gdb/gdbarch.h (working copy) @@ -374,8 +374,10 @@ extern CORE_ADDR gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip); extern void set_gdbarch_skip_prologue (struct gdbarch *gdbarch, gdbarch_skip_prologue_ftype *skip_prologue); -typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs); -extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs); +typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhsf, CORE_ADDR rhsf, + CORE_ADDR lhsc, CORE_ADDR rhsc); +extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhsf, + CORE_ADDR rhsf, CORE_ADDR lhsc, CORE_ADDR rhsc); extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than); typedef const gdb_byte * (gdbarch_breakpoint_from_pc_ftype) (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr); Index: gdb/amd64-linux-tdep.c =================================================================== --- gdb/amd64-linux-tdep.c (revision 4) +++ gdb/amd64-linux-tdep.c (working copy) @@ -3,6 +3,7 @@ Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Contributed by Jiri Smid, SuSE Labs. + Copyright 2004 LinSysSoft Technologies Pvt. Ltd. This file is part of GDB. @@ -288,6 +289,23 @@ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); } + +static void +amd64_linux_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* We can use the register offsets used for linux applications. Only + * first 18 elements of the array will be used for kernel. Offsets of those + * are identical for applications and kernel. */ + tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset; + tdep->gregset_num_regs = AMD64_NUM_GREGS; + tdep->sizeof_gregset = AMD64_NUM_GREGS * 8; + + amd64_init_abi (info, gdbarch); + +} + /* Provide a prototype to silence -Wmissing-prototypes. */ @@ -298,4 +316,6 @@ { gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_LINUX, amd64_linux_init_abi); + gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, + GDB_OSABI_LINUX_KERNEL, amd64_linux_kernel_init_abi); } Index: gdb/symfile.c =================================================================== --- gdb/symfile.c (revision 4) +++ gdb/symfile.c (working copy) @@ -971,6 +971,10 @@ void new_symfile_objfile (struct objfile *objfile, int mainline, int verbo) { + char *filename; + struct symbol *sym; + char *dir; + extern int debugkernel; /* If this is the main symbol file we have to clean up all users of the old main symbol file. Otherwise it is sufficient to fixup all the @@ -980,6 +984,17 @@ /* OK, make it the "real" symbol file. */ symfile_objfile = objfile; + debugkernel = 0; + filename = symfile_objfile->name; + while ((dir = strchr(filename, '/')) != NULL) + filename = dir + 1; + /* only require the given characters to match, so that longer filenames will still match */ + if (!strncmp(filename, LINUX_KERNEL_NAME_STEM, strlen(LINUX_KERNEL_NAME_STEM))) + { + sym = lookup_symbol ("start_kernel", NULL, VAR_DOMAIN, NULL, NULL); + if (sym) + debugkernel = 1; + } clear_symtab_users (); } else Index: gdb/solib.c =================================================================== --- gdb/solib.c (revision 4) +++ gdb/solib.c (working copy) @@ -44,6 +44,7 @@ #include "solist.h" #include "observer.h" #include "readline/readline.h" +#include /* Architecture-specific operations. */ @@ -78,6 +79,7 @@ /* external data declarations */ +extern int debugkernel; /* FIXME: gdbarch needs to control this variable, or else every configuration needs to call set_solib_ops. */ @@ -102,6 +104,172 @@ value); } +/* Return True if the file NAME exists and is a regular file */ +static int +is_regular_file (const char *name) +{ + struct stat st; + const int status = stat (name, &st); + + /* Stat should never fail except when the file does not exist. + If stat fails, analyze the source of error and return True + unless the file does not exist, to avoid returning false results + on obscure systems where stat does not work as expected. + */ + if (status != 0) + return (errno != ENOENT); + + return S_ISREG (st.st_mode); +} + +/* Open a file named STRING, searching path PATH (dir names sep by some char) + using mode MODE and protection bits PROT in the calls to open. + + If TRY_CWD_FIRST, try to open ./STRING before searching PATH. + (ie pretend the first element of PATH is "."). This also indicates + that a slash in STRING disables searching of the path (this is + so that "exec-file ./foo" or "symbol-file ./foo" insures that you + get that particular version of foo or an error message). + + If FILENAME_OPENED is non-null, set it to a newly allocated string naming + the actual file opened (this string will always start with a "/"). We + have to take special pains to avoid doubling the "/" between the directory + and the file, sigh! Emacs gets confuzzed by this when we print the + source file name!!! + + If a file is found, return the descriptor. + Otherwise, return -1, with errno set for the last name we tried to open. */ + +/* >>>> This should only allow files of certain types, + >>>> eg executable, non-directory */ +static int +module_openp (const char *path, int try_cwd_first, const char *string, + int mode, int prot, + char **filename_opened) +{ + register int fd; + register char *filename; + const char *p; + const char *p1; + register int len; + int alloclen; + int uscount; + const char *fnptr; + char *fnptr2; + glob_t globbuf; + + if (!path) + path = "."; + +#if defined(_WIN32) || defined(__CYGWIN__) + mode |= O_BINARY; +#endif + + /* ./foo => foo */ + while (string[0] == '.' && IS_DIR_SEPARATOR (string[1])) + string += 2; + + for (uscount = 0, fnptr = string; *fnptr; fnptr++) + if(*fnptr== '_') + uscount++; + alloclen = strlen (path) + strlen (string) + 2 + uscount * 4; + filename = alloca (alloclen); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = strchr (p, DIRNAME_SEPARATOR); + if (p1) + len = p1 - p; + else + len = strlen (p); + + if (len == 4 && p[0] == '$' && p[1] == 'c' + && p[2] == 'w' && p[3] == 'd') + { + /* Name is $cwd -- insert current directory name instead. */ + int newlen; + + /* First, realloc the filename buffer if too short. */ + len = strlen (current_directory); + newlen = len + strlen (string) + 2; + if (newlen > alloclen) + { + alloclen = newlen; + filename = alloca (alloclen); + } + strcpy (filename, current_directory); + } + else + { + /* Normal file name in path -- just use it. */ + strncpy (filename, p, len); + filename[len] = 0; + } + + /* Remove trailing slashes */ + while (len > 0 && IS_DIR_SEPARATOR (filename[len - 1])) + filename[--len] = 0; + + strcat (filename + len, SLASH_STRING); + fnptr2 = filename + strlen(filename); + for (uscount = 0, fnptr = string; ;fnptr++) + { + if(*fnptr== '_') + { + *(fnptr2++) = '['; + *(fnptr2++) = '_'; + *(fnptr2++) = '-'; + *(fnptr2++) = ']'; + } + else + { + *(fnptr2++) = *fnptr; + if (!*fnptr) + break; + } + } + globbuf.gl_offs = 0; + glob(filename, GLOB_DOOFFS, NULL, &globbuf); + if (!globbuf.gl_pathv[0]) + continue; + + strcpy(filename, globbuf.gl_pathv[0]); + if (is_regular_file (filename)) + { + fd = open (filename, mode); + if (fd >= 0) + break; + } + } + + if (filename_opened) + { + /* If a file was opened, canonicalize its filename. Use xfullpath + rather than gdb_realpath to avoid resolving the basename part + of filenames when the associated file is a symbolic link. This + fixes a potential inconsistency between the filenames known to + GDB and the filenames it prints in the annotations. */ + if (fd < 0) + *filename_opened = NULL; + else if (IS_ABSOLUTE_PATH (filename)) + *filename_opened = xfullpath (filename); + else + { + /* Beware the // my son, the Emacs barfs, the botch that catch... */ + + char *f = concat (current_directory, + IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]) + ? "" : SLASH_STRING, + filename, NULL); + *filename_opened = xfullpath (f); + xfree (f); + } + } + + return fd; +} + + /* GLOBAL FUNCTION @@ -201,6 +369,12 @@ if (found_file < 0 && solib_search_path != NULL) found_file = openp (solib_search_path, OPF_TRY_CWD_FIRST, in_pathname, O_RDONLY | O_BINARY, 0, &temp_pathname); + + /* If not found and debugging a kernel, try _ and - changes */ + if (found_file < 0 && solib_search_path != NULL && debugkernel) { + found_file = module_openp(solib_search_path, + 1, in_pathname, O_RDONLY, 0, &temp_pathname); + } /* If not found, next search the solib_search_path (if any) for the basename only (ignoring the path). This is to allow reading solibs from a path @@ -419,7 +593,7 @@ so->sections_end); so->objfile = symbol_file_add (so->so_name, so->from_tty, - sap, 0, OBJF_SHARED); + sap, 0, OBJF_SHARED | (debugkernel ? OBJF_READNOW : 0)); free_section_addr_info (sap); return (1); @@ -625,6 +799,7 @@ /* Notify any observer that the shared object has been loaded now that we've added it to GDB's tables. */ observer_notify_solib_loaded (i); + solib_read_symbols (i, from_tty); } } } Index: gdb/i386-linux-tdep.c =================================================================== --- gdb/i386-linux-tdep.c (revision 4) +++ gdb/i386-linux-tdep.c (working copy) @@ -2,6 +2,7 @@ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc. + Copyright 2004 LinSysSoft Technologies Pvt. Ltd. This file is part of GDB. @@ -28,12 +29,15 @@ #include "reggroups.h" #include "dwarf2-frame.h" #include "gdb_string.h" +#include "elf-bfd.h" #include "i386-tdep.h" #include "i386-linux-tdep.h" #include "glibc-tdep.h" #include "solib-svr4.h" #include "symtab.h" +#include "arch-utils.h" +#include "gdbarch.h" /* Return the name of register REG. */ @@ -402,6 +406,39 @@ 0 * 4 /* %gs */ }; +int i386_inner_than (CORE_ADDR lhsf, CORE_ADDR rhsf, CORE_ADDR lhsc, + CORE_ADDR rhsc) +{ + /* Read code at rhsc, if it contains a stack switch instruction, return + * true. We check for 4 instructions. + * 89C4 mov eax, esp + * 89DC mov ebx, esp + * 89CC mov ecx, esp + * 89D4 mov edx, esp + * 94 xchg eax, esp + * 87DC xchg ebx, esp + * 87CC xchg ecx, esp + * 87D4 xchg edx, esp + */ + unsigned short twobyte_insns[] = { 0x89c4, 0x89dc, 0x89cc, 0x89d4, 0x87dc, + 0x87dc, 0x87cc, 0x87d4 }; + unsigned char onebyte_insns[] = { 0x94 }; + unsigned short tmp; + int i; + + if (rhsc && + target_read_memory(rhsc, (gdb_byte *)&tmp, sizeof(unsigned short)) == 0) + { + for (i = 0; i < sizeof(onebyte_insns); i++) + if (onebyte_insns[i] == (unsigned char)tmp) + return 0; + for (i = 0; i < sizeof(twobyte_insns); i++) + if (twobyte_insns[i] == tmp) + return 0; + } + return core_addr_lessthan(lhsf, rhsf, lhsc, rhsc); +} + static void i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -446,8 +483,32 @@ /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, i386_inner_than); } +static void +i386_linux_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* Linux Kernel uses ELF format for vmlinux file. */ + i386_elf_init_abi (info, gdbarch); + + /* We can use the register offsets used for linux applications. Only + * first 16 elements of the array will be used for kernel. Offsets of those + * are identical for applications and kernel. */ + tdep->gregset_reg_offset = i386_linux_gregset_reg_offset; + tdep->gregset_num_regs = I386_NUM_GREGS; + tdep->sizeof_gregset = I386_NUM_GREGS * 4; + + tdep->jb_pc_offset = 20; /* From . */ + + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, i386_inner_than); +} + /* Provide a prototype to silence -Wmissing-prototypes. */ extern void _initialize_i386_linux_tdep (void); @@ -456,4 +517,7 @@ { gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX, i386_linux_init_abi); + gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX_KERNEL, + i386_linux_kernel_init_abi); + } Index: gdb/frame.c =================================================================== --- gdb/frame.c (revision 4) +++ gdb/frame.c (working copy) @@ -380,7 +380,8 @@ comment in "frame.h", there is some fuzz here. Frameless functions are not strictly inner than (same .stack but different .code and/or .special address). */ - inner = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr); + inner = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr, + l.code_addr, r.code_addr); if (frame_debug) { fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l="); Index: gdb/arch-utils.c =================================================================== --- gdb/arch-utils.c (revision 4) +++ gdb/arch-utils.c (working copy) @@ -80,9 +80,10 @@ /* Helper functions for gdbarch_inner_than */ int -core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs) +core_addr_lessthan (CORE_ADDR lhsf, CORE_ADDR rhsf, CORE_ADDR lhsc, + CORE_ADDR rhsc) { - return (lhs < rhs); + return (lhsf < rhsf); } int Index: gdb/arch-utils.h =================================================================== --- gdb/arch-utils.h (revision 4) +++ gdb/arch-utils.h (working copy) @@ -31,7 +31,8 @@ extern int gdbarch_debug; /* The only possible cases for inner_than. */ -extern int core_addr_lessthan (CORE_ADDR lhs, CORE_ADDR rhs); +extern int core_addr_lessthan (CORE_ADDR lhsf, CORE_ADDR rhsf, + CORE_ADDR lhsc, CORE_ADDR rhsc); extern int core_addr_greaterthan (CORE_ADDR lhs, CORE_ADDR rhs); /* Identity functions on a CORE_ADDR. Just return the "addr". */ Index: gdb/osabi.c =================================================================== --- gdb/osabi.c (revision 4) +++ gdb/osabi.c (working copy) @@ -56,6 +56,7 @@ "Solaris", "OSF/1", "GNU/Linux", + "Linux-kernel", "FreeBSD a.out", "FreeBSD ELF", "NetBSD a.out", Index: gdb/gcore.c =================================================================== --- gdb/gcore.c (revision 4) +++ gdb/gcore.c (working copy) @@ -184,7 +184,8 @@ /* Save frame pointer of TOS frame. */ *top = get_frame_base (fi); /* If current stack pointer is more "inner", use that instead. */ - if (gdbarch_inner_than (get_frame_arch (fi), get_frame_sp (fi), *top)) + if (gdbarch_inner_than (get_frame_arch (fi), get_frame_sp (fi), + *top, (CORE_ADDR)NULL, (CORE_ADDR)NULL)) *top = get_frame_sp (fi); /* Find prev-most frame. */ Index: gdb/defs.h =================================================================== --- gdb/defs.h (revision 4) +++ gdb/defs.h (working copy) @@ -918,6 +918,7 @@ GDB_OSABI_SOLARIS, GDB_OSABI_OSF1, GDB_OSABI_LINUX, + GDB_OSABI_LINUX_KERNEL, GDB_OSABI_FREEBSD_AOUT, GDB_OSABI_FREEBSD_ELF, GDB_OSABI_NETBSD_AOUT, @@ -1182,6 +1183,7 @@ extern ULONGEST align_up (ULONGEST v, int n); extern ULONGEST align_down (ULONGEST v, int n); +#define LINUX_KERNEL_NAME_STEM "vmlinux" /* Allocation and deallocation functions for the libiberty hash table which use obstacks. */