From e2502c6d8ff9edd57b706657ab12df32c8b41514 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 8 Apr 2008 13:50:52 +0200 Subject: bugfix: imklog did not work well with kernel 2.6+. Thanks to Peter Vrabec for patching it based on the development in sysklogd - and thanks to the sysklogd project for upgrading klogd to support the new functionality. --- ChangeLog | 4 + plugins/imklog/ksym.c | 94 ++++--- plugins/imklog/ksym_mod.c | 644 ++++++++++++++++++++-------------------------- plugins/imklog/module.h | 59 +---- 4 files changed, 349 insertions(+), 452 deletions(-) diff --git a/ChangeLog b/ChangeLog index 092067ae..2e1b28e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,10 @@ Version 3.14.2 (rgerhards), 2008-04-?? - bugfix: segfault with expression-based filters - bugfix: omsnmp did not deref errmsg object on exit (no bad effects caused) - some cleanup +- bugfix: imklog did not work well with kernel 2.6+. Thanks to Peter + Vrabec for patching it based on the development in sysklogd - and thanks + to the sysklogd project for upgrading klogd to support the new + functionality --------------------------------------------------------------------------- Version 3.14.1 (rgerhards), 2008-04-04 - bugfix: some messages were emited without hostname diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c index c9fd7147..4fa2fbb6 100644 --- a/plugins/imklog/ksym.c +++ b/plugins/imklog/ksym.c @@ -120,16 +120,10 @@ #include #include "imklog.h" #include "ksyms.h" +#include "module.h" -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -static int num_syms = 0; +int num_syms = 0; static int i_am_paranoid = 0; static char vstring[12]; static struct sym_table *sym_array = (struct sym_table *) 0; @@ -589,38 +583,65 @@ static int AddSymbol(unsigned long address, char *symbol) * If a match is found the pointer to the symbolic name most * closely matching the address is returned. **************************************************************************/ -char * LookupSymbol(unsigned long value, struct symbol *sym) +char * LookupSymbol(value, sym) + + unsigned long value; + + struct symbol *sym; + { - auto int lp; - auto char *last; + auto int lp; - if (!sym_array) - return((char *) 0); + auto char *last; + auto char *name; - last = sym_array[0].name; - sym->offset = 0; - sym->size = 0; - if ( value < sym_array[0].value ) - return((char *) 0); - - for(lp= 0; lp <= num_syms; ++lp) - { - if ( sym_array[lp].value > value ) - { - sym->offset = value - sym_array[lp-1].value; - sym->size = sym_array[lp].value - \ - sym_array[lp-1].value; - return(last); - } - last = sym_array[lp].name; - } + struct symbol ksym, msym; - if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 ) - return(last); + if (!sym_array) + return((char *) 0); - return(NULL); -} + last = sym_array[0].name; + ksym.offset = 0; + ksym.size = 0; + if ( value < sym_array[0].value ) + return((char *) 0); + for(lp = 0; lp <= num_syms; ++lp) + { + if ( sym_array[lp].value > value ) + { + ksym.offset = value - sym_array[lp-1].value; + ksym.size = sym_array[lp].value - \ + sym_array[lp-1].value; + break; + } + last = sym_array[lp].name; + } + + name = LookupModuleSymbol(value, &msym); + + if ( ksym.offset == 0 && msym.offset == 0 ) + { + return((char *) 0); + } + + if ( ksym.offset == 0 || msym.offset < 0 || + (ksym.offset > 0 && ksym.offset < msym.offset) ) + { + sym->offset = ksym.offset; + sym->size = ksym.size; + return(last); + } + else + { + sym->offset = msym.offset; + sym->size = msym.size; + return(name); + } + + + return((char *) 0); +} /************************************************************************** * Function: FreeSymbols @@ -679,6 +700,9 @@ extern char *ExpandKadds(char *line, char *el) auto unsigned long int value; auto struct symbol sym; + sym.offset = 0; + sym.size = 0; + /* * This is as handy a place to put this as anyplace. * @@ -819,7 +843,7 @@ extern char *ExpandKadds(char *line, char *el) { --value; ++kp; - elp += sprintf(elp, "+%x/%d", sym.offset, sym.size); + elp += sprintf(elp, "+0x%x/0x%02x", sym.offset, sym.size); } strncat(elp, kp, value); elp += value; diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c index 3c7e0e45..ec1231be 100644 --- a/plugins/imklog/ksym_mod.c +++ b/plugins/imklog/ksym_mod.c @@ -86,6 +86,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -97,8 +98,6 @@ #include #else /* __GLIBC__ */ #include "module.h" -extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); -extern int get_kernel_syms __P ((struct kernel_sym *__table)); #endif /* __GLIBC__ */ #include #include @@ -108,42 +107,7 @@ extern int get_kernel_syms __P ((struct kernel_sym *__table)); #include "imklog.h" #include "ksyms.h" - -#if !defined(__GLIBC__) -/* - * The following bit uses some kernel/library magic to product what - * looks like a function call to user level code. This function is - * actually a system call in disguise. The purpose of the getsyms - * call is to return a current copy of the in-kernel symbol table. - */ -#define __LIBRARY__ -#include -#define __NR_getsyms __NR_get_kernel_syms -_syscall1(int, getsyms, struct kernel_sym *, syms); -#undef __LIBRARY__ -extern int getsyms(struct kernel_sym *); -#else /* __GLIBC__ */ -#define getsyms get_kernel_syms -#endif /* __GLIBC__ */ - -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -struct Module -{ - struct sym_table *sym_array; - int num_syms; - - char *name; - struct module module; -#if LINUX_VERSION_CODE >= 0x20112 - struct module_info module_info; -#endif -}; +#define KSYMS "/proc/kallsyms" static int num_modules = 0; struct Module *sym_array_modules = (struct Module *) 0; @@ -153,10 +117,13 @@ static int have_modules = 0; /* Function prototypes. */ static void FreeModules(void); -static int AddSymbol(struct Module *mp, unsigned long, char *); -static int AddModule(unsigned long, char *); +static int AddSymbol(const char *); +struct Module *AddModule(const char *); static int symsort(const void *, const void *); +/* Imported from ksym.c */ +extern int num_syms; + /************************************************************************** * Function: InitMsyms @@ -175,94 +142,74 @@ static int symsort(const void *, const void *); **************************************************************************/ extern int InitMsyms(void) { - auto int rtn, - tmp; - auto struct kernel_sym *ksym_table, - *p; + auto int rtn, + tmp; + + FILE *ksyms; + char buf[128]; + char *p; /* Initialize the kernel module symbol table. */ FreeModules(); - - /* - * The system call which returns the kernel symbol table has - * essentialy two modes of operation. Called with a null pointer - * the system call returns the number of symbols defined in the - * the table. - * - * The second mode of operation is to pass a valid pointer to - * the call which will then load the current symbol table into - * the memory provided. - * - * Returning the symbol table is essentially an all or nothing - * proposition so we need to pre-allocate enough memory for the - * complete table regardless of how many symbols we need. - * - * Bummer. - */ - if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) - { - if ( errno == ENOSYS ) - Syslog(LOG_INFO, "No module symbols loaded - " - "kernel modules not enabled.\n"); - else - Syslog(LOG_ERR, "Error loading kernel symbols " \ - "- %s\n", strerror(errno)); - return(0); - } - dbgprintf("Loading kernel module symbols - Size of table: %d\n", rtn); - - ksym_table = (struct kernel_sym *) malloc(rtn * sizeof(struct kernel_sym)); - if ( ksym_table == (struct kernel_sym *) 0 ) - { - Syslog(LOG_WARNING, " Failed memory allocation for kernel symbol table.\n"); - return(0); - } - if ( (rtn = getsyms(ksym_table)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", strerror(errno)); - return(0); - } - - - /* - * Build a symbol table compatible with the other one used by - * klogd. - */ - tmp = rtn; - p = ksym_table; - while ( tmp-- ) - { - if ( !AddModule(p->value, p->name) ) - { - Syslog(LOG_WARNING, "Error adding kernel module table entry.\n"); - free(ksym_table); - return(0); - } - ++p; - } - - /* Sort the symbol tables in each module. */ - for (rtn = tmp= 0; tmp < num_modules; ++tmp) - { - rtn += sym_array_modules[tmp].num_syms; - if ( sym_array_modules[tmp].num_syms < 2 ) - continue; - qsort(sym_array_modules[tmp].sym_array, \ - sym_array_modules[tmp].num_syms, \ - sizeof(struct sym_table), symsort); - } - - if ( rtn == 0 ) - Syslog(LOG_INFO, "No module symbols loaded."); - else - Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ - (rtn == 1) ? "symbol" : "symbols", \ - num_modules, (num_modules == 1) ? "." : "s."); - free(ksym_table); - return(1); + ksyms = fopen(KSYMS, "r"); + + if ( ksyms == NULL ) + { + if ( errno == ENOENT ) + Syslog(LOG_INFO, "No module symbols loaded - " + "kernel modules not enabled.\n"); + else + Syslog(LOG_ERR, "Error loading kernel symbols " \ + "- %s\n", strerror(errno)); + fclose(ksyms); + return(0); + } + + dbgprintf("Loading kernel module symbols - Source: %s\n", KSYMS); + + while ( fgets(buf, sizeof(buf), ksyms) != NULL ) + { + if (num_syms > 0 && index(buf, '[') == NULL) + continue; + + p = index(buf, ' '); + + if ( p == NULL ) + continue; + + if ( buf[strlen(buf)-1] == '\n' ) + buf[strlen(buf)-1] = '\0'; + /* overlong lines will be ignored above */ + + AddSymbol(buf); + } + + fclose(ksyms); + + have_modules = 1; + + /* Sort the symbol tables in each module. */ + for (rtn = tmp = 0; tmp < num_modules; ++tmp) + { + rtn += sym_array_modules[tmp].num_syms; + if ( sym_array_modules[tmp].num_syms < 2 ) + continue; + qsort(sym_array_modules[tmp].sym_array, \ + sym_array_modules[tmp].num_syms, \ + sizeof(struct sym_table), symsort); + } + + if ( rtn == 0 ) + Syslog(LOG_INFO, "No module symbols loaded."); + else + Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ + (rtn == 1) ? "symbol" : "symbols", \ + num_modules, (num_modules == 1) ? "." : "s."); + + return(1); } @@ -295,134 +242,100 @@ extern void DeinitMsyms(void) * * Return: void **************************************************************************/ -static void FreeModules(void) +static void FreeModules() + { - auto int nmods, - nsyms; + auto int nmods, + nsyms; - auto struct Module *mp; + auto struct Module *mp; - /* Check to see if the module symbol tables need to be cleared. */ - have_modules = 0; - if ( num_modules == 0 ) - return; + /* Check to see if the module symbol tables need to be cleared. */ + have_modules = 0; + if ( num_modules == 0 ) + return; + if ( sym_array_modules == NULL ) + return; - for (nmods= 0; nmods < num_modules; ++nmods) - { - mp = &sym_array_modules[nmods]; - if ( mp->num_syms == 0 ) - continue; - - for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) - free(mp->sym_array[nsyms].name); - free(mp->sym_array); - } + for (nmods = 0; nmods < num_modules; ++nmods) + { + mp = &sym_array_modules[nmods]; + if ( mp->num_syms == 0 ) + continue; - free(sym_array_modules); - sym_array_modules = (struct Module *) 0; - num_modules = 0; - return; -} + for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) + free(mp->sym_array[nsyms].name); + free(mp->sym_array); + if ( mp->name != NULL ) + free(mp->name); + } + free(sym_array_modules); + sym_array_modules = (struct Module *) 0; + num_modules = 0; + return; +} /************************************************************************** - * Function: AddModule - * - * Purpose: This function is responsible for adding a module to - * the list of currently loaded modules. - * - * Arguements: (unsigned long) address, (char *) symbol - * - * address:-> The address of the module. - * - * symbol:-> The name of the module. - * - * Return: int - **************************************************************************/ -static int AddModule(unsigned long address, char *symbol) -{ - auto int memfd; - auto struct Module *mp; - - - /* Return if we have loaded the modules. */ - if ( have_modules ) - return(1); - - /* - * The following section of code is responsible for determining - * whether or not we are done reading the list of modules. - */ - if ( symbol[0] == '#' ) - { - - if ( symbol[1] == '\0' ) - { - /* - * A symbol which consists of a # sign only - * signifies a a resident kernel segment. When we - * hit one of these we are done reading the - * module list. - */ - have_modules = 1; - return(1); - } - /* Allocate space for the module. */ - sym_array_modules = (struct Module *) \ - realloc(sym_array_modules, \ - (num_modules+1) * sizeof(struct Module)); - if ( sym_array_modules == (struct Module *) 0 ) - { - Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); - return(0); - } - mp = &sym_array_modules[num_modules]; - - if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) - { - Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); - return(0); - } - if ( lseek64(memfd, address, SEEK_SET) < 0 ) - { - Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); - Syslog(LOG_WARNING, "Symbol %s, value %08lx\n", symbol, - (unsigned long) address); - return(0); - } - if ( read(memfd, \ - (char *)&sym_array_modules[num_modules].module, \ - sizeof(struct module)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading module " - "descriptor.\n"); - return(0); - } - close(memfd); - - /* Save the module name. */ - mp->name = (char *) malloc(strlen(&symbol[1]) + 1); - if ( mp->name == (char *) 0 ) - return(0); - strcpy(mp->name, &symbol[1]); - - mp->num_syms = 0; - mp->sym_array = (struct sym_table *) 0; - ++num_modules; - return(1); - } - else - { - if (num_modules > 0) - mp = &sym_array_modules[num_modules - 1]; - else - mp = &sym_array_modules[0]; - AddSymbol(mp, address, symbol); - } + * * Function: AddModule + * * + * * Purpose: This function is responsible for adding a module to + * * the list of currently loaded modules. + * * + * * Arguments: (const char *) module + * * + * * module:-> The name of the module. + * * + * * Return: struct Module * + * **************************************************************************/ + +struct Module *AddModule(module) + + const char *module; - return(1); +{ + struct Module *mp; + + if ( num_modules == 0 ) + { + sym_array_modules = (struct Module *)malloc(sizeof(struct Module)); + + if ( sym_array_modules == NULL ) + { + Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); + return NULL; + } + mp = sym_array_modules; + } + else + { + /* Allocate space for the module. */ + mp = (struct Module *) \ + realloc(sym_array_modules, \ + (num_modules+1) * sizeof(struct Module)); + + if ( mp == NULL ) + { + Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); + return NULL; + } + + sym_array_modules = mp; + mp = &sym_array_modules[num_modules]; + } + + num_modules++; + mp->sym_array = NULL; + mp->num_syms = 0; + + if ( module != NULL ) + mp->name = strdup(module); + else + mp->name = NULL; + + return mp; } @@ -432,49 +345,85 @@ static int AddModule(unsigned long address, char *symbol) * Purpose: This function is responsible for adding a symbol name * and its address to the symbol table. * - * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol - * - * mp:-> A pointer to the module which the symbol is - * to be added to. - * - * address:-> The address of the symbol. - * - * symbol:-> The name of the symbol. + * Arguements: const char * * * Return: int * * A boolean value is assumed. True if the addition is * successful. False if not. **************************************************************************/ -static int AddSymbol(struct Module *mp, unsigned long address, char *symbol) +static int AddSymbol(line) + + const char *line; + { - auto int tmp; + char *module; + unsigned long address; + char *p; + static char *lastmodule = NULL; + struct Module *mp; - /* Allocate space for the symbol table entry. */ - mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ - (mp->num_syms+1) * sizeof(struct sym_table)); - if ( mp->sym_array == (struct sym_table *) 0 ) - return(0); + module = index(line, '['); - /* Then the space for the symbol. */ - tmp = strlen(symbol); - tmp += (strlen(mp->name) + 1); - mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); - if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) - return(0); - memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); - - /* Stuff interesting information into the module. */ - mp->sym_array[mp->num_syms].value = address; - strcpy(mp->sym_array[mp->num_syms].name, mp->name); - strcat(mp->sym_array[mp->num_syms].name, ":"); - strcat(mp->sym_array[mp->num_syms].name, symbol); - ++mp->num_syms; + if ( module != NULL ) + { + p = index(module, ']'); - return(1); + if ( p != NULL ) + *p = '\0'; + + p = module++; + + while ( isspace(*(--p)) ); + *(++p) = '\0'; + } + + p = index(line, ' '); + + if ( p == NULL ) + return(0); + + *p = '\0'; + + address = strtoul(line, (char **) 0, 16); + + p += 3; + + if ( num_modules == 0 || + ( lastmodule == NULL && module != NULL ) || + ( module == NULL && lastmodule != NULL) || + ( module != NULL && strcmp(module, lastmodule))) + { + mp = AddModule(module); + + if ( mp == NULL ) + return(0); + } + else + mp = &sym_array_modules[num_modules-1]; + + lastmodule = mp->name; + + /* Allocate space for the symbol table entry. */ + mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ + (mp->num_syms+1) * sizeof(struct sym_table)); + + if ( mp->sym_array == (struct sym_table *) 0 ) + return(0); + + mp->sym_array[mp->num_syms].name = strdup(p); + if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) + return(0); + + /* Stuff interesting information into the module. */ + mp->sym_array[mp->num_syms].value = address; + ++mp->num_syms; + + return(1); } + /************************************************************************** * Function: LookupModuleSymbol * @@ -494,103 +443,68 @@ static int AddSymbol(struct Module *mp, unsigned long address, char *symbol) * If a match is found the pointer to the symbolic name most * closely matching the address is returned. **************************************************************************/ -extern char * LookupModuleSymbol(unsigned long value, struct symbol *sym) +extern char * LookupModuleSymbol(value, sym) + + unsigned long value; + + struct symbol *sym; + { - auto int nmod, - nsym; - auto struct sym_table *last; - auto struct Module *mp; - - - sym->size = 0; - sym->offset = 0; - if ( num_modules == 0 ) - return((char *) 0); - - for(nmod= 0; nmod < num_modules; ++nmod) - { - mp = &sym_array_modules[nmod]; - - /* + auto int nmod, + nsym; + + auto struct sym_table *last; + + auto struct Module *mp; + + static char ret[100]; + + + sym->size = 0; + sym->offset = 0; + if ( num_modules == 0 ) + return((char *) 0); + + for (nmod = 0; nmod < num_modules; ++nmod) + { + mp = &sym_array_modules[nmod]; + + /* * Run through the list of symbols in this module and - * see if the address can be resolved. - */ - for(nsym= 1, last = &mp->sym_array[0]; - nsym < mp->num_syms; - ++nsym) - { - if ( mp->sym_array[nsym].value > value ) - { - sym->offset = value - last->value; - sym->size = mp->sym_array[nsym].value - \ - last->value; - return(last->name); - } - last = &mp->sym_array[nsym]; - } - - /* - * At this stage of the game we still cannot give up the - * ghost. There is the possibility that the address is - * from a module which has no symbols registered with - * the kernel. The solution is to compare the address - * against the starting address and extant of the module - * If it is in this range we can at least return the - * name of the module. + * see if the address can be resolved. */ -#if LINUX_VERSION_CODE < 0x20112 - if ( (void *) value >= mp->module.addr && - (void *) value <= (mp->module.addr + \ - mp->module.size * 4096) ) -#else - if ( value >= mp->module_info.addr && - value <= (mp->module_info.addr + \ - mp->module.size * 4096) ) -#endif - { - /* - * A special case needs to be checked for. The above - * conditional tells us that we are within the - * extant of this module but symbol lookup has - * failed. - * - * We need to check to see if any symbols have - * been defined in this module. If there have been - * symbols defined the assumption must be made that - * the faulting address lies somewhere beyond the - * last symbol. About the only thing we can do - * at this point is use an offset from this - * symbol. - */ - if ( mp->num_syms > 0 ) - { - last = &mp->sym_array[mp->num_syms - 1]; -#if LINUX_VERSION_CODE < 0x20112 - sym->size = (int) mp->module.addr + \ - (mp->module.size * 4096) - value; -#else - sym->size = (int) mp->module_info.addr + \ - (mp->module.size * 4096) - value; -#endif - sym->offset = value - last->value; - return(last->name); - } - - /* - * There were no symbols defined for this module. - * Return the module name and the offset of the - * faulting address in the module. - */ - sym->size = mp->module.size * 4096; -#if LINUX_VERSION_CODE < 0x20112 - sym->offset = (void *) value - mp->module.addr; -#else - sym->offset = value - mp->module_info.addr; -#endif - return(mp->name); - } - } - - /* It has been a hopeless exercise. */ - return(NULL); + for(nsym = 1, last = &mp->sym_array[0]; + nsym < mp->num_syms; + ++nsym) + { + if ( mp->sym_array[nsym].value > value ) + { + if ( sym->size == 0 || + (value - last->value) < sym->offset || + ( (sym->offset == (value - last->value)) && + (mp->sym_array[nsym].value-last->value) < sym->size ) ) + { + sym->offset = value - last->value; + sym->size = mp->sym_array[nsym].value - \ + last->value; + ret[sizeof(ret)-1] = '\0'; + if ( mp->name == NULL ) + snprintf(ret, sizeof(ret)-1, + "%s", last->name); + else + snprintf(ret, sizeof(ret)-1, + "%s:%s", mp->name, last->name); + } + break; + } + last = &mp->sym_array[nsym]; + } + } + + if ( sym->size > 0 ) + return(ret); + + /* It has been a hopeless exercise. */ + return((char *) 0); } + diff --git a/plugins/imklog/module.h b/plugins/imklog/module.h index 71eac2c4..7a26ad02 100644 --- a/plugins/imklog/module.h +++ b/plugins/imklog/module.h @@ -19,63 +19,18 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ -struct kernel_sym -{ - unsigned long value; - char name[60]; -}; -struct module_symbol +struct sym_table { - unsigned long value; - const char *name; + unsigned long value; + char *name; }; -struct module_ref +struct Module { - struct module *dep; /* "parent" pointer */ - struct module *ref; /* "child" pointer */ - struct module_ref *next_ref; -}; + struct sym_table *sym_array; + int num_syms; -struct module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; + char *name; }; - -typedef struct { volatile int counter; } atomic_t; - -struct module -{ - unsigned long size_of_struct; /* == sizeof(module) */ - struct module *next; - const char *name; - unsigned long size; - - union - { - atomic_t usecount; - long pad; - } uc; /* Needs to keep its size - so says rth */ - - unsigned long flags; /* AUTOCLEAN et al */ - - unsigned nsyms; - unsigned ndeps; - - struct module_symbol *syms; - struct module_ref *deps; - struct module_ref *refs; - int (*init)(void); - void (*cleanup)(void); - const struct exception_table_entry *ex_table_start; - const struct exception_table_entry *ex_table_end; -#ifdef __alpha__ - unsigned long gp; -#endif -}; - -- cgit