RE: symbolic debug of loadable modules with kgdb light

Caz Yokoyama
2009-01-09T14:52:44Z

[-- Attachment #1: Type: text/plain, Size: 1052 bytes --]

Hello,
I have attached the patch against gdb-6.8.
- This patch is based on http://kgdb.cvs.sourceforge.net/viewvc/kgdb/gdb/. I
removed garbage as mush as possible. But it still has the code which I don't
know what it is. I don't remove copyright notice which is there.
- I haven't run testsuite because I could not find how to do that while I
run make in testsuite directory.
- I believe that the code follows coding standard. Let me know if not.
- The patch is produced by "svn diff". I believe patch format is the one you
want. Let me know if not.
-caz

-----Original Message-----
From: Joel Brobecker [mailto:brobecker@adacore.com]
Sent: Thursday, January 08, 2009 8:18 PM
To: Caz Yokoyama
Cc: gdb@sourceware.org
Subject: Re: symbolic debug of loadable modules with kgdb light

> Is there anyway to integrate my modifications to gdb?

We indeed welcome contributes. Hopefully most of your questions
will be answered by a file called CONTRIBUTE in the gdb/ subdirectory.
Could you have a look and let us know if some things are not clear?

--
Joel

[-- Attachment #2: gdb-6.8-KgdbLight.patch --]
[-- Type: application/octet-stream, Size: 49662 bytes --]

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 <caz@caztech.com>
+
+ * 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));
+ }
}
\f

@@ -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);
+
+}
+
\f

/* 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 <glob.h>

/* Architecture-specific operations. */

@@ -78,6 +79,7 @@
\f

/* 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 <bits/setjmp.h>. */
+
+ /* 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. */