/* symbols.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 David Anderson * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "defs.h" #include #ifdef GDB_7_6 #define __CONFIG_H__ 1 #include "config.h" #endif #include "bfd.h" static void store_symbols(bfd *, int, void *, long, unsigned int); static void store_sysmap_symbols(void); static ulong relocate(ulong, char *, int); static int relocate_force(ulong, char *); static void strip_module_symbol_end(char *s); static int compare_syms(const void *, const void *); static int compare_mods(const void *, const void *); static int compare_prios(const void *v1, const void *v2); static asection *get_kernel_section(char *); static char * get_section(ulong vaddr, char *buf); static void symbol_dump(ulong, char *); static void check_for_dups(struct load_module *); static int symbol_name_count(char *); static struct syment *kallsyms_module_symbol(struct load_module *, symbol_info *); static void store_load_module_symbols \ (bfd *, int, void *, long, uint, ulong, char *); static int load_module_index(struct syment *); static void section_header_info(bfd *, asection *, void *); static void store_section_data(struct load_module *, bfd *, asection *); static void calculate_load_order_v1(struct load_module *, bfd *); static void calculate_load_order_v2(struct load_module *, bfd *, int, void *, long, unsigned int); static void check_insmod_builtin(struct load_module *, int, ulong *); static int is_insmod_builtin(struct load_module *, struct syment *); struct load_module; static int add_symbol_file(struct load_module *); static int add_symbol_file_kallsyms(struct load_module *, struct gnu_request *); static void find_mod_etext(struct load_module *); static long rodata_search(ulong *, ulong); static int ascii_long(ulong word); static int is_bfd_format(char *); static int is_binary_stripped(char *); static int namespace_ctl(int, struct symbol_namespace *, void *, void *); static void symval_hash_init(void); static struct syment *symval_hash_search(ulong); static void symname_hash_init(void); static void symname_hash_install(struct syment *); static struct syment *symname_hash_search(char *); static void gnu_qsort(bfd *, void *, long, unsigned int, asymbol *, asymbol *); static int check_gnu_debuglink(bfd *); static int separate_debug_file_exists(const char *, unsigned long, int *); static int store_module_kallsyms_v1(struct load_module *, int, int, char *); static int store_module_kallsyms_v2(struct load_module *, int, int, char *); static void datatype_error(void **, char *, char *, char *, int); static char *get_thisfile(void); struct elf_common; static void Elf32_Sym_to_common(Elf32_Sym *, struct elf_common *); static void Elf64_Sym_to_common(Elf64_Sym *, struct elf_common *); static void cmd_datatype_common(ulong); static int display_per_cpu_info(struct syment *); static struct load_module *get_module_percpu_sym_owner(struct syment *); static int is_percpu_symbol(struct syment *); static void dump_percpu_symbols(struct load_module *); static void print_struct_with_dereference(ulong, struct datatype_member *, ulong); static int dereference_pointer(ulong, struct datatype_member *, ulong); #define KERNEL_SECTIONS (void *)(1) #define MODULE_SECTIONS (void *)(2) #define VERIFY_SECTIONS (void *)(3) #define EV_DWARFEXTRACT 101010101 #define PARSE_FOR_DATA (1) #define PARSE_FOR_DECLARATION (2) static void parse_for_member(struct datatype_member *, ulong); static int show_member_offset(FILE *, struct datatype_member *, char *); /* * structure/union printing stuff */ #define UINT8 (0x1) #define INT8 (0x2) #define UINT16 (0x4) #define INT16 (0x8) #define UINT32 (0x10) #define INT32 (0x20) #define UINT64 (0x40) #define INT64 (0x80) #define POINTER (0x100) #define FUNCTION (0x200) #define UNION_REQUEST (0x400) #define STRUCT_REQUEST (0x800) #define ARRAY (0x1000) #define ENUM (0x2000) #define TYPEDEF (0x4000) #define STRUCT_VERBOSE (0x8000) #define SHOW_OFFSET (0x10000) #define IN_UNION (0x20000) #define IN_STRUCT (0x40000) #define DATATYPE_QUERY (0x80000) #define ANON_MEMBER_QUERY (0x100000) #define INTEGER_TYPE (UINT8|INT8|UINT16|INT16|UINT32|INT32|UINT64|INT64) #define INITIAL_INDENT (4) #define INDENT_INCR (2) static int is_typedef(char *); static void whatis_datatype(char *, ulong, FILE *); static void whatis_variable(struct syment *); static void print_struct(char *, ulong); static void print_union(char *, ulong); static void dump_datatype_member(FILE *, struct datatype_member *); static void dump_datatype_flags(ulong, FILE *); static long anon_member_offset(char *, char *); static int gdb_whatis(char *); static void do_datatype_declaration(struct datatype_member *, ulong); #define DEBUGINFO_ERROR_MESSAGE1 \ "the use of a System.map file requires that the accompanying namelist\nargument is a kernel file built with the -g CFLAG. The namelist argument\nsupplied in this case is a debuginfo file, which must be accompanied by the\nkernel file from which it was derived.\n" #define DEBUGINFO_ERROR_MESSAGE2 \ "The namelist argument supplied in this case is a debuginfo file,\nwhich must be accompanied by the kernel file from which it was derived.\n" /* * This routine scours the namelist for kernel text and data symbols, * sorts, and stores, them in a static table for quick reference. */ void symtab_init(void) { char **matching; long symcount; void *minisyms; unsigned int size; asymbol *sort_x; asymbol *sort_y; if ((st->bfd = bfd_openr(pc->namelist, NULL)) == NULL) error(FATAL, "cannot open object file: %s\n", pc->namelist); if (!bfd_check_format_matches(st->bfd, bfd_object, &matching)) error(FATAL, "cannot determine object file format: %s\n", pc->namelist); /* * Check whether the namelist is a kerntypes file built by * dwarfextract, which places a magic number in e_version. */ if (file_elf_version(pc->namelist) == EV_DWARFEXTRACT) pc->flags |= KERNTYPES; if (pc->flags & SYSMAP) { bfd_map_over_sections(st->bfd, section_header_info, VERIFY_SECTIONS); if ((st->flags & (NO_SEC_LOAD|NO_SEC_CONTENTS)) == (NO_SEC_LOAD|NO_SEC_CONTENTS)) { error(INFO, "%s: no text and data contents\n", pc->namelist); error(FATAL, pc->flags & SYSMAP_ARG ? DEBUGINFO_ERROR_MESSAGE1 : DEBUGINFO_ERROR_MESSAGE2); } store_sysmap_symbols(); return; } else if (LKCD_KERNTYPES()) error(FATAL, "%s: use of kerntypes requires a system map\n", pc->namelist); /* * Pull a bait-and-switch on st->bfd if we've got a separate * .gnu_debuglink file that matches the CRC. Not done for kerntypes. */ if (!(LKCD_KERNTYPES()) && !(bfd_get_file_flags(st->bfd) & HAS_SYMS)) { if (!check_gnu_debuglink(st->bfd)) no_debugging_data(FATAL); } symcount = bfd_read_minisymbols(st->bfd, FALSE, &minisyms, &size); if (symcount <= 0) no_debugging_data(FATAL); sort_x = bfd_make_empty_symbol(st->bfd); sort_y = bfd_make_empty_symbol(st->bfd); if (sort_x == NULL || sort_y == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); gnu_qsort(st->bfd, minisyms, symcount, size, sort_x, sort_y); store_symbols(st->bfd, FALSE, minisyms, symcount, size); free(minisyms); /* * Gather references to the kernel sections. */ if ((st->sections = (struct sec *) malloc(st->bfd->section_count * sizeof(struct sec *))) == NULL) error(FATAL, "symbol table section array malloc: %s\n", strerror(errno)); BZERO(st->sections, st->bfd->section_count * sizeof(struct sec *)); bfd_map_over_sections(st->bfd, section_header_info, KERNEL_SECTIONS); if ((st->flags & (NO_SEC_LOAD|NO_SEC_CONTENTS)) == (NO_SEC_LOAD|NO_SEC_CONTENTS)) { if (!pc->namelist_debug && !pc->debuginfo_file) { error(INFO, "%s: no text and data contents\n", pc->namelist); error(FATAL, DEBUGINFO_ERROR_MESSAGE2); } } symname_hash_init(); symval_hash_init(); } /* * Adapted from gdb's get_debug_link_info() * * Look in: current directory * basename-of-namelist/.debug directory * /usr/lib/debug/boot (since we know it's a Red Hat kernel) */ static int check_gnu_debuglink(bfd *bfd) { int i, exists, found; asection *sect; bfd_size_type debuglink_size; char *contents; int crc_offset; unsigned long crc32; char *dirname; char *namelist_debug; char **matching; sect = bfd_get_section_by_name(bfd, ".gnu_debuglink"); if (!sect) { error(INFO, "%s: no .gnu_debuglink section\n", pc->namelist); return FALSE; } debuglink_size = bfd_section_size(bfd, sect); contents = GETBUF(debuglink_size); bfd_get_section_contents(bfd, sect, contents, (file_ptr)0, (bfd_size_type)debuglink_size); crc_offset = strlen (contents) + 1; crc_offset = (crc_offset + 3) & ~3; crc32 = bfd_get_32(bfd, (bfd_byte *)(contents + crc_offset)); if (CRASHDEBUG(1)) error(NOTE, "gnu_debuglink file: %s\ncrc32: %lx\n", contents, crc32); if ((pc->debuginfo_file = (char *) malloc(((strlen(pc->namelist) + strlen("/.debug/") + + strlen(".debug") + strlen(" /usr/lib/debug/boot/ "))*10) + strlen(pc->namelist_debug ? pc->namelist_debug : " "))) == NULL) error(FATAL, "debuginfo file name malloc: %s\n", strerror(errno)); dirname = GETBUF(strlen(pc->namelist)+1); strcpy(dirname, pc->namelist); for (i = strlen(dirname)-1; i >= 0; i--) { if (dirname[i] == '/') break; } dirname[i+1] = NULLCHAR; if (!strlen(dirname)) sprintf(dirname, "."); namelist_debug = NULL; if (pc->namelist_debug) { sprintf(pc->debuginfo_file, "%s", pc->namelist_debug); if (separate_debug_file_exists(pc->debuginfo_file, crc32, &exists)) { if (CRASHDEBUG(1)) fprintf(fp, "%s: CRC matches\n", pc->debuginfo_file); st->flags |= CRC_MATCHES; goto reset_bfd; } else { if ((st->flags & FORCE_DEBUGINFO) && exists) { error(WARNING, "%s:\n CRC value does not match\n\n", pc->debuginfo_file); goto reset_bfd; } else error(INFO, "%s:\n CRC value does not match\n\n", pc->debuginfo_file); namelist_debug = pc->namelist_debug; pc->namelist_debug = NULL; } } found = 0; sprintf(pc->debuginfo_file, "%s/%s", dirname, contents); if (separate_debug_file_exists(pc->debuginfo_file, crc32, &exists)) { if (CRASHDEBUG(1)) fprintf(fp, "%s: CRC matches\n", pc->debuginfo_file); st->flags |= CRC_MATCHES; goto reset_bfd; } else { if (CRASHDEBUG(1)) fprintf(fp, "%s: %s\n", pc->debuginfo_file, exists ? "CRC does not match" : "not readable/found"); if (exists) { error(INFO, "%s: CRC does not match\n\n", pc->debuginfo_file); found++; } } sprintf(pc->debuginfo_file, "%s/.debug/%s", dirname, contents); if (separate_debug_file_exists(pc->debuginfo_file, crc32, &exists)) { if (CRASHDEBUG(1)) fprintf(fp, "%s: CRC matches\n", pc->debuginfo_file); st->flags |= CRC_MATCHES; goto reset_bfd; } else { if (CRASHDEBUG(1)) fprintf(fp, "%s: %s\n", pc->debuginfo_file, exists ? "CRC does not match" : "not readable/found"); if (exists) { error(INFO, "%s: CRC does not match\n\n", pc->debuginfo_file); found++; } } sprintf(pc->debuginfo_file, "/usr/lib/debug/boot/%s", contents); if (separate_debug_file_exists(pc->debuginfo_file, crc32, &exists)) { if (CRASHDEBUG(1)) fprintf(fp, "%s: CRC matches\n", pc->debuginfo_file); st->flags |= CRC_MATCHES; goto reset_bfd; } else { if (CRASHDEBUG(1)) fprintf(fp, "%s: %s\n", pc->debuginfo_file, exists ? "CRC does not match" : "not readable/found"); if (exists) { error(INFO, "%s: CRC does not match\n\n", pc->debuginfo_file); found++; } } if (!found && namelist_debug) { error(INFO, "%s:\n use of -f option may suffice, or may fail miserably\n", namelist_debug); } if (!found && !namelist_debug) { no_debugging_data(INFO); error(INFO, "%s: debuginfo file not found\n", contents); error(FATAL, "either install the appropriate kernel debuginfo package, or\n copy %s to this machine", contents); } return FALSE; reset_bfd: if ((st->bfd = bfd_openr(pc->debuginfo_file, NULL)) == NULL) error(FATAL, "cannot open object file: %s\n", pc->debuginfo_file); if (!bfd_check_format_matches(st->bfd, bfd_object, &matching)) error(FATAL, "cannot determine object file format: %s\n", pc->debuginfo_file); FREEBUF(contents); FREEBUF(dirname); return TRUE; } /* * Based upon gdb's separate_debug_file_exists(). */ static int separate_debug_file_exists(const char *name, unsigned long crc, int *exists) { unsigned long file_crc = 0; int fd; char buffer[8*1024]; size_t count; fd = open(name, O_RDONLY); if (fd < 0) { *exists = FALSE; return 0; } *exists = TRUE; while ((count = read(fd, buffer, sizeof(buffer))) > 0) #ifdef GDB_5_3 file_crc = calc_crc32(file_crc, buffer, count); #else #ifdef GDB_7_6 file_crc = bfd_calc_gnu_debuglink_crc32(file_crc, (unsigned char *)buffer, count); #else file_crc = gnu_debuglink_crc32(file_crc, (unsigned char *)buffer, count); #endif #endif close (fd); return crc == file_crc; } /* * Callback for gdb to use a specified vmlinux.debug file. */ char * check_specified_kernel_debug_file() { if (pc->flags & GDB_INIT) return NULL; return (pc->namelist_debug ? pc->namelist_debug : NULL); } /* * Common bailout/warning routine when running against non-debug kernels. * * INFO: used when this routine should return. * FATAL: kills function if runtime, or kills program if during init. * WARNING: called by gdb_session_init() only, in an attempt to at least * get by with built-in debug data; if not possible the program * is killed. */ void no_debugging_data(int error_type) { switch (error_type) { case INFO: error(INFO, "%s: no debugging data available\n", pc->namelist); break; case FATAL: error(FATAL, "%s%s: no debugging data available\n", pc->flags & RUNTIME ? "" : "\n", pc->namelist); clean_exit(1); case WARNING: error(FATAL, "\n%s: no debugging data available\n", pc->namelist); clean_exit(1); } } /* * Get the address space formerly used as init-time text. While there * get the boundaries of the kernel .rodata section so that it won't * be confused with text. * * This is done indirectly by the call-back to section_header_info(). */ void get_text_init_space(void) { asection *section = NULL; if (pc->flags & SYSMAP) return; if (machine_type("ARM")) section = get_kernel_section(".init"); if (!section && !(section = get_kernel_section(".text.init"))) section = get_kernel_section(".init.text"); if (!section) { error(WARNING, "cannot determine text init space\n"); return; } kt->stext_init = (ulong)bfd_get_section_vma(st->bfd, section); kt->etext_init = kt->stext_init + (ulong)bfd_section_size(st->bfd, section); if (kt->relocate) { kt->stext_init -= kt->relocate; kt->etext_init -= kt->relocate; } } /* * Strip gcc-generated cloned text symbol name endings. */ static char * strip_symbol_end(const char *name, char *buf) { char *p; if (st->flags & NO_STRIP) return (char *)name; if ((p = strstr(name, ".isra."))) { if (buf) { strcpy(buf, name); buf[p-name] = NULLCHAR; return buf; } else { *p = NULLCHAR; return (char *)name; } } if ((p = strstr(name, ".part."))) { if (buf) { strcpy(buf, name); buf[p-name] = NULLCHAR; return buf; } else { *p = NULLCHAR; return (char *)name; } } return (char *)name; } /* * Store the symbols gathered by symtab_init(). The symbols are stored * in increasing numerical order. */ static void store_symbols(bfd *abfd, int dynamic, void *minisyms, long symcount, unsigned int size) { asymbol *store; asymbol *sym; bfd_byte *from, *fromend; symbol_info syminfo; struct syment *sp; char buf[BUFSIZE]; char *name; int first; if ((store = bfd_make_empty_symbol(abfd)) == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); if ((st->symtable = (struct syment *) calloc(symcount, sizeof(struct syment))) == NULL) error(FATAL, "symbol table syment space malloc: %s\n", strerror(errno)); if (!namespace_ctl(NAMESPACE_INIT, &st->kernel_namespace, (void *)symcount, NULL)) error(FATAL, "symbol table namespace malloc: %s\n", strerror(errno)); st->syment_size = symcount * sizeof(struct syment); st->symcnt = 0; sp = st->symtable; if (machine_type("X86")) { if (!(kt->flags & RELOC_SET)) kt->flags |= RELOC_FORCE; } else kt->flags &= ~RELOC_SET; first = 0; from = (bfd_byte *) minisyms; fromend = from + symcount * size; for (; from < fromend; from += size) { if ((sym = bfd_minisymbol_to_symbol(abfd, dynamic, from, store)) == NULL) error(FATAL, "bfd_minisymbol_to_symbol() failed\n"); bfd_get_symbol_info(abfd, sym, &syminfo); name = strip_symbol_end(syminfo.name, buf); if (machdep->verify_symbol(name, syminfo.value, syminfo.type)) { if (kt->flags & (RELOC_SET|RELOC_FORCE)) sp->value = relocate(syminfo.value, (char *)syminfo.name, !(first++)); else sp->value = syminfo.value; sp->type = syminfo.type; namespace_ctl(NAMESPACE_INSTALL, &st->kernel_namespace, sp, name); sp++; st->symcnt++; } } st->symend = &st->symtable[st->symcnt]; st->flags |= KERNEL_SYMS; namespace_ctl(NAMESPACE_COMPLETE, &st->kernel_namespace, st->symtable, st->symend); } /* * Store the symbols from the designated System.map. The symbols are stored * in increasing numerical order. */ static void store_sysmap_symbols(void) { int c, first; long symcount; char buf[BUFSIZE]; char name[BUFSIZE]; FILE *map; char *mapitems[MAXARGS]; struct syment *sp, syment; if ((map = fopen(pc->system_map, "r")) == NULL) error(FATAL, "cannot open %s\n", pc->system_map); symcount = 0; while (fgets(buf, BUFSIZE, map)) symcount++; if ((st->symtable = (struct syment *) calloc(symcount, sizeof(struct syment))) == NULL) error(FATAL, "symbol table syment space malloc: %s\n", strerror(errno)); if (!namespace_ctl(NAMESPACE_INIT, &st->kernel_namespace, (void *)symcount, NULL)) error(FATAL, "symbol table namespace malloc: %s\n", strerror(errno)); if (!machine_type("X86")) kt->flags &= ~RELOC_SET; first = 0; st->syment_size = symcount * sizeof(struct syment); st->symcnt = 0; sp = st->symtable; rewind(map); while (fgets(buf, BUFSIZE, map)) { if ((c = parse_line(buf, mapitems)) != 3) continue; syment.value = htol(mapitems[0], FAULT_ON_ERROR, NULL); syment.type = mapitems[1][0]; syment.name = mapitems[2]; strcpy(name, syment.name); strip_symbol_end(name, NULL); if (machdep->verify_symbol(name, syment.value, syment.type)) { if (kt->flags & RELOC_SET) sp->value = relocate(syment.value, syment.name, !(first++)); else sp->value = syment.value; sp->type = syment.type; namespace_ctl(NAMESPACE_INSTALL, &st->kernel_namespace, sp, name); sp++; st->symcnt++; } } fclose(map); st->symend = &st->symtable[st->symcnt]; st->flags |= KERNEL_SYMS; namespace_ctl(NAMESPACE_COMPLETE, &st->kernel_namespace, st->symtable, st->symend); symname_hash_init(); symval_hash_init(); } /* * Handle x86 kernels configured such that the vmlinux symbols * are not as loaded into the kernel (not unity-mapped). */ static ulong relocate(ulong symval, char *symname, int first_symbol) { if (XEN_HYPER_MODE()) { kt->flags &= ~(RELOC_SET|RELOC_FORCE); return symval; } switch (kt->flags & (RELOC_SET|RELOC_FORCE)) { case RELOC_SET: break; case RELOC_FORCE: if (first_symbol && !relocate_force(symval, symname)) kt->flags &= ~RELOC_FORCE; break; } return (symval - kt->relocate); } /* * If no --reloc argument was passed, try to figure it out * by comparing the first vmlinux kernel symbol with the * first /proc/kallsyms symbol. (should be "_text") * * Live system only (at least for now). */ static int relocate_force(ulong symval, char *symname) { int count, found; FILE *kp; char buf[BUFSIZE]; char *kallsyms[MAXARGS]; ulong kallsym; if (!ACTIVE() || !file_exists("/proc/kallsyms", NULL)) { if (CRASHDEBUG(1)) fprintf(fp, "cannot determine relocation value: %s\n", !ACTIVE() ? "not a live system" : "/proc/kallsyms does not exist"); return FALSE; } if ((kp = fopen("/proc/kallsyms", "r")) == NULL) { if (CRASHDEBUG(1)) fprintf(fp, "cannot open /proc/kallsyms to determine relocation\n"); return FALSE; } if (CRASHDEBUG(1)) fprintf(fp, "relocate from: %s\n" " %s @ %lx\n" "relocate to: /proc/kallsyms\n", pc->namelist, symname, symval); found = FALSE; count = kallsym = 0; while (!found && fgets(buf, BUFSIZE, kp) && (parse_line(buf, kallsyms) == 3) && hexadecimal(kallsyms[0], 0)) { if (STREQ(kallsyms[2], symname)) { kallsym = htol(kallsyms[0], RETURN_ON_ERROR, NULL); found = TRUE; } count++; if (CRASHDEBUG(1)) fprintf(fp, " %s @ %s %s\n", kallsyms[2], kallsyms[0], STREQ(kallsyms[2], symname) ? "(match!)" : ""); } fclose(kp); /* * If the symbols match and have different values, * force the relocation. */ if (found) { if (symval != kallsym) { kt->relocate = symval - kallsym; return TRUE; } } if (CRASHDEBUG(1)) fprintf(fp, "cannot determine relocation value from" " %d symbols in /proc/kallsyms\n", count); return FALSE; } /* * Install all static kernel symbol values into the symval_hash. */ static void symval_hash_init(void) { int index; struct syment *sp, *sph; for (sp = st->symtable; sp < st->symend; sp++) { index = SYMVAL_HASH_INDEX(sp->value); if (st->symval_hash[index].val_hash_head == NULL) { st->symval_hash[index].val_hash_head = sp; st->symval_hash[index].val_hash_last = sp; continue; } sph = st->symval_hash[index].val_hash_head; while (sph->val_hash_next) sph = sph->val_hash_next; sph->val_hash_next = sp; } } /* * Static kernel symbol value search */ static struct syment * symval_hash_search(ulong value) { int index; struct syment *sp, *splo; index = SYMVAL_HASH_INDEX(value); if (!st->symval_hash[index].val_hash_head) return NULL; st->val_hash_searches += 1; st->val_hash_iterations += 1; if (st->symval_hash[index].val_hash_last->value <= value) sp = st->symval_hash[index].val_hash_last; else sp = st->symval_hash[index].val_hash_head; for (splo = NULL; sp; sp = sp->val_hash_next) { if (sp->value == value) { st->symval_hash[index].val_hash_last = sp; return sp; } if (sp->value > value) break; st->val_hash_iterations += 1; splo = sp; } if (splo) st->symval_hash[index].val_hash_last = splo; return splo; } /* * Store all kernel static symbols into the symname_hash. */ static void symname_hash_init(void) { struct syment *sp; for (sp = st->symtable; sp < st->symend; sp++) symname_hash_install(sp); if ((sp = symbol_search("__per_cpu_start"))) st->__per_cpu_start = sp->value; if ((sp = symbol_search("__per_cpu_end"))) st->__per_cpu_end = sp->value; } /* * Install a single static kernel symbol into the symname_hash. */ static void symname_hash_install(struct syment *spn) { struct syment *sp; int index; index = SYMNAME_HASH_INDEX(spn->name); spn->cnt = 1; if ((sp = st->symname_hash[index]) == NULL) st->symname_hash[index] = spn; else { while (sp) { if (STREQ(sp->name, spn->name)) { sp->cnt++; spn->cnt++; } if (sp->name_hash_next) sp = sp->name_hash_next; else { sp->name_hash_next = spn; break; } } } } /* * Static kernel symbol value search */ static struct syment * symname_hash_search(char *name) { struct syment *sp; sp = st->symname_hash[SYMNAME_HASH_INDEX(name)]; while (sp) { if (STREQ(sp->name, name)) return sp; sp = sp->name_hash_next; } return NULL; } /* * Output for sym -[lL] command. */ #define MODULE_PSEUDO_SYMBOL(sp) \ ((STRNEQ((sp)->name, "_MODULE_START_") || STRNEQ((sp)->name, "_MODULE_END_")) || \ (STRNEQ((sp)->name, "_MODULE_INIT_START_") || STRNEQ((sp)->name, "_MODULE_INIT_END_")) || \ (STRNEQ((sp)->name, "_MODULE_SECTION_"))) #define MODULE_START(sp) (STRNEQ((sp)->name, "_MODULE_START_")) #define MODULE_END(sp) (STRNEQ((sp)->name, "_MODULE_END_")) #define MODULE_INIT_START(sp) (STRNEQ((sp)->name, "_MODULE_INIT_START_")) #define MODULE_INIT_END(sp) (STRNEQ((sp)->name, "_MODULE_INIT_END_")) #define MODULE_SECTION_START(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_START")) #define MODULE_SECTION_END(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_END")) static void symbol_dump(ulong flags, char *module) { int i, start, percpu_syms; struct syment *sp, *sp_end; struct load_module *lm; char *p1, *p2;; #define TBD 1 #define DISPLAYED 2 if (flags & KERNEL_SYMS) { for (sp = st->symtable; sp < st->symend; sp++) { show_symbol(sp, 0, SHOW_RADIX()); if (received_SIGINT() || output_closed()) return; } } if (!(flags & MODULE_SYMS)) return; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (module && !STREQ(module, lm->mod_name)) continue; if (received_SIGINT() || output_closed()) return; sp = lm->mod_symtable; sp_end = lm->mod_symend; percpu_syms = 0; for (start = FALSE; sp <= sp_end; sp++) { if (IN_MODULE_PERCPU(sp->value, lm)) { if (percpu_syms == DISPLAYED) continue; if (!start) { percpu_syms = TBD; continue; } dump_percpu_symbols(lm); percpu_syms = DISPLAYED; } if (MODULE_PSEUDO_SYMBOL(sp)) { if (MODULE_SECTION_START(sp)) { p1 = sp->name + strlen("_MODULE_SECTION_START "); p2 = "section start"; } else if (MODULE_SECTION_END(sp)) { p1 = sp->name + strlen("_MODULE_SECTION_END "); p2 = "section end"; } else if (MODULE_START(sp)) { p1 = "MODULE START"; p2 = sp->name+strlen("_MODULE_START_"); start = TRUE; } else { p1 = "MODULE END"; p2 = sp->name+strlen("_MODULE_END_"); if (MODULE_PERCPU_SYMS_LOADED(lm) && !percpu_syms) { dump_percpu_symbols(lm); percpu_syms = DISPLAYED; } } fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2); if (percpu_syms == TBD) { dump_percpu_symbols(lm); percpu_syms = DISPLAYED; } } else show_symbol(sp, 0, SHOW_RADIX()); } if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp <= sp_end; sp++) { if (MODULE_PSEUDO_SYMBOL(sp)) { if (MODULE_INIT_START(sp)) { p1 = "MODULE INIT START"; p2 = sp->name+strlen("_MODULE_INIT_START_"); } else { p1 = "MODULE INIT END"; p2 = sp->name+strlen("_MODULE_INIT_END_"); } fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2); } else show_symbol(sp, 0, SHOW_RADIX()); } } } #undef TBD #undef DISPLAYED } static void dump_percpu_symbols(struct load_module *lm) { struct syment *sp, *sp_end; if (MODULE_PERCPU_SYMS_LOADED(lm)) { sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp <= sp_end; sp++) { if (IN_MODULE_PERCPU(sp->value, lm)) show_symbol(sp, 0, SHOW_RADIX()); } } } /* * Get a pointer to the desired asection. */ static asection * get_kernel_section(char *name) { int i; asection **sec; sec = (asection **)st->sections; for (i = 0; i < st->bfd->section_count; i++, sec++) { if (STREQ(name, (*sec)->name)) return(*sec); } return NULL; } /* * Walk through the current set of symbols and check for duplicates. */ static void check_for_dups(struct load_module *lm) { struct syment *sp, *sp_end; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp <= sp_end; sp++) { if (symbol_name_count(sp->name) > 1) error(NOTE, "%s: duplicate symbol name: %s\n", lm->mod_name, sp->name); } } /* * Store the externally declared symbols for all modules in the system. * allowing for dynamic loading of symbols from individual mod object files * during runtime. */ struct module_symbol { unsigned long value; const char *name; }; void store_module_symbols_v1(ulong total, int mods_installed) { int i, m; ulong mod, mod_next, mod_name; uint nsyms; ulong syms, size_of_struct; long strbuflen, size; int mcnt, lm_mcnt; struct module_symbol *modsym; struct load_module *lm; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char name[BUFSIZE]; char rodata[BUFSIZE]; char *strbuf, *modbuf, *modsymbuf; struct syment *sp; ulong first, last; st->mods_installed = mods_installed; if (!st->mods_installed) { st->flags &= ~MODULE_SYMS; return; } /* * If we've been here before, free up everything and start over. */ if (st->flags & MODULE_SYMS) { error(FATAL, "re-initialization of module symbols not implemented yet!\n"); } if ((st->ext_module_symtable = (struct syment *) calloc(total, sizeof(struct syment))) == NULL) error(FATAL, "module syment space malloc: %s\n", strerror(errno)); if (!namespace_ctl(NAMESPACE_INIT, &st->ext_module_namespace, (void *)total, NULL)) error(FATAL, "module namespace malloc: %s\n", strerror(errno)); if ((st->load_modules = (struct load_module *)calloc (st->mods_installed, sizeof(struct load_module))) == NULL) error(FATAL, "load_module array malloc: %s\n", strerror(errno)); modbuf = GETBUF(SIZE(module)); modsymbuf = NULL; m = mcnt = mod_next = 0; for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { readmem(mod, KVADDR, modbuf, SIZE(module), "module buffer", FAULT_ON_ERROR); nsyms = UINT(modbuf + OFFSET(module_nsyms)); syms = ULONG(modbuf + OFFSET(module_syms)); size = LONG(modbuf + OFFSET(module_size)); mod_name = ULONG(modbuf + OFFSET(module_name)); size_of_struct = ULONG(modbuf + OFFSET(module_size_of_struct)); if (!read_string(mod_name, name, BUFSIZE-1)) sprintf(name, "(unknown module)"); sprintf(rodata, "__insmod_%s_S.rodata", name); lm = &st->load_modules[m++]; BZERO(lm, sizeof(struct load_module)); lm->mod_base = lm->module_struct = mod; lm->mod_size = size; lm->mod_size_of_struct = size_of_struct; if (strlen(name) < MAX_MOD_NAME) strcpy(lm->mod_name, name); else { error(INFO, "module name greater than MAX_MOD_NAME: %s\n", name); strncpy(lm->mod_name, name, MAX_MOD_NAME-1); } lm->mod_flags = MOD_EXT_SYMS; lm->mod_ext_symcnt = mcnt; lm->mod_etext_guess = 0; st->ext_module_symtable[mcnt].value = mod; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_START_", name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf2); lm_mcnt = mcnt; mcnt++; if (nsyms) { modsymbuf = GETBUF(sizeof(struct module_symbol)*nsyms); readmem((ulong)syms, KVADDR, modsymbuf, nsyms * sizeof(struct module_symbol), "module symbols", FAULT_ON_ERROR); } for (i = first = last = 0; i < nsyms; i++) { modsym = (struct module_symbol *) (modsymbuf + (i * sizeof(struct module_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; } if (last > first) { strbuflen = (last-first) + BUFSIZE; if ((first + strbuflen) >= (lm->mod_base + lm->mod_size)) { strbuflen = (lm->mod_base + lm->mod_size) - first; } strbuf = GETBUF(strbuflen); if (!readmem(first, KVADDR, strbuf, strbuflen, "module symbol strings", RETURN_ON_ERROR)) { FREEBUF(strbuf); strbuf = NULL; } } else strbuf = NULL; for (i = first = last = 0; i < nsyms; i++) { modsym = (struct module_symbol *) (modsymbuf + (i * sizeof(struct module_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; BZERO(buf1, BUFSIZE); if (strbuf) strcpy(buf1, &strbuf[(ulong)modsym->name - first]); else read_string((ulong)modsym->name, buf1, BUFSIZE-1); if (strlen(buf1)) { st->ext_module_symtable[mcnt].value = modsym->value; st->ext_module_symtable[mcnt].type = '?'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; strip_module_symbol_end(buf1); strip_symbol_end(buf1, NULL); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf1); if (strstr(buf1, rodata)) lm->mod_etext_guess = modsym->value; sprintf(buf2, "__insmod_%s_O/", lm->mod_name); if (strstr(buf1, buf2) && !strstr(buf1, "modules")) lm->mod_flags |= MOD_INITRD; mcnt++; } } if (modsymbuf) { FREEBUF(modsymbuf); modsymbuf = NULL; } if (strbuf) FREEBUF(strbuf); /* * If the module was compiled with kallsyms, add them in. */ switch (kt->flags & (KALLSYMS_V1|KALLSYMS_V2)) { case KALLSYMS_V1: mcnt += store_module_kallsyms_v1(lm, lm_mcnt, mcnt, modbuf); break; case KALLSYMS_V2: /* impossible, I hope... */ mcnt += store_module_kallsyms_v2(lm, lm_mcnt, mcnt, modbuf); break; } st->ext_module_symtable[mcnt].value = mod + size; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_END_", name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf2); mcnt++; lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt; if (!lm->mod_etext_guess) find_mod_etext(lm); NEXT_MODULE(mod_next, modbuf); } FREEBUF(modbuf); st->ext_module_symcnt = mcnt; st->ext_module_symend = &st->ext_module_symtable[mcnt]; namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace, st->ext_module_symtable, st->ext_module_symend); qsort(st->ext_module_symtable, mcnt, sizeof(struct syment), compare_syms); qsort(st->load_modules, m, sizeof(struct load_module), compare_mods); for (m = 0; m < st->mods_installed; m++) { lm = &st->load_modules[m]; sprintf(buf1, "_MODULE_START_%s", lm->mod_name); sprintf(buf2, "_MODULE_END_%s", lm->mod_name); for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) { if (STREQ(sp->name, buf1)) { lm->mod_ext_symtable = sp; lm->mod_symtable = sp; } if (STREQ(sp->name, buf2)) { lm->mod_ext_symend = sp; lm->mod_symend = sp; } } } st->flags |= MODULE_SYMS; if (symbol_query("__insmod_", NULL, NULL)) st->flags |= INSMOD_BUILTIN; } struct kernel_symbol { unsigned long value; const char *name; }; void store_module_symbols_v2(ulong total, int mods_installed) { int i, m; ulong mod, mod_next; char *mod_name; uint nsyms, ngplsyms; ulong syms, gpl_syms; ulong nksyms; long strbuflen; ulong size; int mcnt, lm_mcnt; struct kernel_symbol *modsym; struct load_module *lm; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; char *strbuf, *modbuf, *modsymbuf; struct syment *sp; ulong first, last; st->mods_installed = mods_installed; if (!st->mods_installed) { st->flags &= ~MODULE_SYMS; return; } /* * If we've been here before, free up everything and start over. */ if (st->flags & MODULE_SYMS) { error(FATAL, "re-initialization of module symbols not implemented yet!\n"); } if ((st->ext_module_symtable = (struct syment *) calloc(total, sizeof(struct syment))) == NULL) error(FATAL, "v2 module syment space malloc (%ld symbols): %s\n", total, strerror(errno)); if (!namespace_ctl(NAMESPACE_INIT, &st->ext_module_namespace, (void *)total, NULL)) error(FATAL, "module namespace malloc: %s\n", strerror(errno)); if ((st->load_modules = (struct load_module *)calloc (st->mods_installed, sizeof(struct load_module))) == NULL) error(FATAL, "load_module array malloc: %s\n", strerror(errno)); modbuf = GETBUF(SIZE(module)); modsymbuf = NULL; m = mcnt = mod_next = 0; for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { readmem(mod, KVADDR, modbuf, SIZE(module), "module buffer", FAULT_ON_ERROR); syms = ULONG(modbuf + OFFSET(module_syms)); gpl_syms = ULONG(modbuf + OFFSET(module_gpl_syms)); nsyms = UINT(modbuf + OFFSET(module_num_syms)); ngplsyms = UINT(modbuf + OFFSET(module_num_gpl_syms)); if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { nksyms = UINT(modbuf + OFFSET(module_num_symtab)); size = UINT(modbuf + OFFSET(module_core_size)); } else { nksyms = ULONG(modbuf + OFFSET(module_num_symtab)); size = ULONG(modbuf + OFFSET(module_core_size)); } mod_name = modbuf + OFFSET(module_name); lm = &st->load_modules[m++]; BZERO(lm, sizeof(struct load_module)); lm->mod_base = ULONG(modbuf + OFFSET(module_module_core)); lm->module_struct = mod; lm->mod_size = size; if (strlen(mod_name) < MAX_MOD_NAME) strcpy(lm->mod_name, mod_name); else { error(INFO, "module name greater than MAX_MOD_NAME: %s\n", mod_name); strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1); } if (CRASHDEBUG(3)) fprintf(fp, "%lx (%lx): %s syms: %d gplsyms: %d ksyms: %ld\n", mod, lm->mod_base, lm->mod_name, nsyms, ngplsyms, nksyms); lm->mod_flags = MOD_EXT_SYMS; lm->mod_ext_symcnt = mcnt; lm->mod_init_module_ptr = ULONG(modbuf + OFFSET(module_module_init)); if (VALID_MEMBER(module_percpu)) lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu)); if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { lm->mod_etext_guess = lm->mod_base + UINT(modbuf + OFFSET(module_core_text_size)); lm->mod_init_size = UINT(modbuf + OFFSET(module_init_size)); lm->mod_init_text_size = UINT(modbuf + OFFSET(module_init_text_size)); } else { lm->mod_etext_guess = lm->mod_base + ULONG(modbuf + OFFSET(module_core_text_size)); lm->mod_init_size = ULONG(modbuf + OFFSET(module_init_size)); lm->mod_init_text_size = ULONG(modbuf + OFFSET(module_init_text_size)); } lm->mod_text_start = lm->mod_base; st->ext_module_symtable[mcnt].value = lm->mod_base; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_START_", mod_name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf2); lm_mcnt = mcnt; mcnt++; if (lm->mod_init_size > 0) { st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf3, "%s%s", "_MODULE_INIT_START_", mod_name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf3); lm_mcnt = mcnt; mcnt++; lm->mod_flags |= MOD_INIT; } if (nsyms && !IN_MODULE(syms, lm)) { error(WARNING, "[%s] module.syms outside of module " "address space (%lx)\n\n", lm->mod_name, syms); nsyms = 0; } if (nsyms) { modsymbuf = GETBUF(sizeof(struct kernel_symbol)*nsyms); readmem((ulong)syms, KVADDR, modsymbuf, nsyms * sizeof(struct kernel_symbol), "module symbols", FAULT_ON_ERROR); } for (i = first = last = 0; i < nsyms; i++) { modsym = (struct kernel_symbol *) (modsymbuf + (i * sizeof(struct kernel_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; } if (last > first) { strbuflen = (last-first) + BUFSIZE; if ((first + strbuflen) >= (lm->mod_base + lm->mod_size)) { strbuflen = (lm->mod_base + lm->mod_size) - first; } strbuf = GETBUF(strbuflen); if (!readmem(first, KVADDR, strbuf, strbuflen, "module symbol strings", RETURN_ON_ERROR)) { FREEBUF(strbuf); strbuf = NULL; } } else strbuf = NULL; for (i = first = last = 0; i < nsyms; i++) { modsym = (struct kernel_symbol *) (modsymbuf + (i * sizeof(struct kernel_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; BZERO(buf1, BUFSIZE); if (strbuf) strcpy(buf1, &strbuf[(ulong)modsym->name - first]); else read_string((ulong)modsym->name, buf1, BUFSIZE-1); if (strlen(buf1)) { st->ext_module_symtable[mcnt].value = modsym->value; st->ext_module_symtable[mcnt].type = '?'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; strip_module_symbol_end(buf1); strip_symbol_end(buf1, NULL); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf1); mcnt++; } } if (modsymbuf) { FREEBUF(modsymbuf); modsymbuf = NULL; } if (strbuf) FREEBUF(strbuf); if (ngplsyms) { modsymbuf = GETBUF(sizeof(struct kernel_symbol) * ngplsyms); readmem((ulong)gpl_syms, KVADDR, modsymbuf, ngplsyms * sizeof(struct kernel_symbol), "module gpl symbols", FAULT_ON_ERROR); } for (i = first = last = 0; i < ngplsyms; i++) { modsym = (struct kernel_symbol *) (modsymbuf + (i * sizeof(struct kernel_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; } if (last > first) { strbuflen = (last-first) + BUFSIZE; if ((first + strbuflen) >= (lm->mod_base + lm->mod_size)) { strbuflen = (lm->mod_base + lm->mod_size) - first; } strbuf = GETBUF(strbuflen); if (!readmem(first, KVADDR, strbuf, strbuflen, "module gpl symbol strings", RETURN_ON_ERROR)) { FREEBUF(strbuf); strbuf = NULL; } } else strbuf = NULL; for (i = first = last = 0; i < ngplsyms; i++) { modsym = (struct kernel_symbol *) (modsymbuf + (i * sizeof(struct kernel_symbol))); if (!first) first = (ulong)modsym->name; last = (ulong)modsym->name; BZERO(buf1, BUFSIZE); if (strbuf) strcpy(buf1, &strbuf[(ulong)modsym->name - first]); else read_string((ulong)modsym->name, buf1, BUFSIZE-1); if (strlen(buf1)) { st->ext_module_symtable[mcnt].value = modsym->value; st->ext_module_symtable[mcnt].type = '?'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; strip_module_symbol_end(buf1); strip_symbol_end(buf1, NULL); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf1); mcnt++; } } if (modsymbuf) { FREEBUF(modsymbuf); modsymbuf = NULL; } if (strbuf) FREEBUF(strbuf); /* * If the module was compiled with kallsyms, add them in. */ switch (kt->flags & (KALLSYMS_V1|KALLSYMS_V2)) { case KALLSYMS_V1: /* impossible, I hope... */ mcnt += store_module_kallsyms_v1(lm, lm_mcnt, mcnt, modbuf); break; case KALLSYMS_V2: mcnt += store_module_kallsyms_v2(lm, lm_mcnt, mcnt, modbuf); break; } st->ext_module_symtable[mcnt].value = lm->mod_base + size; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf2, "%s%s", "_MODULE_END_", mod_name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf2); mcnt++; if (lm->mod_init_size > 0) { st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr + lm->mod_init_size; st->ext_module_symtable[mcnt].type = 'm'; st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; sprintf(buf4, "%s%s", "_MODULE_INIT_END_", mod_name); namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt], buf4); mcnt++; } lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt; if (!lm->mod_etext_guess) find_mod_etext(lm); NEXT_MODULE(mod_next, modbuf); } FREEBUF(modbuf); st->ext_module_symcnt = mcnt; st->ext_module_symend = &st->ext_module_symtable[mcnt]; namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace, st->ext_module_symtable, st->ext_module_symend); qsort(st->ext_module_symtable, mcnt, sizeof(struct syment), compare_syms); qsort(st->load_modules, m, sizeof(struct load_module), compare_mods); for (m = 0; m < st->mods_installed; m++) { lm = &st->load_modules[m]; sprintf(buf1, "_MODULE_START_%s", lm->mod_name); sprintf(buf2, "_MODULE_END_%s", lm->mod_name); sprintf(buf3, "_MODULE_INIT_START_%s", lm->mod_name); sprintf(buf4, "_MODULE_INIT_END_%s", lm->mod_name); for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) { if (STREQ(sp->name, buf1)) { lm->mod_ext_symtable = sp; lm->mod_symtable = sp; } if (STREQ(sp->name, buf2)) { lm->mod_ext_symend = sp; lm->mod_symend = sp; } if (STREQ(sp->name, buf3)) { lm->mod_init_symtable = sp; } if (STREQ(sp->name, buf4)) { lm->mod_init_symend = sp; } } } st->flags |= MODULE_SYMS; if (symbol_query("__insmod_", NULL, NULL)) st->flags |= INSMOD_BUILTIN; if (mcnt > total) error(FATAL, "store_module_symbols_v2: total: %ld mcnt: %d\n", total, mcnt); } /* * Get the module's kallsyms list if it was compiled in. */ static int store_module_kallsyms_v1(struct load_module *lm, int start, int curr, char *modbuf) { int i, j; struct syment *sp; ulong kallsyms_header; char *module_buf; char *header_buf; uint symbols; ulong name_off; ulong sec_name_off; ulong section_off; ulong symptr; ulong symbol_addr; ulong stringptr; ulong sectionptr; char *nameptr; char *secnameptr; ulong secptr; char type; int mcnt; int mcnt_idx; int found; struct symbol_namespace *ns; if (!(kt->flags & KALLSYMS_V1)) return 0; kallsyms_header = ULONG(modbuf + OFFSET(module_kallsyms_start)); if (!kallsyms_header) return 0; mcnt = 0; mcnt_idx = curr; module_buf = GETBUF(ULONG(modbuf + OFFSET(module_size))); ns = &st->ext_module_namespace; if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size, "module (kallsyms)", RETURN_ON_ERROR|QUIET)) { error(WARNING,"cannot access module kallsyms\n"); FREEBUF(module_buf); return 0; } #define IN_MODULE_BUF_V1(x) \ (((x) >= module_buf) && ((x) < (module_buf + lm->mod_size))) header_buf = module_buf + (kallsyms_header - lm->mod_base); symbols = UINT(header_buf + OFFSET(kallsyms_header_symbols)); // sections = UINT(header_buf + OFFSET(kallsyms_header_sections)); if (CRASHDEBUG(7)) fprintf(fp, "kallsyms: module: %s\n", lm->mod_name); symptr = (ulong)(header_buf + ULONG(header_buf + OFFSET(kallsyms_header_symbol_off))); stringptr = (ulong)(header_buf + ULONG(header_buf + OFFSET(kallsyms_header_string_off))); sectionptr = (ulong)(header_buf + ULONG(header_buf + OFFSET(kallsyms_header_section_off))); for (i = 0; i < symbols; i++, symptr += SIZE(kallsyms_symbol)) { symbol_addr = ULONG(symptr+OFFSET(kallsyms_symbol_symbol_addr)); name_off = ULONG(symptr+OFFSET(kallsyms_symbol_name_off)); section_off = ULONG(symptr+OFFSET(kallsyms_symbol_section_off)); nameptr = (char *)(stringptr + name_off); secptr = (ulong)(sectionptr + section_off); sec_name_off = ULONG(secptr+OFFSET(kallsyms_section_name_off)); secnameptr = (char *)(stringptr + sec_name_off); if (!IN_MODULE_BUF_V1(nameptr)) { if (CRASHDEBUG(7)) error(INFO, "%s: invalid nameptr: %lx (stringptr: %lx + name_off: %lx)\n", lm->mod_name, nameptr, stringptr, name_off); continue; } if (!IN_MODULE_BUF_V1(secnameptr)) { if (CRASHDEBUG(7)) error(INFO, "%s: invalid secnameptr: %lx (stringptr: %lx + sec_name_off: %lx)\n", lm->mod_name, secnameptr, stringptr, sec_name_off); continue; } if (!STREQ(nameptr, secnameptr)) { if (STREQ(secnameptr, ".text")) type = 't'; else if (STREQ(secnameptr, ".data")) type = 'd'; else if (STREQ(secnameptr, ".bss")) type = 'b'; else if (STREQ(secnameptr, ".rodata")) type = 'd'; else continue; strip_module_symbol_end(nameptr); strip_symbol_end(nameptr, NULL); if (CRASHDEBUG(7)) fprintf(fp," symbol: %lx \"%s\" section: %s\n", symbol_addr, nameptr, secnameptr); for (found = 0, j = start; j < curr; j++) { sp = &st->ext_module_symtable[j]; if ((sp->value == symbol_addr) && STREQ(nameptr, &ns->address[(ulong)sp->name])) { if (CRASHDEBUG(7)) fprintf(fp, "current symbol \"%s\" at %lx of type (%c)\n", &ns->address[(ulong)sp->name], sp->value, sp->type); if (sp->type == '?') sp->type = type; found++; break; } } if (found) continue; st->ext_module_symtable[mcnt_idx].value = symbol_addr; st->ext_module_symtable[mcnt_idx].type = type; st->ext_module_symtable[mcnt_idx].flags |= MODULE_SYMBOL; namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt_idx++], nameptr); mcnt++; } } lm->mod_flags |= MOD_KALLSYMS; FREEBUF(module_buf); return mcnt; } /* * Translate either an Elf32_Sym or Elf64_Sym to an elf_common structure * for more convenient use by store_module_kallsyms_v2(). */ struct elf_common { ulong st_name; ulong st_value; ulong st_shndx; unsigned char st_info; }; static void Elf32_Sym_to_common(Elf32_Sym *e32, struct elf_common *ec) { ec->st_name = (ulong)e32->st_name; ec->st_value = (ulong)e32->st_value; ec->st_shndx = (ulong)e32->st_shndx; ec->st_info = e32->st_info; } static void Elf64_Sym_to_common(Elf64_Sym *e64, struct elf_common *ec) { ec->st_name = (ulong)e64->st_name; ec->st_value = (ulong)e64->st_value; ec->st_shndx = (ulong)e64->st_shndx; ec->st_info = e64->st_info; } static int store_module_kallsyms_v2(struct load_module *lm, int start, int curr, char *modbuf) { int i, j, found; struct elf_common elf_common, *ec; ulong nksyms, ksymtab, kstrtab; char *module_buf, *ptr, *locsymtab, *locstrtab, *nameptr; struct syment *sp; struct symbol_namespace *ns; int mcnt; int mcnt_idx; char *module_buf_init = NULL; if (!(kt->flags & KALLSYMS_V2)) return 0; mcnt = 0; BZERO(&elf_common, sizeof(struct elf_common)); mcnt_idx = curr; ns = &st->ext_module_namespace; ec = &elf_common; module_buf = GETBUF(lm->mod_size); if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size, "module (kallsyms)", RETURN_ON_ERROR|QUIET)) { error(WARNING,"cannot access module kallsyms\n"); FREEBUF(module_buf); return 0; } if (lm->mod_init_size > 0) { module_buf_init = GETBUF(lm->mod_init_size); if (!readmem(lm->mod_init_module_ptr, KVADDR, module_buf_init, lm->mod_init_size, "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) { error(WARNING,"cannot access module init kallsyms\n"); FREEBUF(module_buf_init); } } if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) nksyms = UINT(modbuf + OFFSET(module_num_symtab)); else nksyms = ULONG(modbuf + OFFSET(module_num_symtab)); ksymtab = ULONG(modbuf + OFFSET(module_symtab)); if (!IN_MODULE(ksymtab, lm) && !IN_MODULE_INIT(ksymtab, lm)) { error(WARNING, "%s: module.symtab outside of module address space\n", lm->mod_name); FREEBUF(module_buf); if (module_buf_init) FREEBUF(module_buf_init); return 0; } if (IN_MODULE(ksymtab, lm)) locsymtab = module_buf + (ksymtab - lm->mod_base); else locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr); kstrtab = ULONG(modbuf + OFFSET(module_strtab)); if (!IN_MODULE(kstrtab, lm) && !IN_MODULE_INIT(kstrtab, lm)) { error(WARNING, "%s: module.strtab outside of module address space\n", lm->mod_name); FREEBUF(module_buf); if (module_buf_init) FREEBUF(module_buf_init); return 0; } if (IN_MODULE(kstrtab, lm)) locstrtab = module_buf + (kstrtab - lm->mod_base); else locstrtab = module_buf_init + (kstrtab - lm->mod_init_module_ptr); for (i = 1; i < nksyms; i++) { /* ELF starts real symbols at 1 */ switch (BITS()) { case 32: ptr = locsymtab + (i * sizeof(Elf32_Sym)); Elf32_Sym_to_common((Elf32_Sym *)ptr, ec); break; case 64: ptr = locsymtab + (i * sizeof(Elf64_Sym)); Elf64_Sym_to_common((Elf64_Sym *)ptr, ec); break; } if (((ec->st_value < lm->mod_base) || (ec->st_value > (lm->mod_base + lm->mod_size))) && ((ec->st_value < lm->mod_init_module_ptr) || (ec->st_value > (lm->mod_init_module_ptr + lm->mod_init_size)))) continue; if (ec->st_shndx == SHN_UNDEF) continue; if (!IN_MODULE(kstrtab + ec->st_name, lm) && !IN_MODULE_INIT(kstrtab + ec->st_name, lm)) { if (CRASHDEBUG(3)) { error(WARNING, "%s: bad st_name index: %lx -> %lx\n " " st_value: %lx st_shndx: %ld st_info: %c\n", lm->mod_name, ec->st_name, (kstrtab + ec->st_name), ec->st_value, ec->st_shndx, ec->st_info); } continue; } nameptr = locstrtab + ec->st_name; if (*nameptr == '\0') continue; /* * On ARM we have linker mapping symbols like '$a' and '$d'. * Make sure that these don't end up into our symbol list. */ if (machine_type("ARM") && !machdep->verify_symbol(nameptr, ec->st_value, ec->st_info)) continue; if (CRASHDEBUG(7)) fprintf(fp, "%s: st_name: %ld st_value: %lx st_shndx: %ld st_info: %c\n", nameptr, ec->st_name, ec->st_value, ec->st_shndx, ec->st_info); strip_symbol_end(nameptr, NULL); for (found = 0, j = start; j < curr; j++) { sp = &st->ext_module_symtable[j]; if ((sp->value == ec->st_value) && STREQ(nameptr, &ns->address[(ulong)sp->name])) { if (CRASHDEBUG(7)) fprintf(fp, "current symbol \"%s\" at %lx of type (%c)\n", &ns->address[(ulong)sp->name], sp->value, sp->type); if (sp->type == '?') sp->type = ec->st_info; found++; break; } } if (found) continue; st->ext_module_symtable[mcnt_idx].value = ec->st_value; st->ext_module_symtable[mcnt_idx].type = ec->st_info; st->ext_module_symtable[mcnt_idx].flags |= MODULE_SYMBOL; namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, &st->ext_module_symtable[mcnt_idx++], nameptr); mcnt++; } lm->mod_flags |= MOD_KALLSYMS; FREEBUF(module_buf); if (module_buf_init) FREEBUF(module_buf_init); return mcnt; } /* * Strip the kernel clutter tagged on the end of an exported module symbol. */ static void strip_module_symbol_end(char *buf) { char *p1, *lastR; if (!(lastR = strrchr(buf, 'R'))) return; if (((p1 = lastR-1) < buf) || (*p1 != '_')) return; if ((kt->flags & SMP) && STRNEQ(p1, "_Rsmp_")) { *p1 = NULLCHAR; return; } if (!hexadecimal(lastR+1, 0)) return; *p1 = NULLCHAR; } /* * Return the lowest or highest module virtual address. */ ulong lowest_module_address(void) { int i; struct load_module *lm; ulong low, lowest; if (!st->mods_installed) return 0; lowest = (ulong)(-1); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; low = lm->mod_base; if (low < lowest) lowest = low; } return lowest; } ulong highest_module_address(void) { int i; struct load_module *lm; ulong high, highest; highest = 0; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; high = lm->mod_base + lm->mod_size; if (high > highest) highest = high; } return highest; } /* * Look through a string for bogus kernel clutter of an exported * module symbol. In the case of LM_P_FILTER, shift the string left * as appropriate to get rid of the extra stuff. In the case of * LM_DIS_FILTER, translation of the previous address is done first, * and its results are stuffed into the string. In both cases, * this routine is recursive to catch multiple instances. */ #define SMP_CLUTTER (strlen("_Rsmp_")) #define UP_CLUTTER (strlen("_R")) #define CLUTTER_IDLEN (8) char * load_module_filter(char *s, int type) { char *arglist[MAXARGS]; char buf1[BUFSIZE]; char buf2[BUFSIZE]; int clen, last; int prev; char *pstart, *p1, *p2, *smp, *pend, *colon; ulong vaddr; ulong offset; struct syment *sp; int argc; switch (type) { case LM_P_FILTER: if (!(pstart = strstr(s, "_R"))) return s; smp = strstr(s, "_Rsmp_"); pend = &s[strlen(s)]; p2 = pstart + (smp ? SMP_CLUTTER : UP_CLUTTER); if ((p2 >= pend) || !hexadecimal(p2, CLUTTER_IDLEN)) return s; clen = smp ? SMP_CLUTTER+CLUTTER_IDLEN : UP_CLUTTER+CLUTTER_IDLEN; if (bracketed(s, pstart, clen)) { /* hack it out for now */ pstart--; shift_string_left(pstart, clen+2); if (*pstart == ',') shift_string_left(pstart-1, 1); } else shift_string_left(pstart, clen); return (load_module_filter(s, type)); /* catch multiples */ case LM_DIS_FILTER: strip_beginning_whitespace(s); strcpy(buf1, s); argc = parse_line(buf1, arglist); if (argc < 2) return s; /* * Fix up the first half of the disassembly expression, * that is, the address and symbol to the left of the * colon. */ colon = NULL; if (hexadecimal(arglist[0], VADDR_PRLEN+2) && bracketed(arglist[1], &arglist[1][1], 0) && (colon = strstr(s, ":"))) { strcpy(buf2, colon+2); vaddr = htol(arglist[0], FAULT_ON_ERROR, NULL); if ((sp = value_search(vaddr, &offset))) { if (offset) sprintf(s, "%s <%s+%ld>:\t%s", arglist[0], sp->name, offset, buf2); else sprintf(s, "%s <%s>:\t%s", arglist[0], sp->name, buf2); } } /* * Now work on the second part -- if it exists. * Find a virtual address followed by a bracked symbol * at the end of the line. */ if (colon) { strcpy(buf1, s); argc = parse_line(buf1, arglist); colon = strstr(s, ":"); } last = argc-1; prev = argc-2; if (bracketed(arglist[last], &arglist[last][1], 0) && hexadecimal(arglist[prev], VADDR_PRLEN+2)) { vaddr = htol(arglist[prev], FAULT_ON_ERROR, NULL); p1 = strstr(s, arglist[last]); if ((sp = value_search(vaddr, &offset)) && !(colon && (p1 < colon))) { if (offset) sprintf(p1, "<%s+%ld>\n", sp->name, offset); else sprintf(p1, "<%s>\n", sp->name); } } pend = &s[strlen(s)-3]; if (STREQ(pend, ":\t\n")) LASTCHAR(s) = NULLCHAR; return s; default: return NULL; /* can't get here */ } } /* * Handle the various commands for controlling symbol string space: * * NAMESPACE_INIT: Allocates an estimated size for the string space. * NAMESPACE_REUSE: Resets appropriate fields to allow a previously * allocated module string buffer to be reused. * NAMESPACE_FREE: Frees (module) string space. * NAMESPACE_INSTALL: Copies a symbol name string into the next available * buffer space. If the string cannot be squeezed in, * the whole string space is reallocated, which may * change its starting address. For that reason, the * buffer index is temporarily stored in the sp->name * field, which NAMESPACE_COMPLETE later transforms into * the proper address when the buffer is set. * NAMESPACE_COMPLETE: Reallocs a completed string buffer to the exact * size that is required, and then calculates and stores * the proper addresses into the name fields of the * passed-in syment array. */ #define AVERAGE_SYMBOL_SIZE (16) static int namespace_ctl(int cmd, struct symbol_namespace *ns, void *nsarg1, void *nsarg2) { char *addr; struct syment *sp, *sp_end; char *name; long cnt; int len; switch (cmd) { case NAMESPACE_INIT: cnt = (long)nsarg1; if ((addr = calloc(cnt, AVERAGE_SYMBOL_SIZE)) == NULL) return FALSE; ns->address = addr; ns->index = 0; ns->cnt = 0; ns->size = cnt * AVERAGE_SYMBOL_SIZE; return TRUE; case NAMESPACE_REUSE: ns->index = 0; ns->cnt = 0; return TRUE; case NAMESPACE_FREE: if (!ns->address) error(FATAL, "attempt to free unallocated module namespace\n"); free(ns->address); ns->address = 0; ns->index = 0; ns->size = 0; ns->cnt = 0; return TRUE; case NAMESPACE_INSTALL: sp = (struct syment *)nsarg1; name = (char *)nsarg2; len = strlen(name)+1; if ((ns->index + len) >= ns->size) { if (!(addr = realloc(ns->address, ns->size*2))) error(FATAL, "symbol name space malloc: %s\n", strerror(errno)); ns->address = addr; ns->size *= 2; } sp->name = (char *)ns->index; BCOPY(name, &ns->address[ns->index], len); ns->index += len; ns->cnt++; return TRUE; case NAMESPACE_COMPLETE: sp = (struct syment *)nsarg1; sp_end = (struct syment *)nsarg2; if (ns->index < (ns->size-1)) { if ((addr = realloc(ns->address, ns->index+1))) { ns->address = addr; ns->size = ns->index+1; } } for ( ; sp < sp_end; sp++) sp->name = ns->address + (long)sp->name; return TRUE; default: return FALSE; /* can't get here */ } } /* * These comparison functions must return an integer less than, * equal to, or greater than zero if the first argument is * considered to be respectively less than, equal to, or * greater than the second. If two members compare as equal, * their order in the sorted array is undefined. */ static int compare_syms(const void *v1, const void *v2) { struct syment *s1, *s2; char sn1[BUFSIZE], sn2[BUFSIZE]; s1 = (struct syment *)v1; s2 = (struct syment *)v2; if (s1->value == s2->value) { if (STRNEQ(s1->name, "__insmod")) return -1; if (STRNEQ(s2->name, "__insmod")) return 1; if (STRNEQ(s2->name, "_MODULE_START_")) return 1; /* Get pseudo section name. */ if (MODULE_SECTION_START(s1)) sscanf(s1->name, "_MODULE_SECTION_START [%s]", sn1); else if (MODULE_SECTION_END(s1)) sscanf(s1->name, "_MODULE_SECTION_END [%s]", sn1); if (MODULE_SECTION_START(s2)) sscanf(s2->name, "_MODULE_SECTION_START [%s]", sn2); else if (MODULE_SECTION_END(s2)) sscanf(s2->name, "_MODULE_SECTION_END [%s]", sn2); /* * Sort pseudo symbols in mind section. * The same values must be sorted like examples. * - exp1 * c9046000 MODULE START: sctp * c9046000 [.data]: section start * c9046000 (D) sctp_timer_events * * - exp2 * c9046c68 [.bss]: section end * c9046c68 MODULE END: sctp * * - exp3 * c90e9b44 [.text]: section end * c90e9b44 [.exit.text]: section start * c90e9b44 (T) cleanup_module * c90e9b44 (t) sctp_exit * c90e9c81 [.exit.text]: section end */ if (MODULE_SECTION_END(s1)) { if (!MODULE_PSEUDO_SYMBOL(s2) || MODULE_END(s2)) return -1; else if (MODULE_SECTION_START(s2) && !STREQ(sn1, sn2)) return -1; return 1; } if (MODULE_SECTION_END(s2)) { if (MODULE_END(s1) || !MODULE_PSEUDO_SYMBOL(s1)) return 1; else if (MODULE_SECTION_START(s1) && STREQ(sn1, sn2)) return 1; return -1; } if (MODULE_SECTION_START(s2)) { if (MODULE_START(s1)) return -1; return 1; } } return (s1->value < s2->value ? -1 : s1->value == s2->value ? 0 : 1); } static int compare_mods(const void *v1, const void *v2) { struct load_module *lm1, *lm2; lm1 = (struct load_module *)v1; lm2 = (struct load_module *)v2; return (lm1->mod_base < lm2->mod_base ? -1 : lm1->mod_base == lm2->mod_base ? 0 : 1); } /* * Check whether a value falls into a text-type (SEC_CODE) section. * If it's a module address, and symbols are not loaded, we're forced * to use our "mod_etext_guess" value. */ int is_kernel_text(ulong value) { int i, s; asection **sec, *section; struct load_module *lm; ulong start, end; struct syment *sp; start = 0; if (pc->flags & SYSMAP) { if ((sp = value_search(value, NULL)) && ((sp->type == 'T') || (sp->type == 't'))) return TRUE; for (sp = st->symtable; sp < st->symend; sp++) { if (!((sp->type == 'T') || (sp->type == 't'))) continue; if ((value >= sp->value) && (value < kt->etext)) return TRUE; break; } } else { sec = (asection **)st->sections; for (i = 0; i < st->bfd->section_count; i++, sec++) { section = *sec; if (section->flags & SEC_CODE) { start = (ulong)bfd_get_section_vma(st->bfd, section); end = start + (ulong)bfd_section_size(st->bfd, section); if ((value >= start) && (value < end)) return TRUE; } } } if ((sp = value_search(value, NULL)) && ((sp->type == 'T') || (sp->type == 't'))) return TRUE; if (NO_MODULES()) return FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!IN_MODULE(value, lm) && !IN_MODULE_INIT(value, lm)) continue; if (lm->mod_flags & MOD_LOAD_SYMS) { for (s = (lm->mod_sections-1); s >= 0; s--) { if (!(lm->mod_section_data[s].flags & SEC_CODE)) continue; start = lm->mod_base + lm->mod_section_data[s].offset; end = start + lm->mod_section_data[s].size; if ((value >= start) && (value < end)) return TRUE; } } else { switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V1: start = lm->mod_base + lm->mod_size_of_struct; break; case KMOD_V2: if (IN_MODULE(value, lm)) start = lm->mod_base; else start = lm->mod_init_module_ptr; break; } end = lm->mod_etext_guess; if (IN_MODULE_INIT(value, lm) && end < lm->mod_init_module_ptr + lm->mod_init_size) end = lm->mod_init_module_ptr + lm->mod_init_size; if ((value >= start) && (value < end)) return TRUE; } } return FALSE; } /* * Detemine whether an address is offset into a text function, i.e., not * the starting address of the function. */ int is_kernel_text_offset(ulong value) { struct syment *sp; ulong offset; if (!is_kernel_text(value)) return FALSE; if (!(sp = value_search(value, &offset))) return FALSE; return(offset ? TRUE : FALSE); } /* * Check whether an address is most likely kernel data. * * TBD: This should be refined to recognize module text/data. */ int is_kernel_data(ulong value) { return(IS_KVADDR(value) && !is_kernel_text(value) && !IS_MODULE_VADDR(value)); } /* * Check whether the closest symbol to a value is rodata. */ int is_rodata(ulong value, struct syment **spp) { struct syment *sp; if (!(sp = value_search(value, NULL))) return FALSE; if ((sp->type == 'r') || (sp->type == 'R')) { if (spp) *spp = sp; return TRUE; } return FALSE; } /* * "help -s" output */ void dump_symbol_table(void) { int i, s, cnt, tot; struct load_module *lm; struct syment *sp; int others; asection **sec; fprintf(fp, " flags: %lx%s(", st->flags, count_bits_long(st->flags) > 3 ? "\n " : " "); others = 0; if (st->flags & KERNEL_SYMS) fprintf(fp, "%sKERNEL_SYMS", others++ ? "|" : ""); if (st->flags & MODULE_SYMS) fprintf(fp, "%sMODULE_SYMS", others++ ? "|" : ""); if (st->flags & LOAD_MODULE_SYMS) fprintf(fp, "%sLOAD_MODULE_SYMS", others++ ? "|" : ""); if (st->flags & INSMOD_BUILTIN) fprintf(fp, "%sINSMOD_BUILTIN", others++ ? "|" : ""); if (st->flags & GDB_SYMS_PATCHED) fprintf(fp, "%sGDB_SYMS_PATCHED", others++ ? "|" : ""); if (st->flags & NO_SEC_LOAD) fprintf(fp, "%sNO_SEC_LOAD", others++ ? "|" : ""); if (st->flags & NO_SEC_CONTENTS) fprintf(fp, "%sNO_SEC_CONTENTS", others++ ? "|" : ""); if (st->flags & FORCE_DEBUGINFO) fprintf(fp, "%sFORCE_DEBUGINFO", others++ ? "|" : ""); if (st->flags & CRC_MATCHES) fprintf(fp, "%sCRC_MATCHES", others++ ? "|" : ""); if (st->flags & ADD_SYMBOL_FILE) fprintf(fp, "%sADD_SYMBOL_FILE", others++ ? "|" : ""); if (st->flags & USE_OLD_ADD_SYM) fprintf(fp, "%sUSE_OLD_ADD_SYM", others++ ? "|" : ""); if (st->flags & PERCPU_SYMS) fprintf(fp, "%sPERCPU_SYMS", others++ ? "|" : ""); if (st->flags & MODSECT_V1) fprintf(fp, "%sMODSECT_V1", others++ ? "|" : ""); if (st->flags & MODSECT_V2) fprintf(fp, "%sMODSECT_V2", others++ ? "|" : ""); if (st->flags & MODSECT_V3) fprintf(fp, "%sMODSECT_V3", others++ ? "|" : ""); if (st->flags & MODSECT_UNKNOWN) fprintf(fp, "%sMODSECT_UNKNOWN", others++ ? "|" : ""); if (st->flags & NO_STRIP) fprintf(fp, "%sNO_STRIP", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " bfd: %lx\n", (ulong)st->bfd); fprintf(fp, " symtable: %lx\n", (ulong)st->symtable); fprintf(fp, " symend: %lx\n", (ulong)st->symend); fprintf(fp, " symcnt: %ld\n", st->symcnt); fprintf(fp, " syment_size: %ld\n", st->syment_size); fprintf(fp, " first_ksymbol: "); if (st->first_ksymbol) { fprintf(fp, "%lx (%s)\n", st->first_ksymbol, st->flags & KERNEL_SYMS ? value_symbol(st->first_ksymbol) : ""); } else fprintf(fp, "(unused)\n"); if (st->__per_cpu_start || st->__per_cpu_end) { fprintf(fp, " __per_cpu_start: %lx\n", st->__per_cpu_start); fprintf(fp, " __per_cpu_end: %lx\n", st->__per_cpu_end); } else { fprintf(fp, " __per_cpu_start: (unused)\n"); fprintf(fp, " __per_cpu_end: (unused)\n"); } fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH, (ulong)&st->symval_hash[0]); if (CRASHDEBUG(1)) { fprintf(fp, " "); for (i = 0; i < SYMVAL_HASH; i++) { fprintf(fp, " [%3d]: ", i); sp = st->symval_hash[i].val_hash_head; if (!sp) { fprintf(fp, " 0 "); } else { cnt = 1; while ((sp = sp->val_hash_next)) cnt++; fprintf(fp, "%3d ", cnt); } if (i && (((i+1)%6)== 0)) fprintf(fp, "\n "); } } fprintf(fp, "%s val_hash_searches: %.0f\n", CRASHDEBUG(1) ? "\n" : "", st->val_hash_searches); fprintf(fp, " val_hash_iterations: %.0f (avg: %.1f)\n", st->val_hash_iterations, st->val_hash_iterations/st->val_hash_searches); fprintf(fp, " symname_hash[%d]: %lx\n", SYMNAME_HASH, (ulong)&st->symname_hash[0]); if (CRASHDEBUG(1)) { fprintf(fp, " "); for (i = tot = 0; i < SYMNAME_HASH; i++) { fprintf(fp, "[%3d]: ", i); if ((sp = st->symname_hash[i]) == NULL) fprintf(fp, "%3d ", 0); else { cnt = 1; while (sp->name_hash_next) { cnt++; sp = sp->name_hash_next; } fprintf(fp, "%3d ", cnt); tot += cnt; } if (i && (((i+1) % 6) == 0)) fprintf(fp, "\n "); } if (SYMNAME_HASH % 6) fprintf(fp, "\n"); } fprintf(fp, " symbol_namespace: "); fprintf(fp, "address: %lx ", (ulong)st->kernel_namespace.address); fprintf(fp, "index: %ld ", st->kernel_namespace.index); fprintf(fp, "size: %ld ", (ulong)st->kernel_namespace.size); fprintf(fp, "cnt: %ld\n", st->kernel_namespace.cnt); fprintf(fp, " ext_module_symtable: %lx\n", (ulong)st->ext_module_symtable); fprintf(fp, " ext_module_symend: %lx\n", (ulong)st->ext_module_symend); fprintf(fp, " ext_module_symcnt: %ld\n", (ulong)st->ext_module_symcnt); fprintf(fp, "ext_module_namespace: "); fprintf(fp, "address: %lx ", (ulong)st->ext_module_namespace.address); fprintf(fp, "index: %ld ", st->ext_module_namespace.index); fprintf(fp, "size: %ld ", (ulong)st->ext_module_namespace.size); fprintf(fp, "cnt: %ld\n", st->ext_module_namespace.cnt); fprintf(fp, " mods_installed: %d\n", st->mods_installed); fprintf(fp, " current: %lx\n", (ulong)st->current); fprintf(fp, " load_modules: %lx\n", (ulong)st->load_modules); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; others = 0; fprintf(fp, "\n mod_base: %lx\n", lm->mod_base); fprintf(fp, " module_struct: %lx\n", lm->module_struct); fprintf(fp, " mod_name: %s\n", lm->mod_name); fprintf(fp, " mod_size: %ld\n", lm->mod_size); fprintf(fp, " mod_namelist: %s\n", lm->mod_namelist); fprintf(fp, " mod_flags: %lx (", lm->mod_flags); if (lm->mod_flags & MOD_EXT_SYMS) fprintf(fp, "%sMOD_EXT_SYMS", others++ ? "|" : ""); if (lm->mod_flags & MOD_LOAD_SYMS) fprintf(fp, "%sMOD_LOAD_SYMS", others++ ? "|" : ""); if (lm->mod_flags & MOD_REMOTE) fprintf(fp, "%sMOD_REMOTE", others++ ? "|" : ""); if (lm->mod_flags & MOD_KALLSYMS) fprintf(fp, "%sMOD_KALLSYMS", others++ ? "|" : ""); if (lm->mod_flags & MOD_INITRD) fprintf(fp, "%sMOD_INITRD", others++ ? "|" : ""); if (lm->mod_flags & MOD_NOPATCH) fprintf(fp, "%sMOD_NOPATCH", others++ ? "|" : ""); if (lm->mod_flags & MOD_INIT) fprintf(fp, "%sMOD_INIT", others++ ? "|" : ""); if (lm->mod_flags & MOD_DO_READNOW) fprintf(fp, "%sMOD_DO_READNOW", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " mod_symtable: %lx\n", (ulong)lm->mod_symtable); fprintf(fp, " mod_symend: %lx\n", (ulong)lm->mod_symend); fprintf(fp, " mod_init_symtable: %lx\n", (ulong)lm->mod_init_symtable); fprintf(fp, " mod_init_symend: %lx\n", (ulong)lm->mod_init_symend); fprintf(fp, " mod_ext_symcnt: %ld\n", lm->mod_ext_symcnt); fprintf(fp, " mod_ext_symtable: %lx\n", (ulong)lm->mod_ext_symtable); fprintf(fp, " mod_ext_symend: %lx\n", (ulong)lm->mod_ext_symend); fprintf(fp, " mod_load_symcnt: %ld\n", lm->mod_load_symcnt); fprintf(fp, " mod_load_symtable: %lx\n", (ulong)lm->mod_load_symtable); fprintf(fp, " mod_load_symend: %lx\n", (ulong)lm->mod_load_symend); fprintf(fp, " mod_load_namespace: "); fprintf(fp, "address: %lx ", (ulong)lm->mod_load_namespace.address); fprintf(fp, "index: %ld ", lm->mod_load_namespace.index); fprintf(fp, "size: %ld ", (ulong)lm->mod_load_namespace.size); fprintf(fp, "cnt: %ld\n", lm->mod_load_namespace.cnt); fprintf(fp, " mod_symalloc: %ld\n", lm->mod_symalloc); fprintf(fp, " mod_size_of_struct: %ld (%lx)\n", lm->mod_size_of_struct, lm->mod_size_of_struct); fprintf(fp, " mod_text_start: %lx (%lx)\n", lm->mod_text_start, lm->mod_text_start ? lm->mod_text_start - lm->mod_base : 0); fprintf(fp, " mod_etext_guess: %lx (%lx)\n", lm->mod_etext_guess, lm->mod_etext_guess ? lm->mod_etext_guess - lm->mod_base : 0); fprintf(fp, " mod_rodata_start: %lx (%lx)\n", lm->mod_rodata_start, lm->mod_rodata_start ? lm->mod_rodata_start - lm->mod_base : 0); fprintf(fp, " mod_data_start: %lx (%lx)\n", lm->mod_data_start, lm->mod_data_start ? lm->mod_data_start - lm->mod_base : 0); fprintf(fp, " mod_bss_start: %lx (%lx)\n", lm->mod_bss_start, lm->mod_bss_start ? lm->mod_bss_start - lm->mod_base : 0); fprintf(fp, " mod_init_size: %ld\n", lm->mod_init_size); fprintf(fp, " mod_init_text_size: %ld\n", lm->mod_init_text_size); fprintf(fp, " mod_init_module_ptr: %lx\n", lm->mod_init_module_ptr); if (lm->mod_percpu_size) { fprintf(fp, " mod_percpu_size: %lx\n", lm->mod_percpu_size); fprintf(fp, " mod_percpu: %lx - %lx\n", lm->mod_percpu, lm->mod_percpu + lm->mod_percpu_size); } else { if (lm->mod_percpu) { fprintf(fp, " mod_percpu_size: (not loaded)\n"); fprintf(fp, " mod_percpu: %lx - (unknown)\n", lm->mod_percpu); } else { fprintf(fp, " mod_percpu_size: (not used)\n"); fprintf(fp, " mod_percpu: (not used)\n"); } } fprintf(fp, " mod_sections: %d\n", lm->mod_sections); fprintf(fp, " mod_section_data: %lx %s\n", (ulong)lm->mod_section_data, lm->mod_section_data ? "" : "(not allocated)"); for (s = 0; s < lm->mod_sections; s++) { fprintf(fp, " %12s prio: %x flags: %05x offset: %-8lx size: %lx\n", lm->mod_section_data[s].name, lm->mod_section_data[s].priority, lm->mod_section_data[s].flags, lm->mod_section_data[s].offset, lm->mod_section_data[s].size); } if (CRASHDEBUG(1)) { for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { fprintf(fp, " %lx %s\n", sp->value, sp->name); } } } fprintf(fp, "\n"); fprintf(fp, " dwarf_eh_frame_file_offset: %llx\n", (unsigned long long)st->dwarf_eh_frame_file_offset); fprintf(fp, " dwarf_eh_frame_size: %ld\n", st->dwarf_eh_frame_size); fprintf(fp, "dwarf_debug_frame_file_offset: %llx\n", (unsigned long long)st->dwarf_debug_frame_file_offset); fprintf(fp, " dwarf_debug_frame_size: %ld\n", st->dwarf_debug_frame_size); fprintf(fp, "\n"); sec = (asection **)st->sections; fprintf(fp, " sections: %s\n", sec ? "" : "(not in use)"); for (i = 0; sec && (i < st->bfd->section_count); i++, sec++) { asection *section; section = *sec; fprintf(fp, "%25s vma: %.*lx size: %ld\n", section->name, VADDR_PRLEN, (ulong)bfd_get_section_vma(st->bfd, section), (ulong)bfd_section_size(st->bfd, section)); } } /* * Determine whether a file is in ELF format by checking the magic number * in the first EI_NIDENT characters of the file; if those match, check * whether the file is a known BFD format. */ int is_elf_file(char *s) { int fd; char magic[EI_NIDENT]; if ((fd = open(s, O_RDONLY)) < 0) { error(INFO, "%s: %s\n", s, strerror(errno)); return FALSE; } if (read(fd, magic, EI_NIDENT) != EI_NIDENT) { /* error(INFO, "%s: %s\n", s, strerror(errno)); */ close(fd); return FALSE; } close(fd); magic[EI_CLASS] = NULLCHAR; if (!STREQ(magic, ELFMAG)) return FALSE; return(is_bfd_format(s)); } /* * Verify a vmlinux file, issuing a warning for processor and endianness * mismatches. */ int is_kernel(char *file) { int fd, swap; char eheader[BUFSIZE]; Elf32_Ehdr *elf32; Elf64_Ehdr *elf64; if ((fd = open(file, O_RDONLY)) < 0) { error(INFO, "%s: %s\n", file, strerror(errno)); return FALSE; } if (read(fd, eheader, BUFSIZE) != BUFSIZE) { /* error(INFO, "%s: %s\n", file, strerror(errno)); */ close(fd); return FALSE; } close(fd); if (!STRNEQ(eheader, ELFMAG) || eheader[EI_VERSION] != EV_CURRENT) return FALSE; elf32 = (Elf32_Ehdr *)&eheader[0]; elf64 = (Elf64_Ehdr *)&eheader[0]; swap = (((eheader[EI_DATA] == ELFDATA2LSB) && (__BYTE_ORDER == __BIG_ENDIAN)) || ((eheader[EI_DATA] == ELFDATA2MSB) && (__BYTE_ORDER == __LITTLE_ENDIAN))); if ((elf32->e_ident[EI_CLASS] == ELFCLASS32) && (swap16(elf32->e_type, swap) == ET_EXEC) && (swap32(elf32->e_version, swap) == EV_CURRENT)) { switch (swap16(elf32->e_machine, swap)) { case EM_386: if (machine_type_mismatch(file, "X86", NULL, 0)) { if (machine_type("X86_64")) { /* * Since is_bfd_format() returns TRUE * in this case, just bail out here. */ return FALSE; } goto bailout; } break; case EM_S390: if (machine_type_mismatch(file, "S390", NULL, 0)) goto bailout; break; case EM_ARM: if (machine_type_mismatch(file, "ARM", NULL, 0)) goto bailout; break; case EM_PPC: if (machine_type_mismatch(file, "PPC", NULL, 0)) goto bailout; break; default: if (machine_type_mismatch(file, "(unknown)", NULL, 0)) goto bailout; } if (endian_mismatch(file, elf32->e_ident[EI_DATA], 0)) goto bailout; } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && ((swap16(elf64->e_type, swap) == ET_EXEC) || (swap16(elf64->e_type, swap) == ET_DYN)) && (swap32(elf64->e_version, swap) == EV_CURRENT)) { switch (swap16(elf64->e_machine, swap)) { case EM_IA_64: if (machine_type_mismatch(file, "IA64", NULL, 0)) goto bailout; break; case EM_PPC64: if (machine_type_mismatch(file, "PPC64", NULL, 0)) goto bailout; break; case EM_X86_64: if (machine_type_mismatch(file, "X86_64", NULL, 0)) goto bailout; break; case EM_386: if (machine_type_mismatch(file, "X86", NULL, 0)) goto bailout; break; case EM_S390: if (machine_type_mismatch(file, "S390X", NULL, 0)) goto bailout; break; case EM_AARCH64: if (machine_type_mismatch(file, "ARM64", NULL, 0)) goto bailout; break; default: if (machine_type_mismatch(file, "(unknown)", NULL, 0)) goto bailout; } if (endian_mismatch(file, elf64->e_ident[EI_DATA], 0)) goto bailout; } bailout: return(is_bfd_format(file)); } int is_compressed_kernel(char *file, char **tmp) { int len, type, fd; char *tmpdir, *tempname; unsigned char header[BUFSIZE]; char command[BUFSIZE]; char message[BUFSIZE]; #define GZIP (1) #define BZIP2 (2) #define FNAME (1 << 3) if ((fd = open(file, O_RDONLY)) < 0) return FALSE; if (read(fd, header, BUFSIZE) != BUFSIZE) { close(fd); return FALSE; } close(fd); type = 0; if ((header[0] == 0x1f) && (header[1] == 0x8b) && (header[2] == 8)) { if (!(header[3] & FNAME)) { if (!(st->flags & FORCE_DEBUGINFO)) { error(INFO, "%s: " "original filename unknown\n", file); error(CONT, "Use \"-f %s\" on command line to prevent this message.\n\n", file); } } else if (!STRNEQ((char *)&header[10], "vmlinux") && !(st->flags & FORCE_DEBUGINFO)) { error(INFO, "%s: compressed file name does not " "start with \"vmlinux\"\n", &header[10]); error(CONT, "Use \"-f %s\" on command line to override.\n\n", file); return FALSE; } type = GZIP; } if ((header[0] == 'B') && (header[1] == 'Z') && (header[2] == 'h')) { if (!STRNEQ(basename(file), "vmlinux") && !(st->flags & FORCE_DEBUGINFO)) { error(INFO, "%s: compressed file name does not start " "with \"vmlinux\"\n", file); error(CONT, "Use \"-f %s\" on command line to override.\n\n", file); return FALSE; } type = BZIP2; } if (!type) return FALSE; if (!(tmpdir = getenv("TMPDIR"))) tmpdir = "/var/tmp"; len = strlen(tmpdir) + strlen(basename(file)) + strlen("_XXXXXX") + 2; if (!(tempname = (char *)malloc(len))) return FALSE; sprintf(tempname, "%s/%s_XXXXXX", tmpdir, basename(file)); fd = mkstemp(tempname); if (fd < 0) { perror("mkstemp"); free(tempname); return FALSE; } pc->cleanup = tempname; sprintf(message, "uncompressing %s", file); please_wait(message); switch (type) { case GZIP: sprintf(command, "%s -c %s > %s", file_exists("/bin/gunzip", NULL) ? "/bin/gunzip" : "/usr/bin/gunzip", file, tempname); break; case BZIP2: sprintf(command, "%s -c %s > %s", file_exists("/bin/bunzip2", NULL) ? "/bin/bunzip2" : "/usr/bin/bunzip2", file, tempname); break; } if (system(command) < 0) { please_wait_done(); error(INFO, "%s of %s failed\n", type == GZIP ? "gunzip" : "bunzip2", file); free(tempname); return FALSE; } please_wait_done(); if (is_bfd_format(tempname)) { *tmp = tempname; return TRUE; } unlink(tempname); close(fd); free(tempname); pc->cleanup = NULL; return FALSE; } int is_shared_object(char *file) { int fd, swap; char eheader[BUFSIZE]; Elf32_Ehdr *elf32; Elf64_Ehdr *elf64; if (is_directory(file)) return FALSE; if ((fd = open(file, O_RDONLY)) < 0) return FALSE; if (read(fd, eheader, BUFSIZE) != BUFSIZE) { close(fd); return FALSE; } close(fd); if (!STRNEQ(eheader, ELFMAG) || eheader[EI_VERSION] != EV_CURRENT) return FALSE; elf32 = (Elf32_Ehdr *)&eheader[0]; elf64 = (Elf64_Ehdr *)&eheader[0]; swap = (((eheader[EI_DATA] == ELFDATA2LSB) && (__BYTE_ORDER == __BIG_ENDIAN)) || ((eheader[EI_DATA] == ELFDATA2MSB) && (__BYTE_ORDER == __LITTLE_ENDIAN))); if ((elf32->e_ident[EI_CLASS] == ELFCLASS32) && (swap16(elf32->e_type, swap) == ET_DYN)) { switch (swap16(elf32->e_machine, swap)) { case EM_386: if (machine_type("X86") || machine_type("ARM")) return TRUE; break; case EM_S390: if (machine_type("S390")) return TRUE; break; case EM_ARM: if (machine_type("ARM")) return TRUE; break; case EM_PPC: if (machine_type("PPC")) return TRUE; break; } if (CRASHDEBUG(1)) error(INFO, "%s: machine type mismatch: %d\n", file, swap16(elf32->e_machine, swap)); return FALSE; } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) && (swap16(elf64->e_type, swap) == ET_DYN)) { switch (swap16(elf64->e_machine, swap)) { case EM_IA_64: if (machine_type("IA64")) return TRUE; break; case EM_PPC64: if (machine_type("PPC64")) return TRUE; break; case EM_X86_64: if (machine_type("X86_64")) return TRUE; break; case EM_S390: if (machine_type("S390X")) return TRUE; break; case EM_AARCH64: if (machine_type("ARM64")) return TRUE; break; } if (CRASHDEBUG(1)) error(INFO, "%s: machine type mismatch: %d\n", file, swap16(elf32->e_machine, swap)); } return FALSE; } /* * Given a choice between two namelists, pick the one for gdb to use. * For now, just check get their stats and check their sizes; the larger * one presumably has debug data. */ int select_namelist(char *new) { struct stat stat1, stat2; if (pc->server_namelist) { pc->namelist_debug = new; return TRUE; } if (!file_exists(pc->namelist, &stat1) || !file_exists(new, &stat2)) { return FALSE; } if (stat1.st_size > stat2.st_size) { pc->namelist_debug = pc->namelist; pc->namelist = new; } else if (stat2.st_size > stat1.st_size) pc->namelist_debug = new; else { error(INFO, "cannot distinguish %s and %s\n", pc->namelist, new); return FALSE; } return TRUE; } /* * Make a sweep of a non-dump, non-ELF file to guess whether it's a * legitimate System.map file. */ int is_system_map(char *s) { int i, lines, retval; char *mapitems[MAXARGS]; char buf[16384]; FILE *map; /* * First simulate what "file" does by verifying that the first 16K * bytes are ascii data. */ if ((map = fopen(s, "r")) == NULL) { error(INFO, "cannot open %s\n", s); return FALSE; } retval = FALSE; if (fread(buf, sizeof(char), 16384, map) != (16384*sizeof(char))) { if (CRASHDEBUG(1)) error(INFO, "%s: cannot read 16K\n", s); goto not_system_map; } for (i = 0; i < 16384; i++) { if (!ascii(buf[i])) goto not_system_map; } rewind(map); for (lines = 0; lines < 100; lines++) { if (!fgets(buf, BUFSIZE, map)) goto not_system_map; if (parse_line(buf, mapitems) != 3) goto not_system_map; if ((strlen(mapitems[0]) > MAX_HEXADDR_STRLEN) || !hexadecimal(mapitems[0], 0) || (strlen(mapitems[1]) > 1)) goto not_system_map; } if ((pc->flags & SYSMAP) && !same_file("/boot/System.map", s)) error(INFO, "overriding /boot/System.map with %s\n", s); retval = TRUE; not_system_map: fclose(map); return retval; } /* * Check whether a file is a known BFD format. */ static int is_bfd_format(char *filename) { #ifdef GDB_5_3 struct _bfd *bfd; #else struct bfd *bfd; #endif char **matching; if ((bfd = bfd_openr(filename, NULL)) == NULL) return FALSE; if (!bfd_check_format_matches(bfd, bfd_object, &matching)) { bfd_close(bfd); return FALSE; } bfd_close(bfd); return TRUE; } static int is_binary_stripped(char *filename) { #ifdef GDB_5_3 struct _bfd *bfd; #else struct bfd *bfd; #endif int number_of_symbols; if ((bfd = bfd_openr(filename, NULL)) == NULL) { error(INFO, "cannot open ELF file: %s\n", filename); return FALSE; } if (!bfd_check_format(bfd, bfd_object)) { error(INFO, "invalid ELF file: %s\n", filename); bfd_close(bfd); return FALSE; } number_of_symbols = bfd_canonicalize_symtab(bfd, NULL); bfd_close(bfd); return (number_of_symbols == 0); } /* * This command may be used to: * * 1. Translate a symbol to its value. * 2. Translate a value to it symbol. * 3. List all stored symbols. * 4. Query for symbols containing a string. * 5. Show the next and previous symbols. */ void cmd_sym(void) { int c; struct syment *sp, *spp, *spn; ulong value, show_flags; ulong offset; int next, prev, multiples, others; char *name; int errflag; char buf[BUFSIZE]; next = prev = others = 0; show_flags = SHOW_LINENUM | SHOW_RADIX(); while ((c = getopt(argcnt, args, "lLQ:q:npsMm:")) != EOF) { switch(c) { case 'n': next++; break; case 'p': prev++; break; case 'Q': fprintf(fp, "%d found ", symbol_query(optarg, NULL, &sp)); if (sp) fprintf(fp, "(%s)", sp->name); fprintf(fp, "\n"); others++; break; case 'q': if (!symbol_query(optarg, "", NULL)) fprintf(fp, "(none found)\n"); others++; break; case 'm': symbol_dump(MODULE_SYMS, optarg); others++; break; case 'M': symbol_dump(MODULE_SYMS, NULL); others++; break; case 'L': /* obsolete */ case 'l': symbol_dump(KERNEL_SYMS|MODULE_SYMS, NULL); others++; break; case 's': show_flags &= ~SHOW_LINENUM; show_flags |= SHOW_SECTION; break; default: argerrs++; break; } } if (argerrs) cmd_usage(pc->curcmd, SYNOPSIS); if (args[optind]) { do { name = NULL; multiples = 0; sp = NULL; show_flags &= ~SHOW_MODULE; if (clean_arg() && hexadecimal(args[optind], 0)) { errflag = 0; value = htol(args[optind], RETURN_ON_ERROR, &errflag); if (errflag || !in_ksymbol_range(value)) { error(INFO, "invalid address: %s\n", args[optind]); } else if ((sp = value_search(value, &offset))){ name = sp->name; if (module_symbol(sp->value, NULL, NULL, NULL, 0)) show_flags |= SHOW_MODULE; if (prev && (spp = prev_symbol(NULL, sp))) show_symbol(spp, 0, show_flags); show_symbol(sp, offset, show_flags); } else if (module_symbol(value, &sp, NULL, buf, *gdb_output_radix)) { name = buf; if (prev && sp && (spp = prev_symbol(NULL, sp))) show_symbol(spp, 0, show_flags); fprintf(fp, "%lx (?) %s\n", value, buf); } else fprintf(fp, "symbol not found: %s\n", args[optind]); } else { if ((sp = symbol_search(args[optind]))) { multiples = symbol_name_count(sp->name); do_multiples: if (module_symbol(sp->value, NULL, NULL, NULL, 0)) show_flags |= SHOW_MODULE; name = sp->name; if (prev && (spp = prev_symbol(NULL, sp))) show_symbol(spp, 0, show_flags); show_symbol(sp, 0, show_flags); } else { fprintf(fp, "symbol not found: %s\n", args[optind]); fprintf(fp, "possible alternatives:\n"); if (!symbol_query(args[optind], " ", NULL)) fprintf(fp, " (none found)\n"); } } if (name && next && (spn = next_symbol(NULL, sp))) show_symbol(spn, 0, show_flags); if (multiples > 1) { if ((sp = symbol_search_next(name, sp))) goto do_multiples; } optind++; } while(args[optind]); } else if (!others) cmd_usage(pc->curcmd, SYNOPSIS); } /* * Common symbol display for cmd_sym(). */ void show_symbol(struct syment *sp, ulong offset, ulong show_flags) { char buf[BUFSIZE]; char *p1; ulong radix; struct load_module *lm; lm = NULL; if (CRASHDEBUG(1)) show_flags |= SHOW_LINENUM; switch (show_flags & (SHOW_HEX_OFFS|SHOW_DEC_OFFS)) { case SHOW_DEC_OFFS: radix = 10; break; default: case SHOW_HEX_OFFS: radix = 16; break; } if (MODULE_START(sp)) { p1 = sp->name + strlen("_MODULE_START_"); fprintf(fp, "%lx (%c) (%s module)", sp->value, sp->type, p1); if (offset) fprintf(fp, (radix == 16) ? "+0x%lx" : "+%ld", offset); fprintf(fp, "\n"); return; } else if (show_flags & SHOW_MODULE) module_symbol(sp->value, NULL, &lm, NULL, 0); if (offset) fprintf(fp, (radix == 16) ? "%lx (%c) %s+0x%lx" : "%lx (%c) %s+%ld", sp->value+offset, sp->type, sp->name, offset); else fprintf(fp, "%lx (%c) %s", sp->value, sp->type, sp->name); if (lm) fprintf(fp, " [%s]", lm->mod_name); if (is_kernel_text(sp->value+offset) && (show_flags & SHOW_LINENUM)) fprintf(fp, " %s", get_line_number(sp->value+offset, buf, TRUE)); if (show_flags & SHOW_SECTION) fprintf(fp, " [%s]", get_section(sp->value+offset, buf)); fprintf(fp, "\n"); } /* * Use the gdb_interface to get a line number associated with a * text address -- but first check whether the address gets past * any machine-dependent line_number_hooks reference. */ char * get_line_number(ulong addr, char *buf, int reserved) { char *p; struct gnu_request request, *req; struct line_number_hook *lnh; struct syment *sp; char bldbuf[BUFSIZE], *name; struct load_module *lm; buf[0] = NULLCHAR; if (!is_kernel_text(addr) || GDB_PATCHED()) return(buf); if (module_symbol(addr, NULL, &lm, NULL, 0)) { if (!(lm->mod_flags & MOD_LOAD_SYMS)) return(buf); } if ((lnh = machdep->line_number_hooks)) { name = closest_symbol(addr); while (lnh->func) { if (STREQ(name, lnh->func)) { sprintf(buf, "%s/%s", get_build_directory(bldbuf) ? bldbuf : "..", *(lnh->file)); break; } lnh++; } } if (!strlen(buf)) { req = &request; BZERO(req, sizeof(struct gnu_request)); req->command = GNU_GET_LINE_NUMBER; req->addr = addr; req->buf = buf; if ((sp = value_search(addr, NULL))) req->name = sp->name; gdb_interface(req); } while ((p = strstr(buf, "//"))) shift_string_left(p+1, 1); return(buf); } static char * get_section(ulong vaddr, char *buf) { int i; asection **sec; asection *section; ulong start, end; struct load_module *lm; buf[0] = NULLCHAR; if (module_symbol(vaddr, NULL, &lm, NULL, *gdb_output_radix)) { if (lm->mod_flags & MOD_LOAD_SYMS) { for (i = (lm->mod_sections-1); i >= 0; i--) { start = lm->mod_base + lm->mod_section_data[i].offset; end = start + lm->mod_section_data[i].size; if ((vaddr >= start) && (vaddr < end)) { strcpy(buf, lm->mod_section_data[i].name); break; } } } else sprintf(buf, "in %s module", lm->mod_name); } else { sec = (asection **)st->sections; for (i = 0; i < st->bfd->section_count; i++, sec++) { section = *sec; start = (ulong)bfd_get_section_vma(st->bfd, section); end = start + (ulong)bfd_section_size(st->bfd, section); if ((vaddr >= start) && (vaddr < end)) { strcpy(buf, bfd_get_section_name(st->bfd, section)); break; } } } return buf; } /* * Get the kernel build directory. */ char * get_build_directory(char *buf) { char *p; if (symbol_exists("schedule")) get_line_number(symbol_value("schedule"), buf, FALSE); else if (symbol_exists("do_schedule")) get_line_number(symbol_value("do_schedule"), buf, FALSE); else return NULL; if ((p = strstr(buf, "/kernel/"))) *p = NULLCHAR; else return(NULL); return buf; } /* * Search for all symbols containing a string. */ int symbol_query(char *s, char *print_pad, struct syment **spp) { int i; struct syment *sp, *sp_end; struct load_module *lm; int cnt, search_init; cnt = 0; for (sp = st->symtable; sp < st->symend; sp++) { if (strstr(sp->name, s)) { if (print_pad) { if (strlen(print_pad)) fprintf(fp, "%s", print_pad); show_symbol(sp, 0, SHOW_RADIX()); } if (spp) *spp = sp; cnt++; } } search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (MODULE_START(sp)) continue; if (strstr(sp->name, s)) { if (print_pad) { if (strlen(print_pad)) fprintf(fp, "%s", print_pad); show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); } if (spp) *spp = sp; cnt++; } } } if (!search_init) return(cnt); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (MODULE_START(sp)) continue; if (strstr(sp->name, s)) { if (print_pad) { if (strlen(print_pad)) fprintf(fp, "%s", print_pad); show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); } if (spp) *spp = sp; cnt++; } } } return(cnt); } /* * Return the syment of a symbol. */ struct syment * symbol_search(char *s) { int i; struct syment *sp_hashed, *sp, *sp_end; struct load_module *lm; int pseudos, search_init; sp_hashed = symname_hash_search(s); for (sp = sp_hashed ? sp_hashed : st->symtable; sp < st->symend; sp++) { if (STREQ(s, sp->name)) return(sp); } pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp <= sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (STREQ(s, sp->name)) return(sp); } } if (!search_init) return((struct syment *)NULL); pseudos = (strstr(s, "_MODULE_INIT_START_") || strstr(s, "_MODULE_INIT_END_")); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (STREQ(s, sp->name)) return(sp); } } return((struct syment *)NULL); } /* * Count the number of instances of a symbol name. */ static int symbol_name_count(char *s) { int i; struct syment *sp, *sp_end; struct load_module *lm; int count, pseudos, search_init; count = 0; for (sp = st->symtable; sp < st->symend; sp++) { if (STREQ(s, sp->name)) { count = sp->cnt; break; } } pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (STREQ(s, sp->name)) count++; } } if (!search_init) return(count); pseudos = (strstr(s, "_MODULE_INIT_START_") || strstr(s, "_MODULE_INIT_END_")); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (STREQ(s, sp->name)) count++; } } return(count); } /* * Return the syment of the next symbol with the same name of the input symbol. */ struct syment * symbol_search_next(char *s, struct syment *spstart) { int i; struct syment *sp, *sp_end; struct load_module *lm; int found_start; int pseudos, search_init; found_start = FALSE; for (sp = st->symtable; sp < st->symend; sp++) { if (sp == spstart) { found_start = TRUE; continue; } else if (!found_start) continue; if (strcmp(s, sp->name) == 0) { return(sp); } } pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == spstart) { found_start = TRUE; continue; } else if (!found_start) continue; if (STREQ(s, sp->name)) return(sp); } } if (!search_init) return((struct syment *)NULL); pseudos = (strstr(s, "_MODULE_INIT_START_") || strstr(s, "_MODULE_INIT_END_")); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (!pseudos && MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == spstart) { found_start = TRUE; continue; } else if (!found_start) continue; if (STREQ(s, sp->name)) return(sp); } } return((struct syment *)NULL); } /* * Determine whether an address falls within the kernel's, or any module's, * address space. */ int in_ksymbol_range(ulong value) { if ((value >= st->symtable[0].value) && (value <= st->symtable[st->symcnt-1].value)) { if ((st->flags & PERCPU_SYMS) && (value < st->first_ksymbol)) return FALSE; else return TRUE; } if (module_symbol(value, NULL, NULL, NULL, *gdb_output_radix)) return TRUE; if (machdep->value_to_symbol(value, NULL)) return TRUE; return FALSE; } /* * Determine whether an address falls within any module's address space. * If syment or load_module pointers are passed, send them back. * If a pointer to a name buffer is passed, stuff it with the particulars. */ int module_symbol(ulong value, struct syment **spp, struct load_module **lmp, char *name, ulong radix) { int i; struct load_module *lm; struct syment *sp; char buf[BUFSIZE]; ulong offs, offset; ulong base, end; if (NO_MODULES()) return FALSE; if (!radix) radix = *gdb_output_radix; if ((radix != 10) && (radix != 16)) radix = 16; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (IN_MODULE(value, lm)) { base = lm->mod_base; end = lm->mod_base + lm->mod_size; } else if (IN_MODULE_INIT(value, lm)) { base = lm->mod_init_module_ptr; end = lm->mod_init_module_ptr + lm->mod_init_size; } else if (IN_MODULE_PERCPU(value, lm)) { base = lm->mod_percpu; end = lm->mod_percpu + lm->mod_percpu_size; } else continue; if ((value >= base) && (value < end)) { if (lmp) *lmp = lm; if (name) { offs = value - base; if ((sp = value_search(value, &offset))) { if (offset) sprintf(buf, radix == 16 ? "%s+0x%lx" : "%s+%ld", sp->name, offset); else sprintf(buf, "%s", sp->name); strcpy(name, buf); if (spp) *spp = sp; return TRUE; } sprintf(name, "(%s module)", lm->mod_name); if (offs) { sprintf(buf, radix == 16 ? "+0x%lx" : "+%ld", offs); strcat(name, buf); } } return TRUE; } } return FALSE; } struct syment * value_search_module(ulong value, ulong *offset) { int i; struct syment *sp, *sp_end, *spnext, *splast; struct load_module *lm; int search_init_sections, search_init; search_init = FALSE; search_init_sections = 0; for (i = 0; i < st->mods_installed; i++) { if (st->load_modules[i].mod_flags & MOD_INIT) search_init_sections++; } retry: for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (search_init) { if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; } else continue; } else { sp = lm->mod_symtable; sp_end = lm->mod_symend; } if (sp->value > value) /* invalid -- between modules */ break; /* * splast will contain the last module symbol encountered. * Note: "__insmod_"-type symbols will be set in splast only * when they have unique values. */ splast = NULL; for ( ; sp <= sp_end; sp++) { if (value == sp->value) { if (MODULE_END(sp) || MODULE_INIT_END(sp)) break; if (MODULE_PSEUDO_SYMBOL(sp)) { spnext = sp + 1; if (MODULE_PSEUDO_SYMBOL(spnext)) continue; if (spnext->value == value) sp = spnext; } if (is_insmod_builtin(lm, sp)) { spnext = sp+1; if ((spnext < sp_end) && (value == spnext->value)) sp = spnext; } if (sp->name[0] == '.') { spnext = sp+1; if (spnext->value == value) sp = spnext; } if (offset) *offset = 0; return((struct syment *)sp); } if (sp->value > value) { sp = splast ? splast : sp - 1; if (offset) *offset = value - sp->value; return(sp); } if (!MODULE_PSEUDO_SYMBOL(sp)) { if (is_insmod_builtin(lm, sp)) { if (!splast || (sp->value > splast->value)) splast = sp; } else splast = sp; } } } if (search_init_sections) { if (!search_init) { search_init = TRUE; goto retry; } } return((struct syment *)NULL); } /* * Return the syment of the symbol closest to the value, along with * the offset from the symbol value if requested. */ struct syment * value_search(ulong value, ulong *offset) { struct syment *sp, *spnext; if (!in_ksymbol_range(value)) return((struct syment *)NULL); if ((sp = machdep->value_to_symbol(value, offset))) return sp; if (IS_VMALLOC_ADDR(value)) goto check_modules; if ((sp = symval_hash_search(value)) == NULL) sp = st->symtable; for ( ; sp < st->symend; sp++) { if (value == sp->value) { #if !defined(GDB_5_3) && !defined(GDB_6_0) && !defined(GDB_6_1) if (STRNEQ(sp->name, ".text.")) { spnext = sp+1; if (spnext->value == value) sp = spnext; } #endif if (offset) *offset = 0; return((struct syment *)sp); } if (sp->value > value) { if (offset) *offset = value - ((sp-1)->value); return((struct syment *)(sp-1)); } } check_modules: sp = value_search_module(value, offset); return sp; } ulong highest_bss_symbol(void) { struct syment *sp; ulong highest = 0; for (sp = st->symtable; sp < st->symend; sp++) { if ((sp->type == 'b') || (sp->type == 'B')) { if (sp->value > highest) highest = sp->value; } } return highest; } /* * Search for a value only within the base kernel's symbols, * also avoiding the machdep->value_to_symbol() call, which will * most likely be the prime consumer of this call. */ struct syment * value_search_base_kernel(ulong value, ulong *offset) { struct syment *sp; if (value < st->symtable[0].value) return((struct syment *)NULL); if ((sp = symval_hash_search(value)) == NULL) sp = st->symtable; for ( ; sp < st->symend; sp++) { if (value == sp->value) { if (offset) *offset = 0; return((struct syment *)sp); } if (sp->value > value) { if (offset) *offset = value - ((sp-1)->value); return((struct syment *)(sp-1)); } } /* * If we go off the end, just use the last symbol plus offset. */ sp = st->symend; if (offset) *offset = value - ((sp-1)->value); return((struct syment *)(sp-1)); } /* * Allow platforms to assign symbols to their own special values. */ struct syment * generic_machdep_value_to_symbol(ulong value, ulong *offset) { return NULL; } /* * For a given value, format a string containing the nearest symbol name * plus the offset if appropriate. Display the offset in the specified * radix (10 or 16) -- if it's 0, set it to the current pc->output_radix. */ char * value_to_symstr(ulong value, char *buf, ulong radix) { struct syment *sp; ulong offset; char *p1, locbuf[BUFSIZE]; struct load_module *lm; sp = NULL; offset = 0; buf[0] = NULLCHAR; if (!radix) radix = *gdb_output_radix; if ((radix != 10) && (radix != 16)) radix = 16; if ((sp = value_search(value, &offset))) { if (offset) sprintf(buf, radix == 16 ? "%s+0x%lx" : "%s+%ld", sp->name, offset); else sprintf(buf, "%s", sp->name); } if (module_symbol(value, NULL, NULL, locbuf, *gdb_output_radix)) { if (sp) { if (STRNEQ(locbuf, "_MODULE_START_")) shift_string_left(locbuf, strlen("_MODULE_START_")); if ((p1 = strstr(locbuf, "+"))) *p1 = NULLCHAR; if (offset) { if (is_module_name(locbuf, NULL, &lm) && (value < lm->mod_text_start)) sprintf(buf, radix == 16 ? "(%s module)+0x%lx" : "(%s module)+%ld", locbuf, offset); else sprintf(buf, radix == 16 ? "%s+0x%lx" : "%s+%ld", locbuf, offset); } else { if (is_module_name(locbuf, NULL, &lm) && (value < lm->mod_text_start)) sprintf(buf, "(%s)", locbuf); else sprintf(buf, "%s", locbuf); } } else sprintf(buf, "%s", locbuf); } return(buf); } /* * For a given value, return the closest (lower-in-value) symbol name. */ char * closest_symbol(ulong value) { struct syment *sp; if ((sp = value_search(value, NULL))) return(sp->name); else return(NULL); } /* * Same as above, but return the closest (lower-in-value) symbol value. */ ulong closest_symbol_value(ulong value) { struct syment *sp; if ((sp = value_search(value, NULL))) return(sp->value); else return(0); } /* * For a given symbol, return a pointer to the next (higher) symbol's syment. * Either a symbol name or syment pointer may be passed as an argument. */ struct syment * next_symbol(char *symbol, struct syment *sp_in) { int i; int found, search_init; struct syment *sp, *sp_end; struct load_module *lm; char buf[BUFSIZE], *p1; if (!symbol && !sp_in) error(FATAL, "next_symbol: two NULL args!\n"); if (sp_in) { found = FALSE; for (sp = st->symtable; sp < st->symend; sp++) { if (sp == sp_in) found = TRUE; else if (found) { if (sp->value > sp_in->value) return sp; } } search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == sp_in) found = TRUE; else if (found) { if ((sp->value == sp_in->value) && is_insmod_builtin(lm, sp)) continue; return sp; } } } for (i = 0; search_init && (i < st->mods_installed); i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == sp_in) found = TRUE; else if (found) return sp; } } return NULL; } /* * Deal with a few special cases... */ if (strstr(symbol, " module)")) { sprintf(buf, "_MODULE_START_"); strcat(buf, &symbol[1]); p1 = strstr(buf, " module)"); *p1 = NULLCHAR; symbol = buf; } if (STREQ(symbol, "_end")) { if (!st->mods_installed) return NULL; lm = &st->load_modules[0]; return lm->mod_symtable; } if ((sp = symbol_search(symbol))) { sp++; if (MODULE_END(sp)) { sp--; i = load_module_index(sp); if ((i+1) == st->mods_installed) return NULL; lm = &st->load_modules[i+1]; sp = lm->mod_symtable; } return sp; } return NULL; } /* * For a given symbol, return a pointer to the previous (lower) symbol's syment. * Either a symbol name or syment pointer may be passed as an argument. */ struct syment * prev_symbol(char *symbol, struct syment *sp_in) { int i, search_init; struct syment *sp, *sp_end, *sp_prev; char buf[BUFSIZE], *p1; struct load_module *lm; if (!symbol && !sp_in) error(FATAL, "prev_symbol: two NULL args!\n"); if (sp_in) { sp_prev = NULL; for (sp = st->symtable; sp < st->symend; sp++) { if (sp == sp_in) return sp_prev; sp_prev = sp; } search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_INIT) search_init = TRUE; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == sp_in) return sp_prev; if (is_insmod_builtin(lm, sp)) { if (sp->value > sp_prev->value) sp_prev = sp; } else sp_prev = sp; } } for (i = 0; search_init && (i < st->mods_installed); i++) { lm = &st->load_modules[i]; if (!lm->mod_init_symtable) continue; sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (MODULE_PSEUDO_SYMBOL(sp)) continue; if (sp == sp_in) return sp_prev; sp_prev = sp; } } return NULL; } if (strstr(symbol, " module)")) { sprintf(buf, "_MODULE_START_"); strcat(buf, &symbol[1]); p1 = strstr(buf, " module)"); *p1 = NULLCHAR; symbol = buf; } if ((sp = symbol_search(symbol))) { if (sp == st->symtable) return((struct syment *)NULL); if (module_symbol(sp->value, NULL, NULL, NULL, 0)) { if (MODULE_START(sp)) { i = load_module_index(sp); if (i == 0) sp = symbol_search("_end"); else { lm = &st->load_modules[i-1]; sp = lm->mod_symend; sp--; } } else sp--; } else sp--; return sp; } return NULL; } /* * Read the specified amount of data from the given symbol's value. */ void get_symbol_data(char *symbol, long size, void *local) { struct syment *sp; if ((sp = symbol_search(symbol))) readmem(sp->value, KVADDR, local, size, symbol, FAULT_ON_ERROR); else error(FATAL, "cannot resolve: \"%s\"\n", symbol); } /* * Same as above, but allow for failure. */ int try_get_symbol_data(char *symbol, long size, void *local) { struct syment *sp; if ((sp = symbol_search(symbol)) && readmem(sp->value, KVADDR, local, size, symbol, RETURN_ON_ERROR|QUIET)) return TRUE; return FALSE; } /* * Return the value of a given symbol. */ ulong symbol_value(char *symbol) { struct syment *sp; if (!(sp = symbol_search(symbol))) error(FATAL, "cannot resolve \"%s\"\n", symbol); return(sp->value); } /* * Return the value of a symbol from a specific module. */ ulong symbol_value_module(char *symbol, char *module) { int i; struct syment *sp, *sp_end; struct load_module *lm; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!STREQ(module, lm->mod_name)) continue; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) return(sp->value); } if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) return(sp->value); } } } return 0; } /* * Return the symbol name of a given value, with no allowance for offsets. * Returns NULL on failure to allow for testing of a value. */ char * value_symbol(ulong value) { struct syment *sp; ulong offset; if ((sp = value_search(value, &offset))) { if (offset) return NULL; else return sp->name; } return NULL; } /* * Determine whether a symbol exists. */ int symbol_exists(char *symbol) { int i; struct syment *sp, *sp_end; struct load_module *lm; if ((sp = symname_hash_search(symbol))) return TRUE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) return(TRUE); } if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) return(TRUE); } } } return(FALSE); } /* * Determine whether a per-cpu symbol exists. * The old-style per-cpu symbol names were pre-pended with * "per_cpu__", whereas the new-style ones (as of 2.6.34) * are not. This function allows the symbol argument to * use either the old- or new-sytle format, and find either * type. */ struct syment * per_cpu_symbol_search(char *symbol) { struct syment *sp; char old[BUFSIZE]; char *new; if (STRNEQ(symbol, "per_cpu__")) { if ((sp = symbol_search(symbol))) return sp; new = symbol + strlen("per_cpu__"); if ((sp = symbol_search(new))) { if ((sp->type == 'V') || (is_percpu_symbol(sp))) return sp; if ((sp->type == 'd') && (st->__per_cpu_start == st->__per_cpu_end)) return sp; } } else { if ((sp = symbol_search(symbol))) { if ((sp->type == 'V') || (is_percpu_symbol(sp))) return sp; } sprintf(old, "per_cpu__%s", symbol); if ((sp = symbol_search(old))) return sp; } if (CRASHDEBUG(1)) error(INFO, "per_cpu_symbol_search(%s): NULL\n", symbol); return NULL; } /* * Determine whether a static kernel symbol exists. */ int kernel_symbol_exists(char *symbol) { struct syment *sp; if ((sp = symname_hash_search(symbol))) return TRUE; else return FALSE; } /* * Similar to above, but return the syment of the kernel symbol. */ struct syment * kernel_symbol_search(char *symbol) { return symname_hash_search(symbol); } /* * Return the number of instances of a symbol name along with pointers to * their syment structures. */ int get_syment_array(char *symbol, struct syment **sp_array, int max) { int i, cnt; struct syment *sp, *sp_end; struct load_module *lm; cnt = 0; for (sp = st->symtable; sp < st->symend; sp++) { if ((*symbol == *(sp->name)) && STREQ(symbol, sp->name)) { if (!sp_array) return sp->cnt; if (max) { if (cnt == max) { error(INFO, "symbol count overflow (%s)\n", symbol); return cnt; } else sp_array[cnt] = sp; } if (sp->cnt == 1) return 1; cnt++; } } for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; sp = lm->mod_symtable; sp_end = lm->mod_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) { if (max && (cnt < max)) sp_array[cnt] = sp; cnt++; } } if (lm->mod_init_symtable) { sp = lm->mod_init_symtable; sp_end = lm->mod_init_symend; for ( ; sp < sp_end; sp++) { if (STREQ(symbol, sp->name)) { if (max && (cnt < max)) sp_array[cnt] = sp; cnt++; } } } } return cnt; } /* * Perform any datatype-related initializations here. */ void datatype_init(void) { BNEG(&offset_table, sizeof(offset_table)); BNEG(&size_table, sizeof(size_table)); BZERO(&array_table, sizeof(array_table)); } /* * This function is called through the following macros: * * #define STRUCT_SIZE(X) datatype_info((X), NULL, NULL) * #define UNION_SIZE(X) datatype_info((X), NULL, NULL) * #define DATATYPE_SIZE(X) datatype_info((X)->name, NULL, (X)) * #define MEMBER_OFFSET(X,Y) datatype_info((X), (Y), NULL) * #define STRUCT_EXISTS(X) (datatype_info((X), NULL, NULL) >= 0) * #define MEMBER_EXISTS(X,Y) (datatype_info((X), (Y), NULL) >= 0) * #define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) * #define MEMBER_TYPE(X,Y) datatype_info((X), (Y), MEMBER_TYPE_REQUEST) * #define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) * * to determine structure or union sizes, or member offsets. */ long datatype_info(char *name, char *member, struct datatype_member *dm) { struct gnu_request *req; long offset, size, member_size; int member_typecode; ulong type_found; char buf[BUFSIZE]; if (dm == ANON_MEMBER_OFFSET_REQUEST) return anon_member_offset(name, member); strcpy(buf, name); req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); req->command = GNU_GET_DATATYPE; req->flags |= GNU_RETURN_ON_ERROR; req->name = buf; req->member = member; req->fp = pc->nullfp; gdb_interface(req); if (req->flags & GNU_COMMAND_FAILED) { FREEBUF(req); return -1; } if (!req->typecode) { sprintf(buf, "struct %s", name); gdb_interface(req); } if (!req->typecode) { sprintf(buf, "union %s", name); gdb_interface(req); } member_typecode = TYPE_CODE_UNDEF; member_size = 0; type_found = 0; if (CRASHDEBUG(2)) { if (req->typecode) { console("name: %s ", req->name); if (member) console("member: %s ", req->member); console("typecode: %d%s ", req->typecode, req->is_typedef ? " (TYPEDEF)" : ""); console("length: %ld ", req->length); console("member_offset: %ld\n", req->member_offset); } else console("%s: unknown\n", name); } switch (req->typecode) { case TYPE_CODE_STRUCT: type_found = STRUCT_REQUEST; size = req->length; if (req->member_offset >= 0) { offset = req->member_offset/BITS_PER_BYTE; member_size = req->member_length; member_typecode = req->member_typecode; } else { offset = -1; member_size = 0; member_typecode = TYPE_CODE_UNDEF; } break; case TYPE_CODE_UNION: type_found = UNION_REQUEST; size = req->length; if (req->member_offset >= 0) { offset = req->member_offset/BITS_PER_BYTE; member_size = req->member_length; member_typecode = req->member_typecode; } else { offset = -1; member_size = 0; member_typecode = TYPE_CODE_UNDEF; } break; case TYPE_CODE_RANGE: case TYPE_CODE_INT: size = req->length; offset = 0; switch (size) { case SIZEOF_64BIT: type_found = INT64; break; case SIZEOF_32BIT: type_found = INT32; break; case SIZEOF_16BIT: type_found = INT16; break; case SIZEOF_8BIT: type_found = INT8; break; } break; case TYPE_CODE_PTR: size = req->length; offset = 0; type_found = POINTER; break; case TYPE_CODE_FUNC: size = req->length; offset = 0; type_found = FUNCTION; break; case TYPE_CODE_ARRAY: size = req->length; offset = 0; type_found = ARRAY; break; case TYPE_CODE_ENUM: size = req->length; offset = 0; type_found = ENUM; break; default: type_found = 0; size = -1; offset = -1; break; } FREEBUF(req); if (dm && (dm != MEMBER_SIZE_REQUEST) && (dm != MEMBER_TYPE_REQUEST) && (dm != STRUCT_SIZE_REQUEST)) { dm->type = type_found; dm->size = size; dm->member_size = member_size; dm->member_typecode = member_typecode; dm->member_offset = offset; if (req->is_typedef) { dm->flags |= TYPEDEF; } if (req->tagname) { dm->tagname = req->tagname; dm->value = req->value; } } if (!type_found) return -1; if (dm == MEMBER_SIZE_REQUEST) return member_size; else if (dm == MEMBER_TYPE_REQUEST) return member_typecode; else if (dm == STRUCT_SIZE_REQUEST) { if ((req->typecode == TYPE_CODE_STRUCT) || (req->typecode == TYPE_CODE_UNION) || req->is_typedef) return size; else return -1; } else if (member) { if ((req->typecode == TYPE_CODE_STRUCT) || (req->typecode == TYPE_CODE_UNION)) return offset; else return -1; } else return size; } /* * Determine the offset of a member in an anonymous union * in a structure or union. */ static long anon_member_offset(char *name, char *member) { char buf[BUFSIZE]; ulong value; int type; value = -1; type = STRUCT_REQUEST; sprintf(buf, "printf \"%%p\", &((struct %s *)0x0)->%s", name, member); open_tmpfile2(); retry: if (gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { rewind(pc->tmpfile2); if (fgets(buf, BUFSIZE, pc->tmpfile2)) { if (hexadecimal(buf, 0)) value = htol(buf, RETURN_ON_ERROR|QUIET, NULL); else if (STRNEQ(buf, "(nil)")) value = 0; } } if ((value == -1) && (type == STRUCT_REQUEST)) { type = UNION_REQUEST; sprintf(buf, "printf \"%%p\", &((union %s *)0x0)->%s", name, member); rewind(pc->tmpfile2); goto retry; } close_tmpfile2(); return value; } /* * Get the basic type info for a symbol. Let the caller pass in the * gnu_request structure to have access to the full response; in either * case, return the type code. The member field can be used for structures * with no type names, and if there, the member data will be filled in * as well. */ int get_symbol_type(char *name, char *member, struct gnu_request *caller_req) { struct gnu_request *req; int typecode; if (!caller_req) req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); else { req = caller_req; BZERO(req, sizeof(struct gnu_request)); } req->command = GNU_GET_SYMBOL_TYPE; req->name = name; req->member = member; req->flags = GNU_RETURN_ON_ERROR; req->fp = pc->nullfp; gdb_interface(req); if (req->flags & GNU_COMMAND_FAILED) typecode = TYPE_CODE_UNDEF; else if (member) { if (req->member_offset >= 0) typecode = req->member_typecode; else typecode = TYPE_CODE_UNDEF; } else typecode = req->typecode; if (!caller_req) FREEBUF(req); return(typecode); } int get_symbol_length(char *symbol) { struct gnu_request *req; int len; req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); if (get_symbol_type(symbol, NULL, req) == TYPE_CODE_UNDEF) error(FATAL, "cannot determine length of symbol: %s\n", symbol); len = (int)req->length; FREEBUF(req); return len; } /* * Initialize the caller's restore_radix, and if valid, * temporarily override the current output radix. */ void set_temporary_radix(unsigned int radix, unsigned int *restore_radix) { *restore_radix = *gdb_output_radix; if ((radix == 10) || (radix == 16)) { *gdb_output_radix = radix; \ *gdb_output_format = (*gdb_output_radix == 10) ? 0 : 'x'; } } /* * Restore the output radix to the current/default value saved * by the caller. */ void restore_current_radix(unsigned int restore_radix) { if ((restore_radix == 10) || (restore_radix == 16)) { *gdb_output_radix = restore_radix; *gdb_output_format = (*gdb_output_radix == 10) ? 0 : 'x'; } } /* * Externally available routine to dump a structure at an address. */ void dump_struct(char *s, ulong addr, unsigned radix) { unsigned restore_radix; long len; restore_radix = 0; if ((len = STRUCT_SIZE(s)) < 0) error(FATAL, "invalid structure name: %s\n", s); set_temporary_radix(radix, &restore_radix); print_struct(s, addr); restore_current_radix(restore_radix); } /* * Externally available routine to dump a structure member, given the * base structure address. The input string must be in struct.member format. */ void dump_struct_member(char *s, ulong addr, unsigned radix) { struct datatype_member datatype_member, *dm; unsigned restore_radix; char *buf, *p1; restore_radix = 0; buf = GETBUF(strlen(s)+1); strcpy(buf, s); p1 = strstr(buf, "."); *p1 = NULLCHAR; p1++; dm = &datatype_member; dm->name = buf; dm->member = p1; if (!STRUCT_EXISTS(dm->name)) { FREEBUF(buf); error(FATAL, "invalid structure name: %s\n", dm->name); } if (!MEMBER_EXISTS(dm->name, dm->member)) { FREEBUF(buf); error(FATAL, "invalid structure member name: %s\n", dm->member); } set_temporary_radix(radix, &restore_radix); open_tmpfile(); print_struct(dm->name, addr); parse_for_member(dm, PARSE_FOR_DATA); close_tmpfile(); restore_current_radix(restore_radix); FREEBUF(buf); } /* * Externally available routine to dump a union at an address. */ void dump_union(char *s, ulong addr, unsigned radix) { unsigned restore_radix; long len; restore_radix = 0; if ((len = UNION_SIZE(s)) < 0) error(FATAL, "invalid union name: %s\n", s); set_temporary_radix(radix, &restore_radix); print_union(s, addr); restore_current_radix(restore_radix); } /* * This command displays either a structure definition, or a formatted display * of the contents of a structure at a specified address. If no address is * specified, the structure size and the file in which the structure is defined * are also displayed. A structure member may be appended to the structure * name (in a "struct.member" format) in order to limit the scope of the data * displayed to that particular member. Structure data is shown in hexadecimal * format. The raw data in a structure may be dumped with the -r flag. */ void cmd_struct(void) { cmd_datatype_common(STRUCT_REQUEST); } /* * This command displays either a union definition, or a formatted display * of the contents of a union at a specified address. If no address is * specified, the union size and the file in which the union is defined * are also displayed. A union member may be appended to the union * name (in a "union.member" format) in order to limit the scope of the data * displayed to that particular member. Structure data is shown in hexadecimal * format. The raw data in a union may be dumped with the -r flag. */ void cmd_union(void) { cmd_datatype_common(UNION_REQUEST); } /* * After determining what type of data type follows the *, this routine * has the identical functionality as cmd_struct() or cmd_union(). */ void cmd_pointer(void) { cmd_datatype_common(0); } static void print_struct_with_dereference(ulong addr, struct datatype_member *dm, ulong flags) { int indent; char *p1; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char buf3[BUFSIZE]; struct datatype_member datatype_member, *dm1; dm1 = &datatype_member; open_tmpfile(); if (flags & UNION_REQUEST) print_union(dm->name, addr); else if (flags & STRUCT_REQUEST) print_struct(dm->name, addr); rewind(pc->tmpfile); while (fgets(buf1, BUFSIZE, pc->tmpfile)) { indent = count_leading_spaces(buf1); if ((indent != 2) || strstr(buf1, "{") || strstr(buf1, "}")) { print_verbatim(pc->saved_fp, buf1); continue; } sprintf(buf2, "%s.", dm->name); strcpy(buf3, &buf1[2]); p1 = strstr(buf3, " ="); *p1 = NULLCHAR; strcat(buf2, buf3); if ((arg_to_datatype(buf2, dm1, RETURN_ON_ERROR) == 2) && dereference_pointer(addr, dm1, flags)) continue; print_verbatim(pc->saved_fp, buf1); } close_tmpfile(); } static int dereference_pointer(ulong addr, struct datatype_member *dm, ulong flags) { char buf1[BUFSIZE]; char buf2[BUFSIZE]; char *typeptr, *member, *charptr, *voidptr, *p1, *sym; int found, ptrptr, funcptr, typedef_is_ptr, use_symbol; ulong target, value; found = ptrptr = funcptr = typedef_is_ptr = use_symbol = FALSE; member = GETBUF(strlen(dm->member)+4); typeptr = charptr = voidptr = NULL; open_tmpfile2(); whatis_datatype(dm->name, flags, pc->tmpfile2); rewind(pc->tmpfile2); while (fgets(buf1, BUFSIZE, pc->tmpfile2)) { sprintf(member, " *%s;", dm->member); if (strstr(buf1, member) && (buf1[4] != ' ')) { typeptr = &buf1[4]; found++; break; } sprintf(member, "**%s;", dm->member); if (strstr(buf1, member) && (buf1[4] != ' ')) { typeptr = &buf1[4]; found++; ptrptr = TRUE; break; } sprintf(member, "(*%s)(", dm->member); if (strstr(buf1, member) && (buf1[4] != ' ')) { typeptr = &buf1[4]; funcptr = TRUE; found++; break; } sprintf(member, " %s;", dm->member); if (strstr(buf1, member) && (buf1[4] != ' ')) { typeptr = &buf1[4]; typedef_is_ptr = TRUE; strcpy(buf2, typeptr); p1 = strstr(buf2, " "); *p1 = NULLCHAR; if (datatype_exists(buf2) == TYPE_CODE_PTR) { found++; break; } } } close_tmpfile2(); FREEBUF(member); if (!found) { console("%s.%s: not found!\n", dm->name, dm->member); return FALSE; } if (funcptr) { p1 = strstr(buf1, ";"); *p1 = NULLCHAR; } else if (ptrptr) { p1 = strstr(buf1, "**"); *(p1+2) = NULLCHAR; charptr = voidptr = NULL; } else if (typedef_is_ptr) { p1 = strstr(typeptr, " "); *p1 = NULLCHAR; } else { p1 = strstr(buf1, "*"); *(p1+1) = NULLCHAR; charptr = strstr(&buf1[4], "char *"); voidptr = strstr(&buf1[4], "void *"); } console("%s.%s typeptr: %s ", dm->name, dm->member, typeptr); if (charptr) console("[char *]"); else if (voidptr) console("[void *]"); else if (funcptr) console("[func *]"); else if (typedef_is_ptr) console("[typedef is ptr]"); console("\n"); if (!readmem(addr + dm->member_offset, KVADDR, &target, sizeof(void *), "target address", RETURN_ON_ERROR|QUIET)) { error(INFO, "cannot access %s.%s %lx\n", dm->name, dm->member, addr + dm->member_offset); return FALSE; } if ((sym = value_symbol(target))) { switch (get_symbol_type(sym, NULL, NULL)) { case TYPE_CODE_ARRAY: case TYPE_CODE_UNION: case TYPE_CODE_STRUCT: case TYPE_CODE_INT: case TYPE_CODE_PTR: use_symbol = TRUE; console("use_symbol: %s\n", sym); break; } } if (funcptr) { fprintf(pc->saved_fp, " %s = 0x%lx\n -> ", typeptr, target); if (sym) fprintf(pc->saved_fp, "<%s>\n", sym); else if (target) fprintf(pc->saved_fp, "(unknown)\n"); else fprintf(pc->saved_fp, "NULL\n"); return TRUE; } if (charptr) { fprintf(pc->saved_fp, " %s%s = 0x%lx\n -> ", typeptr, dm->member, target); if (sym) fprintf(pc->saved_fp, "<%s> ", sym); if (!target) fprintf(pc->saved_fp, "NULL\n"); else if (!accessible(target) || !read_string(target, buf1, BUFSIZE-1)) fprintf(pc->saved_fp, "(not accessible)\n"); else fprintf(pc->saved_fp, "\"%s\"\n", buf1); return TRUE; } if (voidptr && !use_symbol) { fprintf(pc->saved_fp, " %s%s = 0x%lx\n -> ", typeptr, dm->member, target); if (sym) fprintf(pc->saved_fp, "<%s>\n", sym); else if (!target) fprintf(pc->saved_fp, "NULL\n"); else if (voidptr) fprintf(pc->saved_fp, "(unknown target type)\n"); return TRUE; } if (!target || !accessible(target)) { fprintf(pc->saved_fp, " %s%s%s = 0x%lx\n -> ", typeptr, typedef_is_ptr ? " " : "", dm->member, target); if (!target) fprintf(pc->saved_fp, "NULL\n"); else fprintf(pc->saved_fp, "(not accessible)\n"); return TRUE; } if (ptrptr) { fprintf(pc->saved_fp, " %s%s = 0x%lx\n -> ", typeptr, dm->member, target); if (sym) fprintf(pc->saved_fp, "<%s> ", sym); if (!target || !readmem(target, KVADDR, &value, sizeof(void *), "target value", RETURN_ON_ERROR|QUIET)) fprintf(pc->saved_fp, "\n"); else fprintf(pc->saved_fp, "%lx\n", value); return TRUE; } if (use_symbol) sprintf(buf2, "p %s\n", sym); else sprintf(buf2, "p *((%s)(0x%lx))\n", typeptr, target); console("gdb command: %s", buf2); if (!typedef_is_ptr) { p1 = strstr(typeptr, "*"); *(p1-1) = NULLCHAR; } if (!datatype_exists(typeptr)) { fprintf(pc->saved_fp, " %s %s%s = 0x%lx\n -> (%s: no debuginfo data)\n", typeptr, typedef_is_ptr ? "" : "*", dm->member, target, typeptr); return TRUE; } open_tmpfile2(); if (!gdb_pass_through(buf2, pc->tmpfile2, GNU_RETURN_ON_ERROR)) { console("gdb request failed: %s\n", buf2); close_tmpfile2(); return FALSE; } fprintf(pc->saved_fp, " %s %s%s = 0x%lx\n -> ", typeptr, typedef_is_ptr ? "" : "*", dm->member, target); rewind(pc->tmpfile2); while (fgets(buf1, BUFSIZE, pc->tmpfile2)) { if (buf1[0] == '$') { if (sym) fprintf(pc->saved_fp, "<%s> ", sym); if (typedef_is_ptr || use_symbol) { if (strstr(buf1, "(") && strstr(buf1, ")")) { fprintf(pc->saved_fp, "\n"); break; } } p1 = strstr(buf1, "="); fprintf(pc->saved_fp, p1+2); } else fprintf(pc->saved_fp, " %s", buf1); } close_tmpfile2(); return TRUE; } static void cmd_datatype_common(ulong flags) { int i, c; ulong addr, aflag; struct syment *sp; int rawdata; long len; ulong list_head_offset; int count, pflag; int argc_members; int optind_save; unsigned int radix, restore_radix; struct datatype_member datatype_member, *dm; char *separator; char *structname, *members; char *memberlist[MAXARGS]; dm = &datatype_member; count = 0xdeadbeef; rawdata = 0; aflag = addr = 0; list_head_offset = 0; argc_members = 0; radix = restore_radix = 0; separator = members = NULL; pflag = 0; while ((c = getopt(argcnt, args, "pxdhfuc:rvol:")) != EOF) { switch (c) { case 'p': pflag++; break; case 'd': if (radix == 16) error(FATAL, "-d and -x are mutually exclusive\n"); radix = 10; break; case 'h': case 'x': if (radix == 10) error(FATAL, "-d and -x are mutually exclusive\n"); radix = 16; break; case 'c': count = atoi(optarg); break; case 'r': rawdata = 1; break; case 'v': flags |= STRUCT_VERBOSE; break; case 'o': flags |= SHOW_OFFSET; break; case 'l': if (IS_A_NUMBER(optarg)) list_head_offset = stol(optarg, FAULT_ON_ERROR, NULL); else if (arg_to_datatype(optarg, dm, RETURN_ON_ERROR) > 1) list_head_offset = dm->member_offset; else error(FATAL, "invalid -l option: %s\n", optarg); break; case 'f': if (!pc->dumpfile) error(FATAL, "-f option requires a dumpfile\n"); pc->curcmd_flags |= MEMTYPE_FILEADDR; break; case 'u': pc->curcmd_flags |= MEMTYPE_UVADDR; break; default: argerrs++; break; } } if (argerrs || !args[optind]) cmd_usage(pc->curcmd, SYNOPSIS); if ((count_chars(args[optind], ',')+1) > MAXARGS) error(FATAL, "too many members in comma-separated list!\n"); if ((count_chars(args[optind], '.') > 1) || (LASTCHAR(args[optind]) == ',') || (LASTCHAR(args[optind]) == '.')) error(FATAL, "invalid format: %s\n", args[optind]); optind_save = optind; /* * Take care of address and count (array). */ while (args[++optind]) { if (aflag && (count != 0xdeadbeef)) error(FATAL, "too many arguments!\n"); if (clean_arg() && IS_A_NUMBER(args[optind])) { if (aflag) count = stol(args[optind], FAULT_ON_ERROR, NULL); else { if (pc->curcmd_flags & MEMTYPE_FILEADDR) pc->curcmd_private = stoll(args[optind], FAULT_ON_ERROR, NULL); else if (pc->curcmd_flags & MEMTYPE_UVADDR) { addr = htol(args[optind], FAULT_ON_ERROR, NULL); } else if (!IS_KVADDR(addr = htol(args[optind], FAULT_ON_ERROR, NULL))) error(FATAL, "invalid kernel virtual address: %s\n", args[optind]); aflag++; } } else if ((sp = symbol_search(args[optind]))) { addr = sp->value; aflag++; } else { fprintf(fp, "symbol not found: %s\n", args[optind]); fprintf(fp, "possible alternatives:\n"); if (!symbol_query(args[optind], " ", NULL)) fprintf(fp, " (none found)\n"); goto freebuf; } } optind = optind_save; if (count == 0xdeadbeef) count = 1; else if (!aflag) error(FATAL, "no kernel virtual address argument entered\n"); if (pflag && !aflag) error(FATAL, "-p option requires address argument\n"); if (list_head_offset) addr -= list_head_offset; /* * Handle struct.member[,member] argument format. */ if (strstr(args[optind], ".")) { structname = GETBUF(strlen(args[optind])+1); strcpy(structname, args[optind]); separator = strstr(structname, "."); members = GETBUF(strlen(args[optind])+1); strcpy(members, separator+1); replace_string(members, ",", ' '); argc_members = parse_line(members, memberlist); } else structname = args[optind]; if ((arg_to_datatype(structname, dm, DATATYPE_QUERY|ANON_MEMBER_QUERY|RETURN_ON_ERROR) < 1)) error(FATAL, "invalid data structure reference: %s\n", structname); if ((argc_members > 1) && !aflag) { error(INFO, flags & SHOW_OFFSET ? "-o option not valid with multiple member format\n" : "multiple member format not supported in this syntax\n"); *separator = NULLCHAR; argc_members = 0; flags |= SHOW_OFFSET; } if ((argc_members > 1) && aflag && (flags & SHOW_OFFSET)) error(FATAL, "-o option not valid with multiple member format\n"); len = dm->size; if (count < 0) { addr -= len * abs(count); addr += len; } if (pc->curcmd_flags & MEMTYPE_FILEADDR) addr = 0; /* unused, but parsed by gdb */ for (c = 0; c < abs(count); c++, addr += len, pc->curcmd_private += len) { if (c) fprintf(fp,"\n"); i = 0; do { if (argc_members) { *separator = '.'; strcpy(separator+1, memberlist[i]); } switch (arg_to_datatype(structname, dm, ANON_MEMBER_QUERY|RETURN_ON_ERROR)) { case 0: error(FATAL, "invalid data structure reference: %s\n", structname); break; case 1: break; case 2: if (rawdata) error(FATAL, "member-specific output not allowed with -r\n"); break; } if (!(dm->flags & TYPEDEF)) { if (flags &(STRUCT_REQUEST|UNION_REQUEST) ) { if ((flags & (STRUCT_REQUEST|UNION_REQUEST)) != dm->type) goto freebuf; } else flags |= dm->type; } /* * No address was passed -- dump the structure/member declaration. */ if (!aflag || (aflag && (flags & SHOW_OFFSET))) { if (aflag) dm->vaddr = addr; set_temporary_radix(radix, &restore_radix); do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); restore_current_radix(restore_radix); goto freebuf; } if (!(flags & (UNION_REQUEST|STRUCT_REQUEST))) error(FATAL, "invalid argument"); /* * Display data. */ if (rawdata) raw_data_dump(addr, len, flags & STRUCT_VERBOSE); else if (pflag && !dm->member) { set_temporary_radix(radix, &restore_radix); print_struct_with_dereference(addr, dm, flags); restore_current_radix(restore_radix); } else { if (dm->member) open_tmpfile(); set_temporary_radix(radix, &restore_radix); if (flags & UNION_REQUEST) print_union(dm->name, addr); else if (flags & STRUCT_REQUEST) print_struct(dm->name, addr); if (dm->member) { if (!(pflag && dereference_pointer(addr, dm, flags))) parse_for_member(dm, PARSE_FOR_DATA); close_tmpfile(); } restore_current_radix(restore_radix); } } while (++i < argc_members); } freebuf: if (argc_members) { FREEBUF(structname); FREEBUF(members); } } /* * Generic function for dumping data structure declarations, with a small * fixup for typedefs, sizes and member offsets. */ static void do_datatype_declaration(struct datatype_member *dm, ulong flags) { long len; char buf[BUFSIZE]; char *p1, *p2, *multiline; FILE *sfp; if (CRASHDEBUG(1)) dump_datatype_member(fp, dm); open_tmpfile(); whatis_datatype(dm->name, flags, pc->tmpfile); rewind(pc->tmpfile); if (dm->member) flags |= SHOW_OFFSET; sfp = pc->saved_fp; len = dm->size; multiline = NULL; while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (STRNEQ(buf, "type = ")) { multiline = strstr(buf, "{"); if (flags & TYPEDEF) fprintf(sfp, "typedef "); p1 = buf + strlen("type = "); if ((p2 = strstr(buf, "(*)()"))) { *p2 = NULLCHAR; fprintf(sfp, "%s(*%s)();\n", p1, dm->name); } else if ((p2 = strstr(buf, "()"))) { *p2 = NULLCHAR; fprintf(sfp, "%s(%s)();\n", p1, dm->name); } else if (multiline) fprintf(sfp, "%s", p1); else fprintf(sfp, "%s %s;\n", strip_linefeeds(p1), dm->name); } else { if (multiline && STRNEQ(buf, "}") && (flags & TYPEDEF)){ if (strstr(buf, "} **()")) fprintf(sfp, "} **(%s)();\n", dm->name); else fprintf(sfp, "%s %s;\n", strip_linefeeds(buf), dm->name); } else { if ((flags & SHOW_OFFSET) && whitespace(buf[0])) show_member_offset(sfp, dm, buf); else fprintf(sfp, buf); } } } if (!dm->member) { switch (*gdb_output_radix) { default: case 10: fprintf(sfp, "SIZE: %ld\n", len); break; case 16: fprintf(sfp, "SIZE: 0x%lx\n", len); break; } } close_tmpfile(); } /* * Take a argument string, which may be in "struct.member" or "union.member" * format, figure out whether it's a structure or a union reference, and * fill in the appropriate fields of the dataytype_member structure. * Return 1 if it's a straight struct or union reference, 2 if it has * a legitimate .member attached to it, or 0 if it's bogus. */ int arg_to_datatype(char *s, struct datatype_member *dm, ulong flags) { char *p1; int both; BZERO(dm, sizeof(struct datatype_member)); both = FALSE; dm->name = s; if (!(p1 = strstr(s, "."))) both = FALSE; else if (flags & DATATYPE_QUERY) { *p1 = NULLCHAR; both = FALSE; } else { if ((p1 == s) || !strlen(p1+1)) goto datatype_member_fatal; *p1 = NULLCHAR; if (strstr(p1+1, ".")) goto datatype_member_fatal; both = TRUE; } if ((dm->size = DATATYPE_SIZE(dm)) < 0) { if (flags & RETURN_ON_ERROR) goto datatype_member_fatal; error(FATAL, "cannot handle \"%s\": try \"gdb whatis\" or \"gdb ptype\"\n", s); } if (!both) return 1; dm->member = p1+1; if ((dm->member_offset = MEMBER_OFFSET(dm->name, dm->member)) >= 0) return 2; if ((flags & ANON_MEMBER_QUERY) && ((dm->member_offset = ANON_MEMBER_OFFSET(dm->name, dm->member)) >= 0)) return 2; datatype_member_fatal: if (flags & RETURN_ON_ERROR) { if (both) *p1 = '.'; return 0; } if (both) { *p1 = '.'; if (strstr(p1+1, ".")) error(FATAL, "only one %s member allowed: %s\n", (dm->type == STRUCT_REQUEST) ? "struct" : ((dm->type == UNION_REQUEST) ? "union" : "struct/union"), s); } return (error(FATAL, "invalid argument: %s\n", s)); } /* * debug routine -- not called on purpose by anybody. */ static void dump_datatype_member(FILE *ofp, struct datatype_member *dm) { int others; others = 0; fprintf(ofp, " name: %s\n", dm->name); fprintf(ofp, " member: %s\n", dm->member); fprintf(ofp, " type: %lx (", dm->type); if (dm->type & STRUCT_REQUEST) fprintf(ofp, "%sSTRUCT_REQUEST", others++ ? "|" : ""); if (dm->type & UNION_REQUEST) fprintf(fp, "%sUNION_REQUEST", others++ ? "|" : ""); if (dm->type & INT64) fprintf(ofp, "%sINT64", others++ ? "|" : ""); if (dm->type & INT32) fprintf(ofp, "%sINT32", others++ ? "|" : ""); if (dm->type & INT16) fprintf(ofp, "%sINT16", others++ ? "|" : ""); if (dm->type & INT8) fprintf(ofp, "%sINT8", others++ ? "|" : ""); if (dm->type & POINTER) fprintf(ofp, "%sPOINTER", others++ ? "|" : ""); if (dm->type & FUNCTION) fprintf(ofp, "%sFUNCTION", others++ ? "|" : ""); if (dm->type & ARRAY) fprintf(ofp, "%sARRAY", others++ ? "|" : ""); if (dm->type & ENUM) fprintf(ofp, "%sENUM", others++ ? "|" : ""); if (dm->type & IN_UNION) fprintf(ofp, "%sIN_UNION", others++ ? "|" : ""); if (dm->type & IN_STRUCT) fprintf(ofp, "%sIN_STRUCT", others++ ? "|" : ""); fprintf(ofp, ")\n"); fprintf(ofp, " size: %ld\n", dm->size); fprintf(ofp, " member_offset: %ld\n", dm->member_offset); fprintf(ofp, " member_size: %ld\n", dm->member_size); fprintf(ofp, "member_typecode: %d\n", dm->member_typecode); fprintf(ofp, " flags: %lx ", dm->flags); dump_datatype_flags(dm->flags, ofp); fprintf(ofp, " tagname: %s\n", dm->tagname); fprintf(ofp, " value: %ld\n", dm->value); fprintf(ofp, " vaddr: %lx\n", dm->vaddr); fprintf(ofp, "\n"); } /* * This command displays the definition of structures, unions, typedefs or * text/data symbols: * * 1. For a structure name, the output is the same as if the "struct" * command was used. * 2. For a union name, the output is the same as if the "union" command * was used. * 3. For a typedef name that translates to a structure or union, the output * is the same as if the "struct" or "union" command was used. * 4. For a typedef name that translates to a primitive datatype, the one-line * declaration is displayed. * 5. For a kernel symbol name, the output is the same as if the "sym" command * was used. */ void cmd_whatis(void) { struct datatype_member datatype_member, *dm; struct syment *sp; char buf[BUFSIZE]; long len; int c; ulong flags; dm = &datatype_member; flags = 0; while ((c = getopt(argcnt, args, "o")) != EOF) { switch(c) { case 'o': flags |= SHOW_OFFSET; break; default: argerrs++; break; } } if (argerrs || !args[optind]) cmd_usage(pc->curcmd, SYNOPSIS); if (STREQ(args[optind], "struct") || STREQ(args[optind], "union") || STREQ(args[optind], "enum")) optind++; else if ((sp = symbol_search(args[optind]))) { whatis_variable(sp); return; } if (!args[optind]) cmd_usage(pc->curcmd, SYNOPSIS); if (arg_to_datatype(args[optind], dm, RETURN_ON_ERROR)) { if ((len = dm->size) < 0) goto whatis_failure; flags |= dm->type; if (dm->type == ENUM) { if (dm->tagname) fprintf(fp, "%senum%s%s = %ld\n", dm->flags & TYPEDEF ? "typedef " : "", strlen(dm->tagname) ? " " : "", dm->tagname, dm->value); else dump_enumerator_list(args[optind]); return; } do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); } else { if (!gdb_whatis(concat_args(buf, 1, FALSE))) goto whatis_failure; } return; whatis_failure: error(INFO, "cannot resolve: %s\n", concat_args(buf, 1, FALSE)); cmd_usage(pc->curcmd, SYNOPSIS); } /* * Try gdb's whatis on a command string. */ static int gdb_whatis(char *s) { char buf[BUFSIZE], *p1; open_tmpfile(); sprintf(buf, "whatis %s", s); if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { close_tmpfile(); return FALSE; } rewind(pc->tmpfile); while (fgets(buf, BUFSIZE, pc->tmpfile)) { p1 = buf; if (STRNEQ(buf, "type = ")) p1 += strlen("type = "); fprintf(pc->saved_fp, p1); } close_tmpfile(); return TRUE; } /* * Given the name of an enum, have gdb dump its enumerator list. */ int dump_enumerator_list(char *e) { struct gnu_request *req; struct datatype_member datatype_member, *dm; dm = &datatype_member; if (!arg_to_datatype(e, dm, RETURN_ON_ERROR) || (dm->size < 0) || (dm->type != ENUM) || dm->tagname) return FALSE; req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); req->command = GNU_GET_DATATYPE; req->name = e; req->flags = GNU_PRINT_ENUMERATORS; gdb_interface(req); FREEBUF(req); return TRUE; } /* * Given the name of an enum, return its value. */ int enumerator_value(char *e, long *value) { struct datatype_member datatype_member, *dm; dm = &datatype_member; if (arg_to_datatype(e, dm, RETURN_ON_ERROR)) { if ((dm->size >= 0) && (dm->type == ENUM) && dm->tagname) { *value = dm->value; return TRUE; } } return FALSE; } /* * Verify that a datatype exists, but return on error. */ int datatype_exists(char *s) { int retval; char buf[BUFSIZE], *p; struct gnu_request *req; strcpy(buf, s); if ((p = strstr(buf, "."))) *p = NULLCHAR; req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); req->command = GNU_GET_DATATYPE; req->name = buf; req->flags = GNU_RETURN_ON_ERROR; req->fp = pc->nullfp; gdb_interface(req); retval = req->typecode; FREEBUF(req); return retval; } /* * Set the output radix if requested, and pass it on to gdb. */ void cmd_p(void) { int c; struct syment *sp, *percpu_sp; unsigned radix, restore_radix; int leader, do_load_module_filter, success; char buf1[BUFSIZE]; char buf2[BUFSIZE]; char *p1; leader = do_load_module_filter = radix = restore_radix = 0; while ((c = getopt(argcnt, args, "dhxu")) != EOF) { switch(c) { case 'd': if (radix == 16) error(FATAL, "-d and -x are mutually exclusive\n"); radix = 10; break; case 'h': case 'x': if (radix == 10) error(FATAL, "-d and -x are mutually exclusive\n"); radix = 16; break; case 'u': pc->curcmd_flags |= MEMTYPE_UVADDR; break; default: argerrs++; break; } } if (argerrs || !args[optind]) cmd_usage(pc->curcmd, SYNOPSIS); if ((sp = symbol_search(args[optind])) && !args[optind+1]) { if ((percpu_sp = per_cpu_symbol_search(args[optind])) && display_per_cpu_info(percpu_sp)) return; sprintf(buf2, "%s = ", args[optind]); leader = strlen(buf2); if (module_symbol(sp->value, NULL, NULL, NULL, *gdb_output_radix)) do_load_module_filter = TRUE; } else if ((percpu_sp = per_cpu_symbol_search(args[optind])) && display_per_cpu_info(percpu_sp)) return; else if (st->flags & LOAD_MODULE_SYMS) do_load_module_filter = TRUE; if (leader || do_load_module_filter) open_tmpfile(); set_temporary_radix(radix, &restore_radix); success = gdb_pass_through(concat_args(buf1, 0, TRUE), NULL, GNU_RETURN_ON_ERROR); if (success && (leader || do_load_module_filter)) { int firstline; if (leader) { fprintf(pc->saved_fp, buf2); fflush(pc->saved_fp); } firstline = TRUE; rewind(pc->tmpfile); while (fgets(buf1, BUFSIZE, pc->tmpfile)) { if (firstline && (p1 = strstr(buf1, "{")) && !STRNEQ(p1, "{\n")) { *p1 = NULLCHAR; fprintf(pc->saved_fp, buf1); fprintf(pc->saved_fp, "\n {"); print_verbatim(pc->saved_fp, p1+1); } else print_verbatim(pc->saved_fp, do_load_module_filter ? load_module_filter(buf1, LM_P_FILTER) : buf1); firstline = FALSE; } } if (leader || do_load_module_filter) close_tmpfile(); restore_current_radix(restore_radix); if (!success) error(FATAL, "gdb request failed: %s\n", concat_args(buf1, 0, TRUE)); } /* * Display the datatype of the per_cpu__xxx symbol and * the addresses of each its per-cpu instances. */ static int display_per_cpu_info(struct syment *sp) { int c; ulong addr; char buf[BUFSIZE]; if (((kt->flags & (SMP|PER_CPU_OFF)) != (SMP|PER_CPU_OFF)) || (!is_percpu_symbol(sp)) || !((sp->type == 'd') || (sp->type == 'D') || (sp->type == 'V'))) return FALSE; fprintf(fp, "PER-CPU DATA TYPE:\n "); sprintf(buf, "whatis %s", sp->name); if (!gdb_pass_through(buf, pc->nullfp, GNU_RETURN_ON_ERROR)) fprintf(fp, "[undetermined type] %s;\n", sp->name); else whatis_variable(sp); fprintf(fp, "PER-CPU ADDRESSES:\n"); for (c = 0; c < kt->cpus; c++) { addr = sp->value + kt->__per_cpu_offset[c]; fprintf(fp, " [%d]: %lx\n", c, addr); } return TRUE; } static struct load_module * get_module_percpu_sym_owner(struct syment *sp) { int i; struct load_module *lm; if (!IS_MODULE_SYMBOL(sp)) return NULL; /* * Find out percpu symbol owner module. * If found out, sp is module's percpu symbol. */ for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!MODULE_PERCPU_SYMS_LOADED(lm)) continue; if (IN_MODULE_PERCPU(sp->value, lm)) return lm; } return NULL; } static int is_percpu_symbol(struct syment *sp) { if (sp->value >= st->__per_cpu_start) { if (sp->value < st->__per_cpu_end) /* kernel percpu symbol */ return 1; else if (get_module_percpu_sym_owner(sp)) /* module percpu symbol */ return 2; } return 0; } /* * As a latch ditch effort before a command is thrown away by exec_command(), * args[0] is checked to see whether it's the name of a variable, structure, * union, or typedef. If so, args[0] is changed to the appropriate command, * i.e., "p", "struct", "union", or "whatis", and the original args are all * shifted into the next higer args[] location. */ int is_datatype_command(void) { int i; long len; char *command; struct datatype_member datatype_member, *dm; struct syment *sp; char *rdarg; char buf[BUFSIZE]; if (!args[0]) return FALSE; strcpy(buf, args[0]); dm = &datatype_member; if ((sp = symbol_search(args[0])) && (argcnt == 1)) { if (is_gdb_command(FALSE, RETURN_ON_ERROR)) { pc->curcmd = pc->program_name; error(FATAL, "ambiguous command: %s (symbol and gdb command)\n", args[0]); } command = "p"; } else if (STREQ(args[0], "enum")) command = "whatis"; else if (!datatype_exists(args[0])) return FALSE; else if (!arg_to_datatype(buf, dm, RETURN_ON_ERROR|DATATYPE_QUERY)) return FALSE; else { if (is_gdb_command(FALSE, RETURN_ON_ERROR)) { pc->curcmd = pc->program_name; error(FATAL, "ambiguous command: %s (symbol/data type and gdb command)\n", args[0]); } if ((sp = symbol_search(args[0])) && (argcnt == 1)) { command = "p"; dm->type = 0; } else if ((len = DATATYPE_SIZE(dm)) < 0) { return FALSE; } else if (sp) { command = "p"; dm->type = 0; } switch (dm->type) { case STRUCT_REQUEST: if ((dm->flags & TYPEDEF) && (argcnt == 1)) command = "whatis"; else command = "struct"; break; case UNION_REQUEST: if ((dm->flags & TYPEDEF) && (argcnt == 1)) command = "whatis"; else command = "union"; break; case POINTER: command = "whatis"; break; case ARRAY: command = "whatis"; break; case FUNCTION: command = "whatis"; break; case ENUM: command = "whatis"; break; default: if (dm->type & INTEGER_TYPE) { switch (dm->type) { case INT64: rdarg = "-64"; break; case INT32: rdarg = "-32"; break; case INT16: rdarg = "-16"; break; case INT8: rdarg = "-8"; break; default: rdarg = NULL; break; } if (args[1]) { if ((sp = symbol_search(args[1]))) { command = "p"; args[0] = args[1]; argcnt--; } else { command = "rd"; args[0] = rdarg; } } else command = "whatis"; } else return FALSE; break; } } for (i = argcnt; i; i--) args[i] = args[i-1]; args[0] = command; argcnt++; return TRUE; } /* * Given a structure name and an address, have gdb do most of the work. */ static void print_struct(char *s, ulong addr) { char buf[BUFSIZE]; if (is_typedef(s)) sprintf(buf, "output *(%s *)0x%lx", s, addr); else sprintf(buf, "output *(struct %s *)0x%lx", s, addr); fprintf(fp, "struct %s ", s); gdb_pass_through(buf, NULL, GNU_RETURN_ON_ERROR); fprintf(fp, "\n"); } /* * Given a union name and an address, let gdb do the work. */ static void print_union(char *s, ulong addr) { char buf[BUFSIZE]; if (is_typedef(s)) sprintf(buf, "output *(%s *)0x%lx", s, addr); else sprintf(buf, "output *(union %s *)0x%lx", s, addr); fprintf(fp, "union %s ", s); gdb_pass_through(buf, NULL, GNU_RETURN_ON_ERROR); } /* * Given a structure or union, find its definition in the datatype symbol * file, and dump it. If the verbose flags is set, everything from the * file is shown; otherwise the bitpos, size and id data is stripped. */ static void whatis_datatype(char *st, ulong flags, FILE *ofp) { char lookbuf[BUFSIZE]; if (flags & TYPEDEF) sprintf(lookbuf, "ptype %s", st); else if (flags & UNION_REQUEST) sprintf(lookbuf, "ptype union %s", st); else if (flags & STRUCT_REQUEST) sprintf(lookbuf, "ptype struct %s", st); else return; if (!gdb_pass_through(lookbuf, ofp, GNU_RETURN_ON_ERROR)) { /* * When a structure is defined using the format: * * typedef struct { * yada yada yada * } type_t; * * gdb says it's a structure and not a typedef. So * if the union or struct pass-through fails, it can't * hurt to retry it with just "ptype type_t" before * giving up. */ if (flags & (UNION_REQUEST|STRUCT_REQUEST)) { sprintf(lookbuf, "ptype %s", st); gdb_pass_through(lookbuf, ofp, 0); } } } /* * Scan the symbol file for a variable declaration. */ static void whatis_variable(struct syment *sp) { char *p1; char buf[BUFSIZE]; open_tmpfile(); sprintf(buf, "whatis %s", sp->name); if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { close_tmpfile(); error(FATAL, "gdb request failed: whatis %s\n", sp->name); } rewind(pc->tmpfile); while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (STRNEQ(buf, "type = ")) break; } close_tmpfile(); clean_line(buf); if ((p1 = strstr(buf, "["))) { shift_string_right(p1, strlen(sp->name)); BCOPY(sp->name, p1, strlen(sp->name)); p1 = buf + strlen("type = "); fprintf(fp, "%s;\n", p1); } else if ((p1 = strstr(buf, "("))) { if (index(buf, '(') == rindex(buf, '(')) { shift_string_right(p1, strlen(sp->name)); BCOPY(sp->name, p1, strlen(sp->name)); } else { p1 = strstr(buf, ")"); shift_string_right(p1, strlen(sp->name)); BCOPY(sp->name, p1, strlen(sp->name)); } p1 = buf + strlen("type = "); fprintf(fp, "%s;\n", p1); } else { p1 = buf + strlen("type = "); fprintf(fp, "%s%s%s;\n", p1, LASTCHAR(p1) == '*' ? "":" ", sp->name); } } /* * Determines whether the current structure or union member is a typedef. */ static int is_typedef(char *name) { struct datatype_member datatype_member, *dm; if (!name) drop_core("is_typedef() received NULL name string\n"); dm = &datatype_member; BZERO(dm, sizeof(struct datatype_member)); dm->name = name; return (DATATYPE_SIZE(dm) < 0 ? FALSE : (dm->flags & TYPEDEF)); } static void dump_datatype_flags(ulong flags, FILE *ofp) { int others; others = 0; fprintf(ofp, "("); if (flags & UINT8) fprintf(ofp, "%sUINT8", others++ ? "|" : ""); if (flags & INT8) fprintf(ofp, "%sINT8", others++ ? "|" : ""); if (flags & UINT16) fprintf(ofp, "%sUINT16", others++ ? "|" : ""); if (flags & INT16) fprintf(ofp, "%sINT16", others++ ? "|" : ""); if (flags & UINT32) fprintf(ofp, "%sUINT32", others++ ? "|" : ""); if (flags & INT32) fprintf(ofp, "%sINT32", others++ ? "|" : ""); if (flags & UINT64) fprintf(ofp, "%sUINT64", others++ ? "|" : ""); if (flags & INT64) fprintf(ofp, "%sINT64", others++ ? "|" : ""); if (flags & POINTER) fprintf(ofp, "%sPOINTER", others++ ? "|" : ""); if (flags & FUNCTION) fprintf(ofp, "%sFUNCTION", others++ ? "|" : ""); if (flags & ARRAY) fprintf(ofp, "%sARRAY", others++ ? "|" : ""); if (flags & ENUM) fprintf(ofp, "%sENUM", others++ ? "|" : ""); if (flags & TYPEDEF) fprintf(ofp, "%sTYPEDEF", others++ ? "|" : ""); if (flags & STRUCT_VERBOSE) fprintf(ofp, "%sSTRUCT_VERBOSE", others++ ? "|" : ""); if (flags & SHOW_OFFSET) fprintf(ofp, "%sSHOW_OFFSET", others++ ? "|" : ""); if (flags & DATATYPE_QUERY) fprintf(ofp, "%sDATATYPE_QUERY", others++ ? "|" : ""); if (flags & ANON_MEMBER_QUERY) fprintf(ofp, "%sANON_MEMBER_QUERY", others++ ? "|" : ""); fprintf(ofp, ")\n"); } /* * When a request is made to print just a member of a structure or union, * the whole datatype is dumped to a temporary file, and this routine * parses through it for the targeted member. */ static void parse_for_member(struct datatype_member *dm, ulong flag) { char *s; char buf[BUFSIZE]; char lookfor1[BUFSIZE]; char lookfor2[BUFSIZE]; char lookfor3[BUFSIZE]; char lookfor4[BUFSIZE]; char lookfor5[BUFSIZE]; long curpos, last_open_bracket; int indent, on, array, embed; char *p1; s = dm->member; indent = 0; array = FALSE; on = 0; embed = 0; rewind(pc->tmpfile); switch (flag) { case PARSE_FOR_DATA: sprintf(lookfor1, " %s ", s); sprintf(lookfor2, " %s[", s); next_item: while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (embed && (count_leading_spaces(buf) == embed)) embed = 0; if (!on && !embed && strstr(buf, "= {") && !strstr(buf, lookfor1)) embed = count_leading_spaces(buf); if (embed) continue; if (strstr(buf, lookfor1) || strstr(buf, lookfor2)) { on++; if (strstr(buf, "= {")) indent = count_leading_spaces(buf); if (strstr(buf, "[")) array = TRUE; } if (on) { if ((indent && (on > 1) && (count_leading_spaces(buf) == indent) && !strstr(buf, "}")) || (buf[0] == '}')) { break; } if (!indent) { if ((p1 = strstr(buf, ", \n"))) sprintf(p1, "\n"); fprintf(pc->saved_fp, "%s", buf); break; } if (strstr(buf, "}") && (count_leading_spaces(buf) == indent)) { if ((p1 = strstr(buf, "}, \n"))) sprintf(p1, "}\n"); fprintf(pc->saved_fp, "%s", buf); break; } fprintf(pc->saved_fp, "%s", buf); on++; } } if (array) { on = array = FALSE; on = 0; goto next_item; } break; case PARSE_FOR_DECLARATION: last_open_bracket = curpos = 0; sprintf(lookfor1, " %s;", s); sprintf(lookfor2, "*%s;", s); sprintf(lookfor3, " %s[", s); sprintf(lookfor4, "*%s[", s); sprintf(lookfor5, " %s :", s); while (fgets(buf, BUFSIZE, pc->tmpfile)) { indent = count_leading_spaces(buf); switch (indent) { case 0: curpos = ftell(pc->tmpfile); continue; case INITIAL_INDENT: if (strstr(buf, "{")) last_open_bracket = curpos; break; default: if (!on && (indent != INITIAL_INDENT)) continue; } if (strstr(buf, lookfor1) || strstr(buf, lookfor2) || strstr(buf, lookfor3) || strstr(buf, lookfor4) || strstr(buf, lookfor5)) { if (strstr(buf, "}") && !on) { on = TRUE; fseek(pc->tmpfile, last_open_bracket, SEEK_SET); } else { print_verbatim(pc->saved_fp, buf); if (indent == INITIAL_INDENT) break; } } else if (on) print_verbatim(pc->saved_fp, buf); curpos = ftell(pc->tmpfile); } break; } } /* * Dig out a member name from a formatted gdb structure declaration dump, * and print its offset from the named structure passed in. */ static int show_member_offset(FILE *ofp, struct datatype_member *dm, char *inbuf) { int i, c, len; long offset; char *t1, *target; char *arglist[MAXARGS]; char buf1[BUFSIZE]; char fmt[BUFSIZE]; char workbuf[BUFSIZE]; int end_of_block; if (!STRNEQ(inbuf, " ")) { fprintf(ofp, "rejecting: %s", inbuf); return FALSE; } if (STRNEQ(inbuf, " union {")) dm->flags |= IN_UNION; if (STRNEQ(inbuf, " struct {")) dm->flags |= IN_STRUCT; end_of_block = STRNEQ(inbuf, " } "); switch (*gdb_output_radix) { default: case 10: sprintf(buf1, "%ld", dm->size); break; case 16: sprintf(buf1, "0x%lx", dm->size); } len = strlen(buf1) + 4; strcpy(workbuf, inbuf); c = parse_line(workbuf, arglist); target = NULL; if (strstr(inbuf, ":")) { for (i = 0; i < c; i++) { if (i && STREQ(arglist[i], ":")) { target = arglist[i-1]; break; } } } else if (c) { for (i = 0; i < c; i++) { if (STRNEQ(arglist[i], "(*")) { target = arglist[i]+2; if (!(t1 = strstr(target, ")"))) continue; *t1 = NULLCHAR; break; } } if (i == c) { target = arglist[c-1]; if (!strstr(target, ";")) target = NULL; } } if (!target) goto do_empty_offset; null_first_space(clean_line(replace_string(target, "*[];()", ' '))); if (strlen(target) == 0) goto do_empty_offset; if (dm->member && !STREQ(dm->member, target)) { if (end_of_block) dm->flags &= ~(IN_UNION|IN_STRUCT); return FALSE; } offset = MEMBER_OFFSET(dm->name, target); if (offset == -1) offset = ANON_MEMBER_OFFSET(dm->name, target); if (offset == -1) goto do_empty_offset; if (end_of_block && dm->member) { if (dm->vaddr) sprintf(buf1, " [%lx]", offset + dm->vaddr); else sprintf(buf1, *gdb_output_radix == 10 ? " [%ld]" : " [0x%lx]", offset); sprintf(fmt, "%c%ds", '%', len+1); fprintf(ofp, fmt, " "); switch (dm->flags & (IN_UNION|IN_STRUCT)) { case IN_UNION: fprintf(ofp, "union {\n"); break; case IN_STRUCT: fprintf(ofp, "struct {\n"); break; } dm->flags &= ~(IN_UNION|IN_STRUCT); } if (dm->vaddr) sprintf(buf1, " [%lx]", offset + dm->vaddr); else sprintf(buf1, *gdb_output_radix == 10 ? " [%ld]" : " [0x%lx]", offset); sprintf(fmt, "%c%ds", '%', len); fprintf(ofp, fmt, buf1); fprintf(ofp, &inbuf[3]); return TRUE; do_empty_offset: if (end_of_block) dm->flags &= ~(IN_UNION|IN_STRUCT); if (dm->member) return FALSE; len = strlen(buf1)+1; fprintf(ofp, "%s%s", space(len), inbuf); return FALSE; } /* * Get and store the size of a "known" array. This function is only called * once per requested array; after the first time, ARRAY_LENGTH() should be * used. * * For data symbols, get_symbol_type() does the work. * For structure member arrays, datatype_info() does the work. * For two-dimension arrays, or if the designated function above fails, * then just parse "whatis" or "ptype" commands as a last resort. */ int get_array_length(char *s, int *two_dim, long entry_size) { char copy[BUFSIZE]; char buf[BUFSIZE]; char lookfor1[BUFSIZE]; char lookfor2[BUFSIZE]; int retval; struct datatype_member datatype_member, *dm; struct gnu_request gnu_request, *req; char *p1, *p2; strcpy(copy, s); dm = &datatype_member; BZERO(dm, sizeof(struct datatype_member)); if ((retval = builtin_array_length(s, 0, two_dim))) return retval; /* symbol_search cannot be done with just kernel type information */ if (!(LKCD_KERNTYPES()) && symbol_search(s)) { if (!two_dim) { req = &gnu_request; if ((get_symbol_type(copy, NULL, req) == TYPE_CODE_ARRAY) && req->target_typecode && req->target_length) { retval = req->length / req->target_length; goto store_builtin; } } sprintf(buf, "whatis %s", s); } else { if (arg_to_datatype(copy, dm, RETURN_ON_ERROR)) { if (!dm->member) goto store_builtin; datatype_info(dm->name, dm->member, dm); switch (dm->type) { case UNION_REQUEST: if (entry_size && dm->member_size && (dm->member_typecode == TYPE_CODE_ARRAY)) { retval = dm->member_size/entry_size; goto store_builtin; } sprintf(buf, "ptype union %s", dm->name); break; case STRUCT_REQUEST: if (entry_size && dm->member_size && (dm->member_typecode == TYPE_CODE_ARRAY)) { retval = dm->member_size/entry_size; goto store_builtin; } sprintf(buf, "ptype struct %s", dm->name); break; default: goto store_builtin; } sprintf(lookfor1, " %s[", dm->member); sprintf(lookfor2, "*%s[", dm->member); } else goto store_builtin; } open_tmpfile2(); if (two_dim) *two_dim = 0; gdb_pass_through(buf, pc->tmpfile2, 0); rewind(pc->tmpfile2); while (fgets(buf, BUFSIZE, pc->tmpfile2)) { if (STRNEQ(buf, "type = ") && (p1 = strstr(buf, "[")) && (p2 = strstr(buf, "]")) && (index(buf, '[') == rindex(buf, '['))) { *p2 = NULLCHAR; p1++; if (strlen(p1)) { retval = atoi(p1); break; } } if (STRNEQ(buf, "type = ") && (count_chars(buf, '[') == 2) && (count_chars(buf, ']') == 2) && two_dim) { p1 = strstr(buf, "["); p2 = strstr(buf, "]"); *p2 = NULLCHAR; p1++; if (strlen(p1)) *two_dim = atoi(p1); else break; p2++; p1 = strstr(p2, "["); p2 = strstr(p1, "]"); p1++; if (strlen(p1)) retval = atoi(p1); else { retval = 0; *two_dim = 0; break; } break; } if (dm->type && (strstr(buf, lookfor1) || strstr(buf, lookfor2)) && (p1 = strstr(buf, "[")) && (p2 = strstr(buf, "]")) && (index(buf, '[') == rindex(buf, '['))) { *p2 = NULLCHAR; p1++; if (strlen(p1)) { retval = atoi(p1); break; } } } close_tmpfile2(); store_builtin: return (builtin_array_length(s, retval, two_dim)); } /* * Get and store the size of a "known" array. * A wrapper for get_array_length(), for cases in which * the name of the result to be stored is different from the * structure.member to be evaluated. */ int get_array_length_alt(char *name, char *s, int *two_dim, long entry_size) { int retval; retval = get_array_length(s, two_dim, entry_size); if (retval) retval = builtin_array_length(name, retval, two_dim); return retval; } /* * Designed for use by non-debug kernels, but used by all. */ int builtin_array_length(char *s, int len, int *two_dim) { int *lenptr; int *dimptr; lenptr = dimptr = NULL; if (STREQ(s, "kmem_cache_s.name")) lenptr = &array_table.kmem_cache_s_name; else if (STREQ(s, "kmem_cache_s.c_name")) lenptr = &array_table.kmem_cache_s_c_name; else if (STREQ(s, "kmem_cache_s.array")) lenptr = &array_table.kmem_cache_s_array; else if (STREQ(s, "kmem_cache.array")) lenptr = &array_table.kmem_cache_s_array; else if (STREQ(s, "kmem_cache_s.cpudata")) lenptr = &array_table.kmem_cache_s_cpudata; else if (STREQ(s, "log_buf")) lenptr = &array_table.log_buf; else if (STREQ(s, "irq_desc") || STREQ(s, "_irq_desc")) lenptr = &array_table.irq_desc; else if (STREQ(s, "irq_action")) lenptr = &array_table.irq_action; else if (STREQ(s, "timer_vec.vec")) lenptr = &array_table.timer_vec_vec; else if (STREQ(s, "timer_vec_root.vec")) lenptr = &array_table.timer_vec_root_vec; else if (STREQ(s, "tvec_s.vec")) lenptr = &array_table.tvec_s_vec; else if (STREQ(s, "tvec_root_s.vec")) lenptr = &array_table.tvec_root_s_vec; else if (STREQ(s, "net_device.name")) lenptr = &array_table.net_device_name; else if (STREQ(s, "neigh_table.hash_buckets")) lenptr = &array_table.neigh_table_hash_buckets; else if (STREQ(s, "neighbour.ha")) lenptr = &array_table.neighbour_ha; else if (STREQ(s, "swap_info")) lenptr = &array_table.swap_info; else if (STREQ(s, "page_hash_table")) lenptr = &array_table.page_hash_table; else if (STREQ(s, "pglist_data.node_zones")) lenptr = &array_table.pglist_data_node_zones; else if (STREQ(s, "zone_struct.free_area")) lenptr = &array_table.zone_struct_free_area; else if (STREQ(s, "zone.free_area")) lenptr = &array_table.zone_free_area; else if (STREQ(s, "prio_array.queue")) lenptr = &array_table.prio_array_queue; else if (STREQ(s, "height_to_maxindex")) lenptr = &array_table.height_to_maxindex; else if (STREQ(s, "pid_hash")) lenptr = &array_table.pid_hash; else if (STREQ(s, "free_area")) { lenptr = &array_table.free_area; if (two_dim) dimptr = &array_table.free_area_DIMENSION; } else if (STREQ(s, "kmem_cache.node")) lenptr = &array_table.kmem_cache_node; else if (STREQ(s, "kmem_cache.cpu_slab")) lenptr = &array_table.kmem_cache_cpu_slab; else if (STREQ(s, "rt_prio_array.queue")) lenptr = &array_table.rt_prio_array_queue; if (!lenptr) /* not stored */ return(len); if (*lenptr) { /* pre-set */ if (dimptr && two_dim) *two_dim = *dimptr; return(*lenptr); } if (len) { *lenptr = len; /* initialize passed-in value(s) */ if (dimptr && two_dim) *dimptr = *two_dim; return(len); } return(0); /* in table, but not set yet */ } /* * "help -o" output */ void dump_offset_table(char *spec, ulong makestruct) { char buf[BUFSIZE], *p1; char revname[BUFSIZE]; struct new_utsname *uts; long long data_debug; data_debug = pc->flags & DATADEBUG; pc->flags &= ~DATADEBUG; uts = NULL; if (makestruct) { uts = &kt->utsname; sprintf(revname, "%s_%s", pc->machine_type, uts->release); p1 = revname + strlen(pc->machine_type); while (*p1) { if (((*p1 >= '0') && (*p1 <= '9')) || ((*p1 >= 'a') && (*p1 <= 'z')) || ((*p1 >= 'A') && (*p1 <= 'Z'))) p1++; else *p1++ = '_'; } } if (spec || makestruct) open_tmpfile(); fprintf(fp, " offset_table:\n"); fprintf(fp, " list_head_next: %ld\n", OFFSET(list_head_next)); fprintf(fp, " list_head_prev: %ld\n", OFFSET(list_head_prev)); fprintf(fp, " task_struct_pid: %ld\n", OFFSET(task_struct_pid)); fprintf(fp, " task_struct_state: %ld\n", OFFSET(task_struct_state)); fprintf(fp, " task_struct_exit_state: %ld\n", OFFSET(task_struct_exit_state)); fprintf(fp, " task_struct_comm: %ld\n", OFFSET(task_struct_comm)); fprintf(fp, " task_struct_mm: %ld\n", OFFSET(task_struct_mm)); fprintf(fp, " task_struct_tss: %ld\n", OFFSET(task_struct_tss)); fprintf(fp, " task_struct_thread: %ld\n", OFFSET(task_struct_thread)); fprintf(fp, " task_struct_active_mm: %ld\n", OFFSET(task_struct_active_mm)); fprintf(fp, " task_struct_tss_eip: %ld\n", OFFSET(task_struct_tss_eip)); fprintf(fp, " task_struct_tss_esp: %ld\n", OFFSET(task_struct_tss_esp)); fprintf(fp, " task_struct_tss_ksp: %ld\n", OFFSET(task_struct_tss_ksp)); fprintf(fp, " task_struct_thread_eip: %ld\n", OFFSET(task_struct_thread_eip)); fprintf(fp, " task_struct_thread_esp: %ld\n", OFFSET(task_struct_thread_esp)); fprintf(fp, " task_struct_thread_ksp: %ld\n", OFFSET(task_struct_thread_ksp)); fprintf(fp, " task_struct_processor: %ld\n", OFFSET(task_struct_processor)); fprintf(fp, " task_struct_p_pptr: %ld\n", OFFSET(task_struct_p_pptr)); fprintf(fp, " task_struct_parent: %ld\n", OFFSET(task_struct_parent)); fprintf(fp, " task_struct_has_cpu: %ld\n", OFFSET(task_struct_has_cpu)); fprintf(fp, " task_struct_cpus_runnable: %ld\n", OFFSET(task_struct_cpus_runnable)); fprintf(fp, " task_struct_next_task: %ld\n", OFFSET(task_struct_next_task)); fprintf(fp, " task_struct_files: %ld\n", OFFSET(task_struct_files)); fprintf(fp, " task_struct_fs: %ld\n", OFFSET(task_struct_fs)); fprintf(fp, " task_struct_pidhash_next: %ld\n", OFFSET(task_struct_pidhash_next)); fprintf(fp, " task_struct_next_run: %ld\n", OFFSET(task_struct_next_run)); fprintf(fp, " task_struct_flags: %ld\n", OFFSET(task_struct_flags)); fprintf(fp, " task_struct_sig: %ld\n", OFFSET(task_struct_sig)); fprintf(fp, " task_struct_signal: %ld\n", OFFSET(task_struct_signal)); fprintf(fp, " task_struct_blocked: %ld\n", OFFSET(task_struct_blocked)); fprintf(fp, " task_struct_sigpending: %ld\n", OFFSET(task_struct_sigpending)); fprintf(fp, " task_struct_pending: %ld\n", OFFSET(task_struct_pending)); fprintf(fp, " task_struct_sigqueue: %ld\n", OFFSET(task_struct_sigqueue)); fprintf(fp, " task_struct_sighand: %ld\n", OFFSET(task_struct_sighand)); fprintf(fp, " task_struct_run_list: %ld\n", OFFSET(task_struct_run_list)); fprintf(fp, " task_struct_pgrp: %ld\n", OFFSET(task_struct_pgrp)); fprintf(fp, " task_struct_tgid: %ld\n", OFFSET(task_struct_tgid)); fprintf(fp, " task_struct_namespace: %ld\n", OFFSET(task_struct_namespace)); fprintf(fp, " task_struct_pids: %ld\n", OFFSET(task_struct_pids)); fprintf(fp, " task_struct_last_run: %ld\n", OFFSET(task_struct_last_run)); fprintf(fp, " task_struct_timestamp: %ld\n", OFFSET(task_struct_timestamp)); fprintf(fp, " task_struct_sched_info: %ld\n", OFFSET(task_struct_sched_info)); fprintf(fp, " task_struct_rt: %ld\n", OFFSET(task_struct_rt)); fprintf(fp, " sched_rt_entity_run_list: %ld\n", OFFSET(sched_rt_entity_run_list)); fprintf(fp, " sched_info_last_arrival: %ld\n", OFFSET(sched_info_last_arrival)); fprintf(fp, " task_struct_thread_info: %ld\n", OFFSET(task_struct_thread_info)); fprintf(fp, " task_struct_nsproxy: %ld\n", OFFSET(task_struct_nsproxy)); fprintf(fp, " task_struct_rlim: %ld\n", OFFSET(task_struct_rlim)); fprintf(fp, " task_struct_prio: %ld\n", OFFSET(task_struct_prio)); fprintf(fp, " task_struct_on_rq: %ld\n", OFFSET(task_struct_on_rq)); fprintf(fp, " thread_info_task: %ld\n", OFFSET(thread_info_task)); fprintf(fp, " thread_info_cpu: %ld\n", OFFSET(thread_info_cpu)); fprintf(fp, " thread_info_flags: %ld\n", OFFSET(thread_info_flags)); fprintf(fp, " thread_info_previous_esp: %ld\n", OFFSET(thread_info_previous_esp)); fprintf(fp, " nsproxy_mnt_ns: %ld\n", OFFSET(nsproxy_mnt_ns)); fprintf(fp, " mnt_namespace_root: %ld\n", OFFSET(mnt_namespace_root)); fprintf(fp, " mnt_namespace_list: %ld\n", OFFSET(mnt_namespace_list)); fprintf(fp, " pid_link_pid: %ld\n", OFFSET(pid_link_pid)); fprintf(fp, " pid_hash_chain: %ld\n", OFFSET(pid_hash_chain)); fprintf(fp, " pid_numbers: %ld\n", OFFSET(pid_numbers)); fprintf(fp, " upid_nr: %ld\n", OFFSET(upid_nr)); fprintf(fp, " upid_ns: %ld\n", OFFSET(upid_ns)); fprintf(fp, " upid_pid_chain: %ld\n", OFFSET(upid_pid_chain)); fprintf(fp, " pid_tasks: %ld\n", OFFSET(pid_tasks)); fprintf(fp, " hlist_node_next: %ld\n", OFFSET(hlist_node_next)); fprintf(fp, " hlist_node_pprev: %ld\n", OFFSET(hlist_node_pprev)); fprintf(fp, " pid_pid_chain: %ld\n", OFFSET(pid_pid_chain)); fprintf(fp, " thread_struct_eip: %ld\n", OFFSET(thread_struct_eip)); fprintf(fp, " thread_struct_esp: %ld\n", OFFSET(thread_struct_esp)); fprintf(fp, " thread_struct_ksp: %ld\n", OFFSET(thread_struct_ksp)); fprintf(fp, " thread_struct_rip: %ld\n", OFFSET(thread_struct_rip)); fprintf(fp, " thread_struct_rsp: %ld\n", OFFSET(thread_struct_rsp)); fprintf(fp, " thread_struct_rsp0: %ld\n", OFFSET(thread_struct_rsp0)); fprintf(fp, " signal_struct_count: %ld\n", OFFSET(signal_struct_count)); fprintf(fp, " signal_struct_nr_threads: %ld\n", OFFSET(signal_struct_nr_threads)); fprintf(fp, " signal_struct_action: %ld\n", OFFSET(signal_struct_action)); fprintf(fp, " signal_struct_shared_pending: %ld\n", OFFSET(signal_struct_shared_pending)); fprintf(fp, " signal_struct_rlim: %ld\n", OFFSET(signal_struct_rlim)); fprintf(fp, " task_struct_start_time: %ld\n", OFFSET(task_struct_start_time)); fprintf(fp, " task_struct_times: %ld\n", OFFSET(task_struct_times)); fprintf(fp, " task_struct_cpu: %ld\n", OFFSET(task_struct_cpu)); fprintf(fp, " task_struct_utime: %ld\n", OFFSET(task_struct_utime)); fprintf(fp, " task_struct_stime: %ld\n", OFFSET(task_struct_stime)); fprintf(fp, " tms_tms_utime: %ld\n", OFFSET(tms_tms_utime)); fprintf(fp, " tms_tms_stime: %ld\n", OFFSET(tms_tms_stime)); fprintf(fp, " timekeeper_xtime: %ld\n", OFFSET(timekeeper_xtime)); fprintf(fp, " timekeeper_xtime_sec: %ld\n", OFFSET(timekeeper_xtime_sec)); fprintf(fp, " k_sigaction_sa: %ld\n", OFFSET(k_sigaction_sa)); fprintf(fp, " sigaction_sa_handler: %ld\n", OFFSET(sigaction_sa_handler)); fprintf(fp, " sigaction_sa_flags: %ld\n", OFFSET(sigaction_sa_flags)); fprintf(fp, " sigaction_sa_mask: %ld\n", OFFSET(sigaction_sa_mask)); fprintf(fp, " sigpending_head: %ld\n", OFFSET(sigpending_head)); fprintf(fp, " sigpending_signal: %ld\n", OFFSET(sigpending_signal)); fprintf(fp, " sigpending_list: %ld\n", OFFSET(sigpending_list)); fprintf(fp, " signal_queue_next: %ld\n", OFFSET(signal_queue_next)); fprintf(fp, " signal_queue_info: %ld\n", OFFSET(signal_queue_info)); fprintf(fp, " sigqueue_next: %ld\n", OFFSET(sigqueue_next)); fprintf(fp, " sigqueue_info: %ld\n", OFFSET(sigqueue_info)); fprintf(fp, " sigqueue_list: %ld\n", OFFSET(sigqueue_list)); fprintf(fp, " sighand_struct_action: %ld\n", OFFSET(sighand_struct_action)); fprintf(fp, " siginfo_si_signo: %ld\n", OFFSET(siginfo_si_signo)); fprintf(fp, " thread_struct_fph: %ld\n", OFFSET(thread_struct_fph)); fprintf(fp, " thread_struct_cr3: %ld\n", OFFSET(thread_struct_cr3)); fprintf(fp, " thread_struct_ptbr: %ld\n", OFFSET(thread_struct_ptbr)); fprintf(fp, " thread_struct_pg_tables: %ld\n", OFFSET(thread_struct_pg_tables)); fprintf(fp, " switch_stack_r26: %ld\n", OFFSET(switch_stack_r26)); fprintf(fp, " switch_stack_b0: %ld\n", OFFSET(switch_stack_b0)); fprintf(fp, " switch_stack_ar_bspstore: %ld\n", OFFSET(switch_stack_ar_bspstore)); fprintf(fp, " switch_stack_ar_pfs: %ld\n", OFFSET(switch_stack_ar_pfs)); fprintf(fp, " switch_stack_ar_rnat: %ld\n", OFFSET(switch_stack_ar_rnat)); fprintf(fp, " switch_stack_pr: %ld\n", OFFSET(switch_stack_pr)); fprintf(fp, " cpuinfo_ia64_proc_freq: %ld\n", OFFSET(cpuinfo_ia64_proc_freq)); fprintf(fp, " cpuinfo_ia64_unimpl_va_mask: %ld\n", OFFSET(cpuinfo_ia64_unimpl_va_mask)); fprintf(fp, " cpuinfo_ia64_unimpl_pa_mask: %ld\n", OFFSET(cpuinfo_ia64_unimpl_pa_mask)); fprintf(fp, " device_node_type: %ld\n", OFFSET(device_node_type)); fprintf(fp, " device_node_allnext: %ld\n", OFFSET(device_node_allnext)); fprintf(fp, " device_node_properties: %ld\n", OFFSET(device_node_properties)); fprintf(fp, " property_name: %ld\n", OFFSET(property_name)); fprintf(fp, " property_value: %ld\n", OFFSET(property_value)); fprintf(fp, " property_next: %ld\n", OFFSET(property_next)); fprintf(fp, " machdep_calls_setup_residual: %ld\n", OFFSET(machdep_calls_setup_residual)); fprintf(fp, " RESIDUAL_VitalProductData: %ld\n", OFFSET(RESIDUAL_VitalProductData)); fprintf(fp, " VPD_ProcessorHz: %ld\n", OFFSET(VPD_ProcessorHz)); fprintf(fp, " bd_info_bi_intfreq: %ld\n", OFFSET(bd_info_bi_intfreq)); fprintf(fp, " hwrpb_struct_cycle_freq: %ld\n", OFFSET(hwrpb_struct_cycle_freq)); fprintf(fp, " hwrpb_struct_processor_offset: %ld\n", OFFSET(hwrpb_struct_processor_offset)); fprintf(fp, " hwrpb_struct_processor_size: %ld\n", OFFSET(hwrpb_struct_processor_size)); fprintf(fp, " percpu_struct_halt_PC: %ld\n", OFFSET(percpu_struct_halt_PC)); fprintf(fp, " percpu_struct_halt_ra: %ld\n", OFFSET(percpu_struct_halt_ra)); fprintf(fp, " percpu_struct_halt_pv: %ld\n", OFFSET(percpu_struct_halt_pv)); fprintf(fp, " mm_struct_mmap: %ld\n", OFFSET(mm_struct_mmap)); fprintf(fp, " mm_struct_pgd: %ld\n", OFFSET(mm_struct_pgd)); fprintf(fp, " mm_struct_rss: %ld\n", OFFSET(mm_struct_rss)); fprintf(fp, " mm_struct_anon_rss: %ld\n", OFFSET(mm_struct_anon_rss)); fprintf(fp, " mm_struct_file_rss: %ld\n", OFFSET(mm_struct_file_rss)); fprintf(fp, " mm_struct_total_vm: %ld\n", OFFSET(mm_struct_total_vm)); fprintf(fp, " mm_struct_start_code: %ld\n", OFFSET(mm_struct_start_code)); fprintf(fp, " mm_struct_arg_start: %ld\n", OFFSET(mm_struct_arg_start)); fprintf(fp, " mm_struct_arg_end: %ld\n", OFFSET(mm_struct_arg_end)); fprintf(fp, " mm_struct_env_start: %ld\n", OFFSET(mm_struct_env_start)); fprintf(fp, " mm_struct_env_end: %ld\n", OFFSET(mm_struct_env_end)); fprintf(fp, " mm_struct_rss_stat: %ld\n", OFFSET(mm_struct_rss_stat)); fprintf(fp, " mm_rss_stat_count: %ld\n", OFFSET(mm_rss_stat_count)); fprintf(fp, " vm_area_struct_vm_mm: %ld\n", OFFSET(vm_area_struct_vm_mm)); fprintf(fp, " vm_area_struct_vm_next: %ld\n", OFFSET(vm_area_struct_vm_next)); fprintf(fp, " vm_area_struct_vm_start: %ld\n", OFFSET(vm_area_struct_vm_start)); fprintf(fp, " vm_area_struct_vm_end: %ld\n", OFFSET(vm_area_struct_vm_end)); fprintf(fp, " vm_area_struct_vm_flags: %ld\n", OFFSET(vm_area_struct_vm_flags)); fprintf(fp, " vm_area_struct_vm_file: %ld\n", OFFSET(vm_area_struct_vm_file)); fprintf(fp, " vm_area_struct_vm_offset: %ld\n", OFFSET(vm_area_struct_vm_offset)); fprintf(fp, " vm_area_struct_vm_pgoff: %ld\n", OFFSET(vm_area_struct_vm_pgoff)); fprintf(fp, " vm_struct_addr: %ld\n", OFFSET(vm_struct_addr)); fprintf(fp, " vm_struct_size: %ld\n", OFFSET(vm_struct_size)); fprintf(fp, " vm_struct_next: %ld\n", OFFSET(vm_struct_next)); fprintf(fp, " vmap_area_va_start: %ld\n", OFFSET(vmap_area_va_start)); fprintf(fp, " vmap_area_va_end: %ld\n", OFFSET(vmap_area_va_end)); fprintf(fp, " vmap_area_list: %ld\n", OFFSET(vmap_area_list)); fprintf(fp, " vmap_area_vm: %ld\n", OFFSET(vmap_area_vm)); fprintf(fp, " vmap_area_flags: %ld\n", OFFSET(vmap_area_flags)); fprintf(fp, " module_size_of_struct: %ld\n", OFFSET(module_size_of_struct)); fprintf(fp, " module_next: %ld\n", OFFSET(module_next)); fprintf(fp, " module_name: %ld\n", OFFSET(module_name)); fprintf(fp, " module_syms: %ld\n", OFFSET(module_syms)); fprintf(fp, " module_nsyms: %ld\n", OFFSET(module_nsyms)); fprintf(fp, " module_size: %ld\n", OFFSET(module_size)); fprintf(fp, " module_flags: %ld\n", OFFSET(module_flags)); fprintf(fp, " module_num_syms: %ld\n", OFFSET(module_num_syms)); fprintf(fp, " module_gpl_syms: %ld\n", OFFSET(module_gpl_syms)); fprintf(fp, " module_num_gpl_syms: %ld\n", OFFSET(module_num_gpl_syms)); fprintf(fp, " module_list: %ld\n", OFFSET(module_list)); fprintf(fp, " module_module_core: %ld\n", OFFSET(module_module_core)); fprintf(fp, " module_core_size: %ld\n", OFFSET(module_core_size)); fprintf(fp, " module_core_text_size: %ld\n", OFFSET(module_core_text_size)); fprintf(fp, " module_init_size: %ld\n", OFFSET(module_init_size)); fprintf(fp, " module_init_text_size: %ld\n", OFFSET(module_init_text_size)); fprintf(fp, " module_module_init: %ld\n", OFFSET(module_module_init)); fprintf(fp, " module_num_symtab: %ld\n", OFFSET(module_num_symtab)); fprintf(fp, " module_symtab: %ld\n", OFFSET(module_symtab)); fprintf(fp, " module_strtab: %ld\n", OFFSET(module_strtab)); fprintf(fp, " module_percpu: %ld\n", OFFSET(module_percpu)); fprintf(fp, " module_sect_attrs: %ld\n", OFFSET(module_sect_attrs)); fprintf(fp, " module_sect_attrs_attrs: %ld\n", OFFSET(module_sect_attrs_attrs)); fprintf(fp, " module_sect_attrs_nsections: %ld\n", OFFSET(module_sect_attrs_nsections)); fprintf(fp, " module_sect_attr_mattr: %ld\n", OFFSET(module_sect_attr_mattr)); fprintf(fp, " module_sect_attr_name: %ld\n", OFFSET(module_sect_attr_name)); fprintf(fp, " module_sect_attr_address: %ld\n", OFFSET(module_sect_attr_address)); fprintf(fp, " attribute_owner: %ld\n", OFFSET(attribute_owner)); fprintf(fp, " module_sect_attr_attr: %ld\n", OFFSET(module_sect_attr_attr)); fprintf(fp, " module_sections_attrs: %ld\n", OFFSET(module_sections_attrs)); fprintf(fp, " module_attribute_attr: %ld\n", OFFSET(module_attribute_attr)); fprintf(fp, " module_kallsyms_start: %ld\n", OFFSET(module_kallsyms_start)); fprintf(fp, " kallsyms_header_sections: %ld\n", OFFSET(kallsyms_header_sections)); fprintf(fp, " kallsyms_header_section_off: %ld\n", OFFSET(kallsyms_header_section_off)); fprintf(fp, " kallsyms_header_symbols: %ld\n", OFFSET(kallsyms_header_symbols)); fprintf(fp, " kallsyms_header_symbol_off: %ld\n", OFFSET(kallsyms_header_symbol_off)); fprintf(fp, " kallsyms_header_string_off: %ld\n", OFFSET(kallsyms_header_string_off)); fprintf(fp, " kallsyms_symbol_section_off: %ld\n", OFFSET(kallsyms_symbol_section_off)); fprintf(fp, " kallsyms_symbol_symbol_addr: %ld\n", OFFSET(kallsyms_symbol_symbol_addr)); fprintf(fp, " kallsyms_symbol_name_off: %ld\n", OFFSET(kallsyms_symbol_name_off)); fprintf(fp, " kallsyms_section_start: %ld\n", OFFSET(kallsyms_section_start)); fprintf(fp, " kallsyms_section_size: %ld\n", OFFSET(kallsyms_section_size)); fprintf(fp, " kallsyms_section_name_off: %ld\n", OFFSET(kallsyms_section_name_off)); fprintf(fp, " page_next: %ld\n", OFFSET(page_next)); fprintf(fp, " page_prev: %ld\n", OFFSET(page_prev)); fprintf(fp, " page_next_hash: %ld\n", OFFSET(page_next_hash)); fprintf(fp, " page_list: %ld\n", OFFSET(page_list)); fprintf(fp, " page_list_next: %ld\n", OFFSET(page_list_next)); fprintf(fp, " page_list_prev: %ld\n", OFFSET(page_list_prev)); fprintf(fp, " page_inode: %ld\n", OFFSET(page_inode)); fprintf(fp, " page_offset: %ld\n", OFFSET(page_offset)); fprintf(fp, " page_count: %ld\n", OFFSET(page_count)); fprintf(fp, " page_flags: %ld\n", OFFSET(page_flags)); fprintf(fp, " page_mapping: %ld\n", OFFSET(page_mapping)); fprintf(fp, " page_index: %ld\n", OFFSET(page_index)); fprintf(fp, " page_buffers: %ld\n", OFFSET(page_buffers)); fprintf(fp, " page_lru: %ld\n", OFFSET(page_lru)); fprintf(fp, " page_pte: %ld\n", OFFSET(page_pte)); fprintf(fp, " page_inuse: %ld\n", OFFSET(page_inuse)); fprintf(fp, " page_objects: %ld\n", OFFSET(page_objects)); fprintf(fp, " page_slab: %ld\n", OFFSET(page_slab)); fprintf(fp, " page_first_page: %ld\n", OFFSET(page_first_page)); fprintf(fp, " page_freelist: %ld\n", OFFSET(page_freelist)); fprintf(fp, " swap_info_struct_swap_file: %ld\n", OFFSET(swap_info_struct_swap_file)); fprintf(fp, " swap_info_struct_swap_vfsmnt: %ld\n", OFFSET(swap_info_struct_swap_vfsmnt)); fprintf(fp, " swap_info_struct_flags: %ld\n", OFFSET(swap_info_struct_flags)); fprintf(fp, " swap_info_struct_swap_map: %ld\n", OFFSET(swap_info_struct_swap_map)); fprintf(fp, " swap_info_struct_swap_device: %ld\n", OFFSET(swap_info_struct_swap_device)); fprintf(fp, " swap_info_struct_prio: %ld\n", OFFSET(swap_info_struct_prio)); fprintf(fp, " swap_info_struct_max: %ld\n", OFFSET(swap_info_struct_max)); fprintf(fp, " swap_info_struct_pages: %ld\n", OFFSET(swap_info_struct_pages)); fprintf(fp, " swap_info_struct_inuse_pages: %ld\n", OFFSET(swap_info_struct_inuse_pages)); fprintf(fp, "swap_info_struct_old_block_size: %ld\n", OFFSET(swap_info_struct_old_block_size)); fprintf(fp, " block_device_bd_inode: %ld\n", OFFSET(block_device_bd_inode)); fprintf(fp, " block_device_bd_list: %ld\n", OFFSET(block_device_bd_list)); fprintf(fp, " block_device_bd_disk: %ld\n", OFFSET(block_device_bd_disk)); fprintf(fp, " address_space_nrpages: %ld\n", OFFSET(address_space_nrpages)); fprintf(fp, " gendisk_major: %ld\n", OFFSET(gendisk_major)); fprintf(fp, " gendisk_fops: %ld\n", OFFSET(gendisk_fops)); fprintf(fp, " gendisk_disk_name: %ld\n", OFFSET(gendisk_disk_name)); fprintf(fp, " irq_desc_t_status: %ld\n", OFFSET(irq_desc_t_status)); fprintf(fp, " irq_desc_t_handler: %ld\n", OFFSET(irq_desc_t_handler)); fprintf(fp, " irq_desc_t_chip: %ld\n", OFFSET(irq_desc_t_chip)); fprintf(fp, " irq_desc_t_action: %ld\n", OFFSET(irq_desc_t_action)); fprintf(fp, " irq_desc_t_depth: %ld\n", OFFSET(irq_desc_t_depth)); fprintf(fp, " irqdesc_action: %ld\n", OFFSET(irqdesc_action)); fprintf(fp, " irqdesc_ctl: %ld\n", OFFSET(irqdesc_ctl)); fprintf(fp, " irqdesc_level: %ld\n", OFFSET(irqdesc_level)); fprintf(fp, " irq_desc_t_irq_data: %ld\n", OFFSET(irq_desc_t_irq_data)); fprintf(fp, " irq_desc_t_kstat_irqs: %ld\n", OFFSET(irq_desc_t_kstat_irqs)); fprintf(fp, " irq_desc_t_affinity: %ld\n", OFFSET(irq_desc_t_affinity)); fprintf(fp, " irq_data_chip: %ld\n", OFFSET(irq_data_chip)); fprintf(fp, " irq_data_affinity: %ld\n", OFFSET(irq_data_affinity)); fprintf(fp, " kernel_stat_irqs: %ld\n", OFFSET(kernel_stat_irqs)); fprintf(fp, " irqaction_handler: %ld\n", OFFSET(irqaction_handler)); fprintf(fp, " irqaction_flags: %ld\n", OFFSET(irqaction_flags)); fprintf(fp, " irqaction_mask: %ld\n", OFFSET(irqaction_mask)); fprintf(fp, " irqaction_name: %ld\n", OFFSET(irqaction_name)); fprintf(fp, " irqaction_dev_id: %ld\n", OFFSET(irqaction_dev_id)); fprintf(fp, " irqaction_next: %ld\n", OFFSET(irqaction_next)); fprintf(fp, " hw_interrupt_type_typename: %ld\n", OFFSET(hw_interrupt_type_typename)); fprintf(fp, " hw_interrupt_type_startup: %ld\n", OFFSET(hw_interrupt_type_startup)); fprintf(fp, " hw_interrupt_type_shutdown: %ld\n", OFFSET(hw_interrupt_type_shutdown)); fprintf(fp, " hw_interrupt_type_handle: %ld\n", OFFSET(hw_interrupt_type_handle)); fprintf(fp, " hw_interrupt_type_enable: %ld\n", OFFSET(hw_interrupt_type_enable)); fprintf(fp, " hw_interrupt_type_disable: %ld\n", OFFSET(hw_interrupt_type_disable)); fprintf(fp, " hw_interrupt_type_ack: %ld\n", OFFSET(hw_interrupt_type_ack)); fprintf(fp, " hw_interrupt_type_end: %ld\n", OFFSET(hw_interrupt_type_end)); fprintf(fp, "hw_interrupt_type_set_affinity: %ld\n", OFFSET(hw_interrupt_type_set_affinity)); fprintf(fp, " irq_chip_typename: %ld\n", OFFSET(irq_chip_typename)); fprintf(fp, " irq_chip_startup: %ld\n", OFFSET(irq_chip_startup)); fprintf(fp, " irq_chip_shutdown: %ld\n", OFFSET(irq_chip_shutdown)); fprintf(fp, " irq_chip_enable: %ld\n", OFFSET(irq_chip_enable)); fprintf(fp, " irq_chip_disable: %ld\n", OFFSET(irq_chip_disable)); fprintf(fp, " irq_chip_ack: %ld\n", OFFSET(irq_chip_ack)); fprintf(fp, " irq_chip_mask: %ld\n", OFFSET(irq_chip_mask)); fprintf(fp, " irq_chip_mask_ack: %ld\n", OFFSET(irq_chip_mask_ack)); fprintf(fp, " irq_chip_unmask: %ld\n", OFFSET(irq_chip_unmask)); fprintf(fp, " irq_chip_eoi: %ld\n", OFFSET(irq_chip_eoi)); fprintf(fp, " irq_chip_end: %ld\n", OFFSET(irq_chip_end)); fprintf(fp, " irq_chip_set_affinity: %ld\n", OFFSET(irq_chip_set_affinity)); fprintf(fp, " irq_chip_retrigger: %ld\n", OFFSET(irq_chip_retrigger)); fprintf(fp, " irq_chip_set_type: %ld\n", OFFSET(irq_chip_set_type)); fprintf(fp, " irq_chip_set_wake: %ld\n", OFFSET(irq_chip_set_wake)); fprintf(fp, "irq_cpustat_t___softirq_active: %ld\n", OFFSET(irq_cpustat_t___softirq_active)); fprintf(fp, " irq_cpustat_t___softirq_mask: %ld\n", OFFSET(irq_cpustat_t___softirq_mask)); fprintf(fp, " files_struct_fdt: %ld\n", OFFSET(files_struct_fdt)); fprintf(fp, " fdtable_max_fds: %ld\n", OFFSET(fdtable_max_fds)); fprintf(fp, " fdtable_max_fdset: %ld\n", OFFSET(fdtable_max_fdset)); fprintf(fp, " fdtable_open_fds: %ld\n", OFFSET(fdtable_open_fds)); fprintf(fp, " fdtable_fd: %ld\n", OFFSET(fdtable_fd)); fprintf(fp, " files_struct_max_fds: %ld\n", OFFSET(files_struct_max_fds)); fprintf(fp, " files_struct_max_fdset: %ld\n", OFFSET(files_struct_max_fdset)); fprintf(fp, " files_struct_open_fds: %ld\n", OFFSET(files_struct_open_fds)); fprintf(fp, " files_struct_fd: %ld\n", OFFSET(files_struct_fd)); fprintf(fp, " files_struct_open_fds_init: %ld\n", OFFSET(files_struct_open_fds_init)); fprintf(fp, " file_f_dentry: %ld\n", OFFSET(file_f_dentry)); fprintf(fp, " file_f_vfsmnt: %ld\n", OFFSET(file_f_vfsmnt)); fprintf(fp, " file_f_count: %ld\n", OFFSET(file_f_count)); fprintf(fp, " file_f_path: %ld\n", OFFSET(file_f_path)); fprintf(fp, " path_mnt: %ld\n", OFFSET(path_mnt)); fprintf(fp, " path_dentry: %ld\n", OFFSET(path_dentry)); fprintf(fp, " fs_struct_root: %ld\n", OFFSET(fs_struct_root)); fprintf(fp, " fs_struct_pwd: %ld\n", OFFSET(fs_struct_pwd)); fprintf(fp, " fs_struct_rootmnt: %ld\n", OFFSET(fs_struct_rootmnt)); fprintf(fp, " fs_struct_pwdmnt: %ld\n", OFFSET(fs_struct_pwdmnt)); fprintf(fp, " dentry_d_inode: %ld\n", OFFSET(dentry_d_inode)); fprintf(fp, " dentry_d_parent: %ld\n", OFFSET(dentry_d_parent)); fprintf(fp, " dentry_d_name: %ld\n", OFFSET(dentry_d_name)); fprintf(fp, " dentry_d_iname: %ld\n", OFFSET(dentry_d_iname)); fprintf(fp, " dentry_d_covers: %ld\n", OFFSET(dentry_d_covers)); fprintf(fp, " qstr_len: %ld\n", OFFSET(qstr_len)); fprintf(fp, " qstr_name: %ld\n", OFFSET(qstr_name)); fprintf(fp, " inode_i_mode: %ld\n", OFFSET(inode_i_mode)); fprintf(fp, " inode_i_op: %ld\n", OFFSET(inode_i_op)); fprintf(fp, " inode_i_sb: %ld\n", OFFSET(inode_i_sb)); fprintf(fp, " inode_u: %ld\n", OFFSET(inode_u)); fprintf(fp, " inode_i_flock: %ld\n", OFFSET(inode_i_flock)); fprintf(fp, " inode_i_fop: %ld\n", OFFSET(inode_i_fop)); fprintf(fp, " inode_i_mapping: %ld\n", OFFSET(inode_i_mapping)); fprintf(fp, " vfsmount_mnt_next: %ld\n", OFFSET(vfsmount_mnt_next)); fprintf(fp, " vfsmount_mnt_devname: %ld\n", OFFSET(vfsmount_mnt_devname)); fprintf(fp, " vfsmount_mnt_dirname: %ld\n", OFFSET(vfsmount_mnt_dirname)); fprintf(fp, " vfsmount_mnt_sb: %ld\n", OFFSET(vfsmount_mnt_sb)); fprintf(fp, " vfsmount_mnt_list: %ld\n", OFFSET(vfsmount_mnt_list)); fprintf(fp, " vfsmount_mnt_mountpoint: %ld\n", OFFSET(vfsmount_mnt_mountpoint)); fprintf(fp, " vfsmount_mnt_parent: %ld\n", OFFSET(vfsmount_mnt_parent)); fprintf(fp, " mount_mnt_parent: %ld\n", OFFSET(mount_mnt_parent)); fprintf(fp, " mount_mnt_mountpoint: %ld\n", OFFSET(mount_mnt_mountpoint)); fprintf(fp, " mount_mnt_list: %ld\n", OFFSET(mount_mnt_list)); fprintf(fp, " mount_mnt_devname: %ld\n", OFFSET(mount_mnt_devname)); fprintf(fp, " mount_mnt: %ld\n", OFFSET(mount_mnt)); fprintf(fp, " namespace_root: %ld\n", OFFSET(namespace_root)); fprintf(fp, " namespace_list: %ld\n", OFFSET(namespace_list)); fprintf(fp, " super_block_s_dirty: %ld\n", OFFSET(super_block_s_dirty)); fprintf(fp, " super_block_s_type: %ld\n", OFFSET(super_block_s_type)); fprintf(fp, " super_block_s_files: %ld\n", OFFSET(super_block_s_files)); fprintf(fp, " nlm_file_f_file: %ld\n", OFFSET(nlm_file_f_file)); fprintf(fp, " file_system_type_name: %ld\n", OFFSET(file_system_type_name)); fprintf(fp, " file_lock_fl_owner: %ld\n", OFFSET(file_lock_fl_owner)); fprintf(fp, " nlm_host_h_exportent: %ld\n", OFFSET(nlm_host_h_exportent)); fprintf(fp, " svc_client_cl_ident: %ld\n", OFFSET(svc_client_cl_ident)); fprintf(fp, " kmem_cache_s_c_nextp: %ld\n", OFFSET(kmem_cache_s_c_nextp)); fprintf(fp, " kmem_cache_s_c_name: %ld\n", OFFSET(kmem_cache_s_c_name)); fprintf(fp, " kmem_cache_s_c_num: %ld\n", OFFSET(kmem_cache_s_c_num)); fprintf(fp, " kmem_cache_s_c_org_size: %ld\n", OFFSET(kmem_cache_s_c_org_size)); fprintf(fp, " kmem_cache_s_c_flags: %ld\n", OFFSET(kmem_cache_s_c_flags)); fprintf(fp, " kmem_cache_s_c_offset: %ld\n", OFFSET(kmem_cache_s_c_offset)); fprintf(fp, " kmem_cache_s_c_firstp: %ld\n", OFFSET(kmem_cache_s_c_firstp)); fprintf(fp, " kmem_cache_s_c_gfporder: %ld\n", OFFSET(kmem_cache_s_c_gfporder)); fprintf(fp, " kmem_cache_s_c_magic: %ld\n", OFFSET(kmem_cache_s_c_magic)); fprintf(fp, " kmem_cache_s_c_align: %ld\n", OFFSET(kmem_cache_s_c_align)); fprintf(fp, " kmem_cache_s_num: %ld\n", OFFSET(kmem_cache_s_num)); fprintf(fp, " kmem_cache_s_next: %ld\n", OFFSET(kmem_cache_s_next)); fprintf(fp, " kmem_cache_s_name: %ld\n", OFFSET(kmem_cache_s_name)); fprintf(fp, " kmem_cache_s_objsize: %ld\n", OFFSET(kmem_cache_s_objsize)); fprintf(fp, " kmem_cache_s_flags: %ld\n", OFFSET(kmem_cache_s_flags)); fprintf(fp, " kmem_cache_s_gfporder: %ld\n", OFFSET(kmem_cache_s_gfporder)); fprintf(fp, " kmem_cache_s_slabs: %ld\n", OFFSET(kmem_cache_s_slabs)); fprintf(fp, " kmem_cache_s_slabs_full: %ld\n", OFFSET(kmem_cache_s_slabs_full)); fprintf(fp, " kmem_cache_s_slabs_partial: %ld\n", OFFSET(kmem_cache_s_slabs_partial)); fprintf(fp, " kmem_cache_s_slabs_free: %ld\n", OFFSET(kmem_cache_s_slabs_free)); fprintf(fp, " kmem_cache_s_cpudata: %ld\n", OFFSET(kmem_cache_s_cpudata)); fprintf(fp, " kmem_cache_s_colour_off: %ld\n", OFFSET(kmem_cache_s_colour_off)); fprintf(fp, " cpucache_s_avail: %ld\n", OFFSET(cpucache_s_avail)); fprintf(fp, " cpucache_s_limit: %ld\n", OFFSET(cpucache_s_limit)); fprintf(fp, " array_cache_avail: %ld\n", OFFSET(array_cache_avail)); fprintf(fp, " array_cache_limit: %ld\n", OFFSET(array_cache_limit)); fprintf(fp, " kmem_cache_s_array: %ld\n", OFFSET(kmem_cache_s_array)); fprintf(fp, " kmem_cache_s_lists: %ld\n", OFFSET(kmem_cache_s_lists)); fprintf(fp, " kmem_list3_slabs_partial: %ld\n", OFFSET(kmem_list3_slabs_partial)); fprintf(fp, " kmem_list3_slabs_full: %ld\n", OFFSET(kmem_list3_slabs_full)); fprintf(fp, " kmem_list3_slabs_free: %ld\n", OFFSET(kmem_list3_slabs_free)); fprintf(fp, " kmem_list3_free_objects: %ld\n", OFFSET(kmem_list3_free_objects)); fprintf(fp, " kmem_list3_shared: %ld\n", OFFSET(kmem_list3_shared)); fprintf(fp, " kmem_slab_s_s_nextp: %ld\n", OFFSET(kmem_slab_s_s_nextp)); fprintf(fp, " kmem_slab_s_s_freep: %ld\n", OFFSET(kmem_slab_s_s_freep)); fprintf(fp, " kmem_slab_s_s_inuse: %ld\n", OFFSET(kmem_slab_s_s_inuse)); fprintf(fp, " kmem_slab_s_s_mem: %ld\n", OFFSET(kmem_slab_s_s_mem)); fprintf(fp, " kmem_slab_s_s_index: %ld\n", OFFSET(kmem_slab_s_s_index)); fprintf(fp, " kmem_slab_s_s_offset: %ld\n", OFFSET(kmem_slab_s_s_offset)); fprintf(fp, " kmem_slab_s_s_magic: %ld\n", OFFSET(kmem_slab_s_s_magic)); fprintf(fp, " slab_s_list: %ld\n", OFFSET(slab_s_list)); fprintf(fp, " slab_s_s_mem: %ld\n", OFFSET(slab_s_s_mem)); fprintf(fp, " slab_s_inuse: %ld\n", OFFSET(slab_s_inuse)); fprintf(fp, " slab_s_free: %ld\n", OFFSET(slab_s_free)); fprintf(fp, " slab_list: %ld\n", OFFSET(slab_list)); fprintf(fp, " slab_s_mem: %ld\n", OFFSET(slab_s_mem)); fprintf(fp, " slab_inuse: %ld\n", OFFSET(slab_inuse)); fprintf(fp, " slab_free: %ld\n", OFFSET(slab_free)); fprintf(fp, " kmem_cache_size: %ld\n", OFFSET(kmem_cache_size)); fprintf(fp, " kmem_cache_objsize: %ld\n", OFFSET(kmem_cache_objsize)); fprintf(fp, " kmem_cache_offset: %ld\n", OFFSET(kmem_cache_offset)); fprintf(fp, " kmem_cache_order: %ld\n", OFFSET(kmem_cache_order)); fprintf(fp, " kmem_cache_local_node: %ld\n", OFFSET(kmem_cache_local_node)); fprintf(fp, " kmem_cache_objects: %ld\n", OFFSET(kmem_cache_objects)); fprintf(fp, " kmem_cache_inuse: %ld\n", OFFSET(kmem_cache_inuse)); fprintf(fp, " kmem_cache_align: %ld\n", OFFSET(kmem_cache_align)); fprintf(fp, " kmem_cache_name: %ld\n", OFFSET(kmem_cache_name)); fprintf(fp, " kmem_cache_list: %ld\n", OFFSET(kmem_cache_list)); fprintf(fp, " kmem_cache_node: %ld\n", OFFSET(kmem_cache_node)); fprintf(fp, " kmem_cache_cpu_slab: %ld\n", OFFSET(kmem_cache_cpu_slab)); fprintf(fp, " kmem_cache_oo: %ld\n", OFFSET(kmem_cache_oo)); fprintf(fp, " kmem_cache_node_nr_partial: %ld\n", OFFSET(kmem_cache_node_nr_partial)); fprintf(fp, " kmem_cache_node_nr_slabs: %ld\n", OFFSET(kmem_cache_node_nr_slabs)); fprintf(fp, " kmem_cache_node_partial: %ld\n", OFFSET(kmem_cache_node_partial)); fprintf(fp, " kmem_cache_node_full: %ld\n", OFFSET(kmem_cache_node_full)); fprintf(fp, " kmem_cache_cpu_freelist: %ld\n", OFFSET(kmem_cache_cpu_freelist)); fprintf(fp, " kmem_cache_cpu_page: %ld\n", OFFSET(kmem_cache_cpu_page)); fprintf(fp, " kmem_cache_cpu_node: %ld\n", OFFSET(kmem_cache_cpu_node)); fprintf(fp, " kmem_cache_flags: %ld\n", OFFSET(kmem_cache_flags)); fprintf(fp, " net_device_next: %ld\n", OFFSET(net_device_next)); fprintf(fp, " net_device_name: %ld\n", OFFSET(net_device_name)); fprintf(fp, " net_device_type: %ld\n", OFFSET(net_device_type)); fprintf(fp, " net_device_addr_len: %ld\n", OFFSET(net_device_addr_len)); fprintf(fp, " net_device_ip_ptr: %ld\n", OFFSET(net_device_ip_ptr)); fprintf(fp, " net_device_dev_list: %ld\n", OFFSET(net_device_dev_list)); fprintf(fp, " net_dev_base_head: %ld\n", OFFSET(net_dev_base_head)); fprintf(fp, " device_next: %ld\n", OFFSET(device_next)); fprintf(fp, " device_name: %ld\n", OFFSET(device_name)); fprintf(fp, " device_type: %ld\n", OFFSET(device_type)); fprintf(fp, " device_ip_ptr: %ld\n", OFFSET(device_ip_ptr)); fprintf(fp, " device_addr_len: %ld\n", OFFSET(device_addr_len)); fprintf(fp, " socket_sk: %ld\n", OFFSET(socket_sk)); fprintf(fp, " sock_daddr: %ld\n", OFFSET(sock_daddr)); fprintf(fp, " sock_rcv_saddr: %ld\n", OFFSET(sock_rcv_saddr)); fprintf(fp, " sock_dport: %ld\n", OFFSET(sock_dport)); fprintf(fp, " sock_sport: %ld\n", OFFSET(sock_sport)); fprintf(fp, " sock_num: %ld\n", OFFSET(sock_num)); fprintf(fp, " sock_family: %ld\n", OFFSET(sock_family)); fprintf(fp, " sock_type: %ld\n", OFFSET(sock_type)); fprintf(fp, " sock_sk_type: %ld\n", OFFSET(sock_sk_type)); fprintf(fp, " sock_common_skc_family: %ld\n", OFFSET(sock_common_skc_family)); fprintf(fp, " socket_alloc_vfs_inode: %ld\n", OFFSET(socket_alloc_vfs_inode)); fprintf(fp, " inet_sock_inet: %ld\n", OFFSET(inet_sock_inet)); fprintf(fp, " inet_opt_daddr: %ld\n", OFFSET(inet_opt_daddr)); fprintf(fp, " inet_opt_rcv_saddr: %ld\n", OFFSET(inet_opt_rcv_saddr)); fprintf(fp, " inet_opt_dport: %ld\n", OFFSET(inet_opt_dport)); fprintf(fp, " inet_opt_sport: %ld\n", OFFSET(inet_opt_sport)); fprintf(fp, " inet_opt_num: %ld\n", OFFSET(inet_opt_num)); fprintf(fp, " ipv6_pinfo_rcv_saddr: %ld\n", OFFSET(ipv6_pinfo_rcv_saddr)); fprintf(fp, " ipv6_pinfo_daddr: %ld\n", OFFSET(ipv6_pinfo_daddr)); fprintf(fp, " timer_list_list: %ld\n", OFFSET(timer_list_list)); fprintf(fp, " timer_list_next: %ld\n", OFFSET(timer_list_next)); fprintf(fp, " timer_list_entry: %ld\n", OFFSET(timer_list_entry)); fprintf(fp, " timer_list_expires: %ld\n", OFFSET(timer_list_expires)); fprintf(fp, " timer_list_function: %ld\n", OFFSET(timer_list_function)); fprintf(fp, " timer_vec_root_vec: %ld\n", OFFSET(timer_vec_root_vec)); fprintf(fp, " timer_vec_vec: %ld\n", OFFSET(timer_vec_vec)); fprintf(fp, " tvec_root_s_vec: %ld\n", OFFSET(tvec_root_s_vec)); fprintf(fp, " tvec_s_vec: %ld\n", OFFSET(tvec_s_vec)); fprintf(fp, " tvec_t_base_s_tv1: %ld\n", OFFSET(tvec_t_base_s_tv1)); fprintf(fp, " wait_queue_task: %ld\n", OFFSET(wait_queue_task)); fprintf(fp, " wait_queue_next: %ld\n", OFFSET(wait_queue_next)); fprintf(fp, " __wait_queue_task: %ld\n", OFFSET(__wait_queue_task)); fprintf(fp, " __wait_queue_head_task_list: %ld\n", OFFSET(__wait_queue_head_task_list)); fprintf(fp, " __wait_queue_task_list: %ld\n", OFFSET(__wait_queue_task_list)); fprintf(fp, " pglist_data_node_zones: %ld\n", OFFSET(pglist_data_node_zones)); fprintf(fp, " pglist_data_node_mem_map: %ld\n", OFFSET(pglist_data_node_mem_map)); fprintf(fp, " pglist_data_node_start_paddr: %ld\n", OFFSET(pglist_data_node_start_paddr)); fprintf(fp, " pglist_data_node_start_mapnr: %ld\n", OFFSET(pglist_data_node_start_mapnr)); fprintf(fp, " pglist_data_node_size: %ld\n", OFFSET(pglist_data_node_size)); fprintf(fp, " pglist_data_node_id: %ld\n", OFFSET(pglist_data_node_id)); fprintf(fp, " pglist_data_node_next: %ld\n", OFFSET(pglist_data_node_next)); fprintf(fp, " pglist_data_bdata: %ld\n", OFFSET(pglist_data_bdata)); fprintf(fp, " pglist_data_nr_zones: %ld\n", OFFSET(pglist_data_nr_zones)); fprintf(fp, " pglist_data_node_start_pfn: %ld\n", OFFSET(pglist_data_node_start_pfn)); fprintf(fp, " pglist_data_pgdat_next: %ld\n", OFFSET(pglist_data_pgdat_next)); fprintf(fp, "pglist_data_node_present_pages: %ld\n", OFFSET(pglist_data_node_present_pages)); fprintf(fp, "pglist_data_node_spanned_pages: %ld\n", OFFSET(pglist_data_node_spanned_pages)); fprintf(fp, " page_cache_bucket_chain: %ld\n", OFFSET(page_cache_bucket_chain)); fprintf(fp, " zone_struct_free_pages: %ld\n", OFFSET(zone_struct_free_pages)); fprintf(fp, " zone_struct_free_area: %ld\n", OFFSET(zone_struct_free_area)); fprintf(fp, " zone_struct_zone_pgdat: %ld\n", OFFSET(zone_struct_zone_pgdat)); fprintf(fp, " zone_struct_name: %ld\n", OFFSET(zone_struct_name)); fprintf(fp, " zone_struct_size: %ld\n", OFFSET(zone_struct_size)); fprintf(fp, " zone_struct_memsize: %ld\n", OFFSET(zone_struct_memsize)); fprintf(fp, " zone_struct_zone_start_pfn: %ld\n", OFFSET(zone_struct_zone_start_pfn)); fprintf(fp, " zone_struct_zone_start_paddr: %ld\n", OFFSET(zone_struct_zone_start_paddr)); fprintf(fp, " zone_struct_zone_start_mapnr: %ld\n", OFFSET(zone_struct_zone_start_mapnr)); fprintf(fp, " zone_struct_zone_mem_map: %ld\n", OFFSET(zone_struct_zone_mem_map)); fprintf(fp, "zone_struct_inactive_clean_pages: %ld\n", OFFSET(zone_struct_inactive_clean_pages)); fprintf(fp, "zone_struct_inactive_clean_list: %ld\n", OFFSET(zone_struct_inactive_clean_list)); fprintf(fp, "zone_struct_inactive_dirty_pages: %ld\n", OFFSET(zone_struct_inactive_dirty_pages)); fprintf(fp, " zone_struct_active_pages: %ld\n", OFFSET(zone_struct_active_pages)); fprintf(fp, " zone_struct_pages_min: %ld\n", OFFSET(zone_struct_pages_min)); fprintf(fp, " zone_struct_pages_low: %ld\n", OFFSET(zone_struct_pages_low)); fprintf(fp, " zone_struct_pages_high: %ld\n", OFFSET(zone_struct_pages_high)); fprintf(fp, " zone_free_pages: %ld\n", OFFSET(zone_free_pages)); fprintf(fp, " zone_watermark: %ld\n", OFFSET(zone_watermark)); fprintf(fp, " zone_free_area: %ld\n", OFFSET(zone_free_area)); fprintf(fp, " zone_zone_pgdat: %ld\n", OFFSET(zone_zone_pgdat)); fprintf(fp, " zone_zone_mem_map: %ld\n", OFFSET(zone_zone_mem_map)); fprintf(fp, " zone_name: %ld\n", OFFSET(zone_name)); fprintf(fp, " zone_spanned_pages: %ld\n", OFFSET(zone_spanned_pages)); fprintf(fp, " zone_present_pages: %ld\n", OFFSET(zone_present_pages)); fprintf(fp, " zone_zone_start_pfn: %ld\n", OFFSET(zone_zone_start_pfn)); fprintf(fp, " zone_pages_min: %ld\n", OFFSET(zone_pages_min)); fprintf(fp, " zone_pages_low: %ld\n", OFFSET(zone_pages_low)); fprintf(fp, " zone_pages_high: %ld\n", OFFSET(zone_pages_high)); fprintf(fp, " zone_vm_stat: %ld\n", OFFSET(zone_vm_stat)); fprintf(fp, " zone_nr_active: %ld\n", OFFSET(zone_nr_active)); fprintf(fp, " zone_nr_inactive: %ld\n", OFFSET(zone_nr_inactive)); fprintf(fp, " zone_all_unreclaimable: %ld\n", OFFSET(zone_all_unreclaimable)); fprintf(fp, " zone_flags: %ld\n", OFFSET(zone_flags)); fprintf(fp, " zone_pages_scanned: %ld\n", OFFSET(zone_pages_scanned)); fprintf(fp, " neighbour_next: %ld\n", OFFSET(neighbour_next)); fprintf(fp, " neighbour_primary_key: %ld\n", OFFSET(neighbour_primary_key)); fprintf(fp, " neighbour_ha: %ld\n", OFFSET(neighbour_ha)); fprintf(fp, " neighbour_dev: %ld\n", OFFSET(neighbour_dev)); fprintf(fp, " neighbour_nud_state: %ld\n", OFFSET(neighbour_nud_state)); fprintf(fp, " neigh_table_hash_buckets: %ld\n", OFFSET(neigh_table_hash_buckets)); fprintf(fp, " neigh_table_hash_mask: %ld\n", OFFSET(neigh_table_hash_mask)); fprintf(fp, " neigh_table_hash_shift: %ld\n", OFFSET(neigh_table_hash_shift)); fprintf(fp, " neigh_table_nht_ptr: %ld\n", OFFSET(neigh_table_nht_ptr)); fprintf(fp, " neigh_table_key_len: %ld\n", OFFSET(neigh_table_key_len)); fprintf(fp, " in_device_ifa_list: %ld\n", OFFSET(in_device_ifa_list)); fprintf(fp, " in_ifaddr_ifa_next: %ld\n", OFFSET(in_ifaddr_ifa_next)); fprintf(fp, " in_ifaddr_ifa_address: %ld\n", OFFSET(in_ifaddr_ifa_address)); fprintf(fp, " pci_dev_global_list: %ld\n", OFFSET(pci_dev_global_list)); fprintf(fp, " pci_dev_next: %ld\n", OFFSET(pci_dev_next)); fprintf(fp, " pci_dev_bus: %ld\n", OFFSET(pci_dev_bus)); fprintf(fp, " pci_dev_devfn: %ld\n", OFFSET(pci_dev_devfn)); fprintf(fp, " pci_dev_class: %ld\n", OFFSET(pci_dev_class)); fprintf(fp, " pci_dev_device: %ld\n", OFFSET(pci_dev_device)); fprintf(fp, " pci_dev_vendor: %ld\n", OFFSET(pci_dev_vendor)); fprintf(fp, " pci_bus_number: %ld\n", OFFSET(pci_bus_number)); fprintf(fp, " resource_entry_t_from: %ld\n", OFFSET(resource_entry_t_from)); fprintf(fp, " resource_entry_t_num: %ld\n", OFFSET(resource_entry_t_num)); fprintf(fp, " resource_entry_t_name: %ld\n", OFFSET(resource_entry_t_name)); fprintf(fp, " resource_entry_t_next: %ld\n", OFFSET(resource_entry_t_next)); fprintf(fp, " resource_name: %ld\n", OFFSET(resource_name)); fprintf(fp, " resource_start: %ld\n", OFFSET(resource_start)); fprintf(fp, " resource_end: %ld\n", OFFSET(resource_end)); fprintf(fp, " resource_sibling: %ld\n", OFFSET(resource_sibling)); fprintf(fp, " resource_child: %ld\n", OFFSET(resource_child)); fprintf(fp, " runqueue_curr: %ld\n", OFFSET(runqueue_curr)); fprintf(fp, " runqueue_idle: %ld\n", OFFSET(runqueue_idle)); fprintf(fp, " runqueue_active: %ld\n", OFFSET(runqueue_active)); fprintf(fp, " runqueue_expired: %ld\n", OFFSET(runqueue_expired)); fprintf(fp, " runqueue_arrays: %ld\n", OFFSET(runqueue_arrays)); fprintf(fp, " runqueue_cpu: %ld\n", OFFSET(runqueue_cpu)); fprintf(fp, " cpu_s_idle: %ld\n", OFFSET(cpu_s_idle)); fprintf(fp, " cpu_s_curr: %ld\n", OFFSET(cpu_s_curr)); fprintf(fp, " prio_array_queue: %ld\n", OFFSET(prio_array_queue)); fprintf(fp, " rt_prio_array_queue: %ld\n", OFFSET(rt_prio_array_queue)); fprintf(fp, " prio_array_nr_active: %ld\n", OFFSET(prio_array_nr_active)); fprintf(fp, " user_regs_struct_ebp: %ld\n", OFFSET(user_regs_struct_ebp)); fprintf(fp, " user_regs_struct_eip: %ld\n", OFFSET(user_regs_struct_eip)); fprintf(fp, " user_regs_struct_esp: %ld\n", OFFSET(user_regs_struct_esp)); fprintf(fp, " user_regs_struct_rip: %ld\n", OFFSET(user_regs_struct_rip)); fprintf(fp, " user_regs_struct_rsp: %ld\n", OFFSET(user_regs_struct_rsp)); fprintf(fp, " user_regs_struct_eflags: %ld\n", OFFSET(user_regs_struct_eflags)); fprintf(fp, " user_regs_struct_cs: %ld\n", OFFSET(user_regs_struct_cs)); fprintf(fp, " user_regs_struct_ss: %ld\n", OFFSET(user_regs_struct_ss)); fprintf(fp, " user_regs_struct_eip: %ld\n", OFFSET(user_regs_struct_eip)); fprintf(fp, " user_regs_struct_rax: %ld\n", OFFSET(user_regs_struct_rax)); fprintf(fp, " user_regs_struct_eax: %ld\n", OFFSET(user_regs_struct_eax)); fprintf(fp, " user_regs_struct_rbx: %ld\n", OFFSET(user_regs_struct_rbx)); fprintf(fp, " user_regs_struct_ebx: %ld\n", OFFSET(user_regs_struct_ebx)); fprintf(fp, " user_regs_struct_rcx: %ld\n", OFFSET(user_regs_struct_rcx)); fprintf(fp, " user_regs_struct_ecx: %ld\n", OFFSET(user_regs_struct_ecx)); fprintf(fp, " user_regs_struct_rdx: %ld\n", OFFSET(user_regs_struct_rdx)); fprintf(fp, " user_regs_struct_edx: %ld\n", OFFSET(user_regs_struct_edx)); fprintf(fp, " user_regs_struct_rsi: %ld\n", OFFSET(user_regs_struct_rsi)); fprintf(fp, " user_regs_struct_esi: %ld\n", OFFSET(user_regs_struct_esi)); fprintf(fp, " user_regs_struct_rdi: %ld\n", OFFSET(user_regs_struct_rdi)); fprintf(fp, " user_regs_struct_edi: %ld\n", OFFSET(user_regs_struct_edi)); fprintf(fp, " user_regs_struct_ds: %ld\n", OFFSET(user_regs_struct_ds)); fprintf(fp, " user_regs_struct_es: %ld\n", OFFSET(user_regs_struct_es)); fprintf(fp, " user_regs_struct_fs: %ld\n", OFFSET(user_regs_struct_fs)); fprintf(fp, " user_regs_struct_gs: %ld\n", OFFSET(user_regs_struct_gs)); fprintf(fp, " user_regs_struct_rbp: %ld\n", OFFSET(user_regs_struct_rbp)); fprintf(fp, " user_regs_struct_r8: %ld\n", OFFSET(user_regs_struct_r8)); fprintf(fp, " user_regs_struct_r9: %ld\n", OFFSET(user_regs_struct_r9)); fprintf(fp, " user_regs_struct_r10: %ld\n", OFFSET(user_regs_struct_r10)); fprintf(fp, " user_regs_struct_r11: %ld\n", OFFSET(user_regs_struct_r11)); fprintf(fp, " user_regs_struct_r12: %ld\n", OFFSET(user_regs_struct_r12)); fprintf(fp, " user_regs_struct_r13: %ld\n", OFFSET(user_regs_struct_r13)); fprintf(fp, " user_regs_struct_r14: %ld\n", OFFSET(user_regs_struct_r14)); fprintf(fp, " user_regs_struct_r15: %ld\n", OFFSET(user_regs_struct_r15)); fprintf(fp, " e820map_nr_map: %ld\n", OFFSET(e820map_nr_map)); fprintf(fp, " e820entry_addr: %ld\n", OFFSET(e820entry_addr)); fprintf(fp, " e820entry_size: %ld\n", OFFSET(e820entry_size)); fprintf(fp, " e820entry_type: %ld\n", OFFSET(e820entry_type)); fprintf(fp, " char_device_struct_name: %ld\n", OFFSET(char_device_struct_name)); fprintf(fp, " char_device_struct_next: %ld\n", OFFSET(char_device_struct_next)); fprintf(fp, " char_device_struct_fops: %ld\n", OFFSET(char_device_struct_fops)); fprintf(fp, " char_device_struct_major: %ld\n", OFFSET(char_device_struct_major)); fprintf(fp, " char_device_struct_baseminor: %ld\n", OFFSET(char_device_struct_baseminor)); fprintf(fp, " char_device_struct_cdev: %ld\n", OFFSET(char_device_struct_cdev)); fprintf(fp, " cdev_ops: %ld\n", OFFSET(cdev_ops)); fprintf(fp, " probe_next: %ld\n", OFFSET(probe_next)); fprintf(fp, " probe_dev: %ld\n", OFFSET(probe_dev)); fprintf(fp, " probe_data: %ld\n", OFFSET(probe_data)); fprintf(fp, " kobj_map_probes: %ld\n", OFFSET(kobj_map_probes)); fprintf(fp, " blk_major_name_next: %ld\n", OFFSET(blk_major_name_next)); fprintf(fp, " blk_major_name_major: %ld\n", OFFSET(blk_major_name_major)); fprintf(fp, " blk_major_name_name: %ld\n", OFFSET(blk_major_name_name)); fprintf(fp, " radix_tree_root_height: %ld\n", OFFSET(radix_tree_root_height)); fprintf(fp, " radix_tree_root_rnode: %ld\n", OFFSET(radix_tree_root_rnode)); fprintf(fp, " radix_tree_node_slots: %ld\n", OFFSET(radix_tree_node_slots)); fprintf(fp, " radix_tree_node_height: %ld\n", OFFSET(radix_tree_node_height)); fprintf(fp, " rb_root_rb_node: %ld\n", OFFSET(rb_root_rb_node)); fprintf(fp, " rb_node_rb_left: %ld\n", OFFSET(rb_node_rb_left)); fprintf(fp, " rb_node_rb_right: %ld\n", OFFSET(rb_node_rb_right)); fprintf(fp, " x8664_pda_pcurrent: %ld\n", OFFSET(x8664_pda_pcurrent)); fprintf(fp, " x8664_pda_data_offset: %ld\n", OFFSET(x8664_pda_data_offset)); fprintf(fp, " x8664_pda_kernelstack: %ld\n", OFFSET(x8664_pda_kernelstack)); fprintf(fp, " x8664_pda_irqrsp: %ld\n", OFFSET(x8664_pda_irqrsp)); fprintf(fp, " x8664_pda_cpunumber: %ld\n", OFFSET(x8664_pda_cpunumber)); fprintf(fp, " x8664_pda_irqstackptr: %ld\n", OFFSET(x8664_pda_irqstackptr)); fprintf(fp, " x8664_pda_level4_pgt: %ld\n", OFFSET(x8664_pda_level4_pgt)); fprintf(fp, " x8664_pda_me: %ld\n", OFFSET(x8664_pda_me)); fprintf(fp, " tss_struct_ist: %ld\n", OFFSET(tss_struct_ist)); fprintf(fp, " mem_section_section_mem_map: %ld\n", OFFSET(mem_section_section_mem_map)); fprintf(fp, " vcpu_guest_context_user_regs: %ld\n", OFFSET(vcpu_guest_context_user_regs)); fprintf(fp, " cpu_user_regs_eip: %ld\n", OFFSET(cpu_user_regs_eip)); fprintf(fp, " cpu_user_regs_esp: %ld\n", OFFSET(cpu_user_regs_esp)); fprintf(fp, " cpu_user_regs_rip: %ld\n", OFFSET(cpu_user_regs_rip)); fprintf(fp, " cpu_user_regs_rsp: %ld\n", OFFSET(cpu_user_regs_rsp)); fprintf(fp, " unwind_table_core: %ld\n", OFFSET(unwind_table_core)); fprintf(fp, " unwind_table_init: %ld\n", OFFSET(unwind_table_init)); fprintf(fp, " unwind_table_address: %ld\n", OFFSET(unwind_table_address)); fprintf(fp, " unwind_table_size: %ld\n", OFFSET(unwind_table_size)); fprintf(fp, " unwind_table_link: %ld\n", OFFSET(unwind_table_link)); fprintf(fp, " unwind_table_name: %ld\n", OFFSET(unwind_table_name)); fprintf(fp, " rq_cfs: %ld\n", OFFSET(rq_cfs)); fprintf(fp, " rq_rt: %ld\n", OFFSET(rq_rt)); fprintf(fp, " cfs_rq_curr: %ld\n", OFFSET(cfs_rq_curr)); fprintf(fp, " rq_nr_running: %ld\n", OFFSET(rq_nr_running)); fprintf(fp, " rq_timestamp: %ld\n", OFFSET(rq_timestamp)); fprintf(fp, " task_struct_se: %ld\n", OFFSET(task_struct_se)); fprintf(fp, " sched_entity_run_node: %ld\n", OFFSET(sched_entity_run_node)); fprintf(fp, " sched_entity_cfs_rq: %ld\n", OFFSET(sched_entity_cfs_rq)); fprintf(fp, " sched_entity_my_q: %ld\n", OFFSET(sched_entity_my_q)); fprintf(fp, " sched_entity_on_rq: %ld\n", OFFSET(sched_entity_on_rq)); fprintf(fp, " cfs_rq_nr_running: %ld\n", OFFSET(cfs_rq_nr_running)); fprintf(fp, " cfs_rq_rb_leftmost: %ld\n", OFFSET(cfs_rq_rb_leftmost)); fprintf(fp, " cfs_rq_tasks_timeline: %ld\n", OFFSET(cfs_rq_tasks_timeline)); fprintf(fp, " rt_rq_active: %ld\n", OFFSET(rt_rq_active)); fprintf(fp, " pcpu_info_vcpu: %ld\n", OFFSET(pcpu_info_vcpu)); fprintf(fp, " pcpu_info_idle: %ld\n", OFFSET(pcpu_info_idle)); fprintf(fp, " vcpu_struct_rq: %ld\n", OFFSET(vcpu_struct_rq)); fprintf(fp, " s390_lowcore_psw_save_area: %ld\n", OFFSET(s390_lowcore_psw_save_area)); fprintf(fp, " s390_stack_frame_back_chain: %ld\n", OFFSET(s390_stack_frame_back_chain)); fprintf(fp, " s390_stack_frame_r14: %ld\n", OFFSET(s390_stack_frame_r14)); fprintf(fp, " cpu_context_save_fp: %ld\n", OFFSET(cpu_context_save_fp)); fprintf(fp, " cpu_context_save_sp: %ld\n", OFFSET(cpu_context_save_sp)); fprintf(fp, " cpu_context_save_pc: %ld\n", OFFSET(cpu_context_save_pc)); fprintf(fp, " elf_prstatus_pr_pid: %ld\n", OFFSET(elf_prstatus_pr_pid)); fprintf(fp, " elf_prstatus_pr_reg: %ld\n", OFFSET(elf_prstatus_pr_reg)); fprintf(fp, " irq_desc_t_name: %ld\n", OFFSET(irq_desc_t_name)); fprintf(fp, " thread_info_cpu_context: %ld\n", OFFSET(thread_info_cpu_context)); fprintf(fp, " unwind_table_list: %ld\n", OFFSET(unwind_table_list)); fprintf(fp, " unwind_table_start: %ld\n", OFFSET(unwind_table_start)); fprintf(fp, " unwind_table_stop: %ld\n", OFFSET(unwind_table_stop)); fprintf(fp, " unwind_table_begin_addr: %ld\n", OFFSET(unwind_table_begin_addr)); fprintf(fp, " unwind_table_end_addr: %ld\n", OFFSET(unwind_table_end_addr)); fprintf(fp, " unwind_idx_addr: %ld\n", OFFSET(unwind_idx_addr)); fprintf(fp, " unwind_idx_insn: %ld\n", OFFSET(unwind_idx_insn)); fprintf(fp, " class_devices: %ld\n", OFFSET(class_devices)); fprintf(fp, " class_p: %ld\n", OFFSET(class_p)); fprintf(fp, " class_private_devices: %ld\n", OFFSET(class_private_devices)); fprintf(fp, " device_knode_class: %ld\n", OFFSET(device_knode_class)); fprintf(fp, " device_node: %ld\n", OFFSET(device_node)); fprintf(fp, " gendisk_dev: %ld\n", OFFSET(gendisk_dev)); fprintf(fp, " gendisk_kobj: %ld\n", OFFSET(gendisk_kobj)); fprintf(fp, " gendisk_part0: %ld\n", OFFSET(gendisk_part0)); fprintf(fp, " gendisk_queue: %ld\n", OFFSET(gendisk_queue)); fprintf(fp, " hd_struct_dev: %ld\n", OFFSET(hd_struct_dev)); fprintf(fp, " klist_k_list: %ld\n", OFFSET(klist_k_list)); fprintf(fp, " klist_node_n_klist: %ld\n", OFFSET(klist_node_n_klist)); fprintf(fp, " klist_node_n_node: %ld\n", OFFSET(klist_node_n_node)); fprintf(fp, " kobject_entry: %ld\n", OFFSET(kobject_entry)); fprintf(fp, " kset_list: %ld\n", OFFSET(kset_list)); fprintf(fp, " request_list_count: %ld\n", OFFSET(request_list_count)); fprintf(fp, " request_queue_in_flight: %ld\n", OFFSET(request_queue_in_flight)); fprintf(fp, " request_queue_rq: %ld\n", OFFSET(request_queue_rq)); fprintf(fp, " subsys_private_klist_devices: %ld\n", OFFSET(subsys_private_klist_devices)); fprintf(fp, " subsystem_kset: %ld\n", OFFSET(subsystem_kset)); fprintf(fp, " file_f_op: %ld\n", OFFSET(file_f_op)); fprintf(fp, " file_private_data: %ld\n", OFFSET(file_private_data)); fprintf(fp, " hstate_order: %ld\n", OFFSET(hstate_order)); fprintf(fp, " hugetlbfs_sb_info_hstate: %ld\n", OFFSET(hugetlbfs_sb_info_hstate)); fprintf(fp, " idr_layer_ary: %ld\n", OFFSET(idr_layer_ary)); fprintf(fp, " idr_layer_layer: %ld\n", OFFSET(idr_layer_layer)); fprintf(fp, " idr_layers: %ld\n", OFFSET(idr_layers)); fprintf(fp, " idr_top: %ld\n", OFFSET(idr_top)); fprintf(fp, " ipc_id_ary_p: %ld\n", OFFSET(ipc_id_ary_p)); fprintf(fp, " ipc_ids_entries: %ld\n", OFFSET(ipc_ids_entries)); fprintf(fp, " ipc_ids_max_id: %ld\n", OFFSET(ipc_ids_max_id)); fprintf(fp, " ipc_ids_ipcs_idr: %ld\n", OFFSET(ipc_ids_ipcs_idr)); fprintf(fp, " ipc_ids_in_use: %ld\n", OFFSET(ipc_ids_in_use)); fprintf(fp, " ipc_namespace_ids: %ld\n", OFFSET(ipc_namespace_ids)); fprintf(fp, " kern_ipc_perm_deleted: %ld\n", OFFSET(kern_ipc_perm_deleted)); fprintf(fp, " kern_ipc_perm_key: %ld\n", OFFSET(kern_ipc_perm_key)); fprintf(fp, " kern_ipc_perm_mode: %ld\n", OFFSET(kern_ipc_perm_mode)); fprintf(fp, " kern_ipc_perm_uid: %ld\n", OFFSET(kern_ipc_perm_uid)); fprintf(fp, " kern_ipc_perm_id: %ld\n", OFFSET(kern_ipc_perm_id)); fprintf(fp, " kern_ipc_perm_seq: %ld\n", OFFSET(kern_ipc_perm_seq)); fprintf(fp, " nsproxy_ipc_ns: %ld\n", OFFSET(nsproxy_ipc_ns)); fprintf(fp, " shmem_inode_info_swapped: %ld\n", OFFSET(shmem_inode_info_swapped)); fprintf(fp, " shmem_inode_info_vfs_inode: %ld\n", OFFSET(shmem_inode_info_vfs_inode)); fprintf(fp, " shm_file_data_file: %ld\n", OFFSET(shm_file_data_file)); fprintf(fp, " shmid_kernel_shm_file: %ld\n", OFFSET(shmid_kernel_shm_file)); fprintf(fp, " shmid_kernel_shm_nattch: %ld\n", OFFSET(shmid_kernel_shm_nattch)); fprintf(fp, " shmid_kernel_shm_perm: %ld\n", OFFSET(shmid_kernel_shm_perm)); fprintf(fp, " shmid_kernel_shm_segsz: %ld\n", OFFSET(shmid_kernel_shm_segsz)); fprintf(fp, " shmid_kernel_id: %ld\n", OFFSET(shmid_kernel_id)); fprintf(fp, " sem_array_sem_perm: %ld\n", OFFSET(sem_array_sem_perm)); fprintf(fp, " sem_array_sem_id: %ld\n", OFFSET(sem_array_sem_id)); fprintf(fp, " sem_array_sem_nsems: %ld\n", OFFSET(sem_array_sem_nsems)); fprintf(fp, " msg_queue_q_perm: %ld\n", OFFSET(msg_queue_q_perm)); fprintf(fp, " msg_queue_q_id: %ld\n", OFFSET(msg_queue_q_id)); fprintf(fp, " msg_queue_q_cbytes: %ld\n", OFFSET(msg_queue_q_cbytes)); fprintf(fp, " msg_queue_q_qnum: %ld\n", OFFSET(msg_queue_q_qnum)); fprintf(fp, " super_block_s_fs_info: %ld\n", OFFSET(super_block_s_fs_info)); fprintf(fp, " log_ts_nsec: %ld\n", OFFSET(log_ts_nsec)); fprintf(fp, " log_len: %ld\n", OFFSET(log_len)); fprintf(fp, " log_text_len: %ld\n", OFFSET(log_text_len)); fprintf(fp, " log_dict_len: %ld\n", OFFSET(log_dict_len)); fprintf(fp, " log_level: %ld\n", OFFSET(log_level)); fprintf(fp, " log_flags_level: %ld\n", OFFSET(log_flags_level)); fprintf(fp, " sched_rt_entity_my_q: %ld\n", OFFSET(sched_rt_entity_my_q)); fprintf(fp, " task_group_parent: %ld\n", OFFSET(task_group_parent)); fprintf(fp, " task_group_css: %ld\n", OFFSET(task_group_css)); fprintf(fp, " cgroup_subsys_state_cgroup: %ld\n", OFFSET(cgroup_subsys_state_cgroup)); fprintf(fp, " cgroup_dentry: %ld\n", OFFSET(cgroup_dentry)); fprintf(fp, " task_group_rt_rq: %ld\n", OFFSET(task_group_rt_rq)); fprintf(fp, " rt_rq_tg: %ld\n", OFFSET(rt_rq_tg)); fprintf(fp, " task_group_cfs_rq: %ld\n", OFFSET(task_group_cfs_rq)); fprintf(fp, " cfs_rq_tg: %ld\n", OFFSET(cfs_rq_tg)); fprintf(fp, " task_group_siblings: %ld\n", OFFSET(task_group_siblings)); fprintf(fp, " task_group_children: %ld\n", OFFSET(task_group_children)); fprintf(fp, " task_group_cfs_bandwidth: %ld\n", OFFSET(task_group_cfs_bandwidth)); fprintf(fp, " cfs_rq_throttled: %ld\n", OFFSET(cfs_rq_throttled)); fprintf(fp, " task_group_rt_bandwidth: %ld\n", OFFSET(task_group_rt_bandwidth)); fprintf(fp, " rt_rq_rt_throttled: %ld\n", OFFSET(rt_rq_rt_throttled)); fprintf(fp, " rt_rq_highest_prio: %ld\n", OFFSET(rt_rq_highest_prio)); fprintf(fp, " rt_rq_rt_nr_running: %ld\n", OFFSET(rt_rq_rt_nr_running)); fprintf(fp, " hrtimer_cpu_base_clock_base: %ld\n", OFFSET(hrtimer_cpu_base_clock_base)); fprintf(fp, " hrtimer_clock_base_offset: %ld\n", OFFSET(hrtimer_clock_base_offset)); fprintf(fp, " hrtimer_clock_base_active: %ld\n", OFFSET(hrtimer_clock_base_active)); fprintf(fp, " hrtimer_clock_base_first: %ld\n", OFFSET(hrtimer_clock_base_first)); fprintf(fp, " hrtimer_clock_base_get_time: %ld\n", OFFSET(hrtimer_clock_base_get_time)); fprintf(fp, " hrtimer_base_first: %ld\n", OFFSET(hrtimer_base_first)); fprintf(fp, " hrtimer_base_pending: %ld\n", OFFSET(hrtimer_base_pending)); fprintf(fp, " hrtimer_base_get_time: %ld\n", OFFSET(hrtimer_base_get_time)); fprintf(fp, " hrtimer_node: %ld\n", OFFSET(hrtimer_node)); fprintf(fp, " hrtimer_list: %ld\n", OFFSET(hrtimer_list)); fprintf(fp, " hrtimer_softexpires: %ld\n", OFFSET(hrtimer_softexpires)); fprintf(fp, " hrtimer_expires: %ld\n", OFFSET(hrtimer_expires)); fprintf(fp, " hrtimer_function: %ld\n", OFFSET(hrtimer_function)); fprintf(fp, " timerqueue_head_next: %ld\n", OFFSET(timerqueue_head_next)); fprintf(fp, " timerqueue_node_expires: %ld\n", OFFSET(timerqueue_node_expires)); fprintf(fp, " timerqueue_node_node: %ld\n", OFFSET(timerqueue_node_node)); fprintf(fp, " ktime_t_tv64: %ld\n", OFFSET(ktime_t_tv64)); fprintf(fp, " ktime_t_sec: %ld\n", OFFSET(ktime_t_sec)); fprintf(fp, " ktime_t_nsec: %ld\n", OFFSET(ktime_t_nsec)); fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); fprintf(fp, " page_flags: %ld\n", SIZE(page_flags)); fprintf(fp, " free_area_struct: %ld\n", SIZE(free_area_struct)); fprintf(fp, " free_area: %ld\n", SIZE(free_area)); fprintf(fp, " zone_struct: %ld\n", SIZE(zone_struct)); fprintf(fp, " zone: %ld\n", SIZE(zone)); fprintf(fp, " kmem_slab_s: %ld\n", SIZE(kmem_slab_s)); fprintf(fp, " slab_s: %ld\n", SIZE(slab_s)); fprintf(fp, " slab: %ld\n", SIZE(slab)); fprintf(fp, " kmem_cache_s: %ld\n", SIZE(kmem_cache_s)); fprintf(fp, " cpucache_s: %ld\n", SIZE(cpucache_s)); fprintf(fp, " array_cache: %ld\n", SIZE(array_cache)); fprintf(fp, " kmem_bufctl_t: %ld\n", SIZE(kmem_bufctl_t)); fprintf(fp, " kmem_cache: %ld\n", SIZE(kmem_cache)); fprintf(fp, " kmem_cache_node: %ld\n", SIZE(kmem_cache_node)); fprintf(fp, " kmem_cache_cpu: %ld\n", SIZE(kmem_cache_cpu)); fprintf(fp, " swap_info_struct: %ld\n", SIZE(swap_info_struct)); fprintf(fp, " vm_area_struct: %ld\n", SIZE(vm_area_struct)); fprintf(fp, " mm_struct: %ld\n", SIZE(mm_struct)); fprintf(fp, " pglist_data: %ld\n", SIZE(pglist_data)); fprintf(fp, " page_cache_bucket: %ld\n", SIZE(page_cache_bucket)); fprintf(fp, " pt_regs: %ld\n", SIZE(pt_regs)); fprintf(fp, " task_struct: %ld\n", SIZE(task_struct)); fprintf(fp, " thread_info: %ld\n", SIZE(thread_info)); fprintf(fp, " softirq_state: %ld\n", SIZE(softirq_state)); fprintf(fp, " softirq_action: %ld\n", SIZE(softirq_action)); fprintf(fp, " desc_struct: %ld\n", SIZE(desc_struct)); fprintf(fp, " umode_t: %ld\n", SIZE(umode_t)); fprintf(fp, " dentry: %ld\n", SIZE(dentry)); fprintf(fp, " fs_struct: %ld\n", SIZE(fs_struct)); fprintf(fp, " files_struct: %ld\n", SIZE(files_struct)); fprintf(fp, " fdtable: %ld\n", SIZE(fdtable)); fprintf(fp, " file: %ld\n", SIZE(file)); fprintf(fp, " inode: %ld\n", SIZE(inode)); fprintf(fp, " vfsmount: %ld\n", SIZE(vfsmount)); fprintf(fp, " mount: %ld\n", SIZE(mount)); fprintf(fp, " super_block: %ld\n", SIZE(super_block)); fprintf(fp, " irqdesc: %ld\n", SIZE(irqdesc)); fprintf(fp, " module: %ld\n", SIZE(module)); fprintf(fp, " module_sect_attr: %ld\n", SIZE(module_sect_attr)); fprintf(fp, " list_head: %ld\n", SIZE(list_head)); fprintf(fp, " hlist_head: %ld\n", SIZE(hlist_head)); fprintf(fp, " hlist_node: %ld\n", SIZE(hlist_node)); fprintf(fp, " irq_cpustat_t: %ld\n", SIZE(irq_cpustat_t)); fprintf(fp, " cpuinfo_x86: %ld\n", SIZE(cpuinfo_x86)); fprintf(fp, " cpuinfo_ia64: %ld\n", SIZE(cpuinfo_ia64)); fprintf(fp, " timer_list: %ld\n", SIZE(timer_list)); fprintf(fp, " timer_vec_root: %ld\n", SIZE(timer_vec_root)); fprintf(fp, " timer_vec: %ld\n", SIZE(timer_vec)); fprintf(fp, " tvec_root_s: %ld\n", SIZE(tvec_root_s)); fprintf(fp, " tvec_s: %ld\n", SIZE(tvec_s)); fprintf(fp, " tvec_t_base_s: %ld\n", SIZE(tvec_t_base_s)); fprintf(fp, " wait_queue: %ld\n", SIZE(wait_queue)); fprintf(fp, " __wait_queue: %ld\n", SIZE(__wait_queue)); fprintf(fp, " device: %ld\n", SIZE(device)); fprintf(fp, " net_device: %ld\n", SIZE(net_device)); fprintf(fp, " sock: %ld\n", SIZE(sock)); fprintf(fp, " inet_sock: %ld\n", SIZE(inet_sock)); fprintf(fp, " socket: %ld\n", SIZE(socket)); fprintf(fp, " in6_addr: %ld\n", SIZE(in6_addr)); fprintf(fp, " signal_struct: %ld\n", SIZE(signal_struct)); fprintf(fp, " sigpending_signal: %ld\n", SIZE(sigpending_signal)); fprintf(fp, " signal_queue: %ld\n", SIZE(signal_queue)); fprintf(fp, " sigqueue: %ld\n", SIZE(sigqueue)); fprintf(fp, " k_sigaction: %ld\n", SIZE(k_sigaction)); fprintf(fp, " sighand_struct: %ld\n", SIZE(sighand_struct)); fprintf(fp, " resource_entry_t: %ld\n", SIZE(resource_entry_t)); fprintf(fp, " resource: %ld\n", SIZE(resource)); fprintf(fp, " runqueue: %ld\n", SIZE(runqueue)); fprintf(fp, " irq_desc_t: %ld\n", SIZE(irq_desc_t)); fprintf(fp, " irq_data: %ld\n", SIZE(irq_data)); fprintf(fp, " task_union: %ld\n", SIZE(task_union)); fprintf(fp, " thread_union: %ld\n", SIZE(thread_union)); fprintf(fp, " prio_array: %ld\n", SIZE(prio_array)); fprintf(fp, " user_regs_struct: %ld\n", SIZE(user_regs_struct)); fprintf(fp, " switch_stack: %ld\n", SIZE(switch_stack)); fprintf(fp, " vm_area_struct_vm_flags: %ld\n", SIZE(vm_area_struct_vm_flags)); fprintf(fp, " e820map: %ld\n", SIZE(e820map)); fprintf(fp, " e820entry: %ld\n", SIZE(e820entry)); fprintf(fp, " cpu_s: %ld\n", SIZE(cpu_s)); fprintf(fp, " pgd_t: %ld\n", SIZE(pgd_t)); fprintf(fp, " kallsyms_header: %ld\n", SIZE(kallsyms_header)); fprintf(fp, " kallsyms_symbol: %ld\n", SIZE(kallsyms_symbol)); fprintf(fp, " kallsyms_section: %ld\n", SIZE(kallsyms_section)); fprintf(fp, " block_device: %ld\n", SIZE(block_device)); fprintf(fp, " blk_major_name: %ld\n", SIZE(blk_major_name)); fprintf(fp, " address_space: %ld\n", SIZE(address_space)); fprintf(fp, " gendisk: %ld\n", SIZE(gendisk)); fprintf(fp, " irq_ctx: %ld\n", SIZE(irq_ctx)); fprintf(fp, " char_device_struct: %ld\n", SIZE(char_device_struct)); fprintf(fp, " spinlock_t: %ld\n", SIZE(spinlock_t)); fprintf(fp, " radix_tree_root: %ld\n", SIZE(radix_tree_root)); fprintf(fp, " radix_tree_node: %ld\n", SIZE(radix_tree_node)); fprintf(fp, " x8664_pda: %ld\n", SIZE(x8664_pda)); fprintf(fp, " ppc64_paca: %ld\n", SIZE(ppc64_paca)); fprintf(fp, " gate_struct: %ld\n", SIZE(gate_struct)); fprintf(fp, " tss_struct: %ld\n", SIZE(tss_struct)); fprintf(fp, " task_struct_start_time: %ld\n", SIZE(task_struct_start_time)); fprintf(fp, " task_struct_utime: %ld\n", SIZE(task_struct_utime)); fprintf(fp, " task_struct_stime: %ld\n", SIZE(task_struct_stime)); fprintf(fp, " cputime_t: %ld\n", SIZE(cputime_t)); fprintf(fp, " mem_section: %ld\n", SIZE(mem_section)); fprintf(fp, " pid_link: %ld\n", SIZE(pid_link)); fprintf(fp, " upid: %ld\n", SIZE(upid)); fprintf(fp, " unwind_table: %ld\n", SIZE(unwind_table)); fprintf(fp, " rlimit: %ld\n", SIZE(rlimit)); fprintf(fp, " cfs_rq: %ld\n", SIZE(cfs_rq)); fprintf(fp, " pcpu_info: %ld\n", SIZE(pcpu_info)); fprintf(fp, " vcpu_struct: %ld\n", SIZE(vcpu_struct)); fprintf(fp, " cdev: %ld\n", SIZE(cdev)); fprintf(fp, " probe: %ld\n", SIZE(probe)); fprintf(fp, " kobj_map: %ld\n", SIZE(kobj_map)); fprintf(fp, " cpu_context_save: %ld\n", SIZE(cpu_context_save)); fprintf(fp, " elf_prstatus: %ld\n", SIZE(elf_prstatus)); fprintf(fp, " note_buf: %ld\n", SIZE(note_buf)); fprintf(fp, " unwind_idx: %ld\n", SIZE(unwind_idx)); fprintf(fp, " s390_stack_frame: %ld\n", SIZE(s390_stack_frame)); fprintf(fp, " percpu_data: %ld\n", SIZE(percpu_data)); fprintf(fp, " sched_entity: %ld\n", SIZE(sched_entity)); fprintf(fp, " kernel_stat: %ld\n", SIZE(kernel_stat)); fprintf(fp, " subsystem: %ld\n", SIZE(subsystem)); fprintf(fp, " class_private: %ld\n", SIZE(class_private)); fprintf(fp, " rq_in_flight: %ld\n", SIZE(rq_in_flight)); fprintf(fp, " class_private_devices: %ld\n", SIZE(class_private_devices)); fprintf(fp, " hstate: %ld\n", SIZE(hstate)); fprintf(fp, " ipc_ids: %ld\n", SIZE(ipc_ids)); fprintf(fp, " shmid_kernel: %ld\n", SIZE(shmid_kernel)); fprintf(fp, " sem_array: %ld\n", SIZE(sem_array)); fprintf(fp, " msg_queue: %ld\n", SIZE(msg_queue)); fprintf(fp, " log: %ld\n", SIZE(log)); fprintf(fp, " log_level: %ld\n", SIZE(log_level)); fprintf(fp, " rt_rq: %ld\n", SIZE(rt_rq)); fprintf(fp, " task_group: %ld\n", SIZE(task_group)); fprintf(fp, " vmap_area: %ld\n", SIZE(vmap_area)); fprintf(fp, " hrtimer_clock_base: %ld\n", SIZE(hrtimer_clock_base)); fprintf(fp, " hrtimer_base: %ld\n", SIZE(hrtimer_base)); fprintf(fp, "\n array_table:\n"); /* * Use get_array_length() for those fields not set up at init-time; * ARRAY_LENGTH() will work for the rest. */ fprintf(fp, " kmem_cache_s_name: %d\n", ARRAY_LENGTH(kmem_cache_s_name)); fprintf(fp, " kmem_cache_s_c_name: %d\n", ARRAY_LENGTH(kmem_cache_s_c_name)); fprintf(fp, " kmem_cache_s_array: %d\n", ARRAY_LENGTH(kmem_cache_s_array)); fprintf(fp, " kmem_cache_s_cpudata: %d\n", ARRAY_LENGTH(kmem_cache_s_cpudata)); fprintf(fp, " log_buf: %d\n", ARRAY_LENGTH(log_buf)); fprintf(fp, " irq_desc: %d\n", ARRAY_LENGTH(irq_desc)); fprintf(fp, " irq_action: %d\n", ARRAY_LENGTH(irq_action)); fprintf(fp, " timer_vec_vec: %d\n", get_array_length("timer_vec.vec", NULL, SIZE(list_head))); fprintf(fp, " timer_vec_root_vec: %d\n", get_array_length("timer_vec_root.vec", NULL, SIZE(list_head))); fprintf(fp, " tvec_root_s_vec: %d\n", get_array_length("tvec_root_s.vec", NULL, SIZE(list_head))); fprintf(fp, " tvec_s_vec: %d\n", get_array_length("tvec_s.vec", NULL, SIZE(list_head))); fprintf(fp, " page_hash_table: %d\n", ARRAY_LENGTH(page_hash_table)); fprintf(fp, " net_device_name: %d\n", ARRAY_LENGTH(net_device_name)); fprintf(fp, " neigh_table_hash_buckets: %d\n", get_array_length("neigh_table.hash_buckets", NULL, sizeof(void *))); fprintf(fp, " neighbour_ha: %d\n", get_array_length("neighbour.ha", NULL, sizeof(char))); fprintf(fp, " swap_info: %d\n", get_array_length("swap_info", NULL, 0)); fprintf(fp, " pglist_data_node_zones: %d\n", ARRAY_LENGTH(pglist_data_node_zones)); fprintf(fp, " zone_struct_free_area: %d\n", ARRAY_LENGTH(zone_struct_free_area)); fprintf(fp, " zone_free_area: %d\n", ARRAY_LENGTH(zone_free_area)); fprintf(fp, " free_area: %d\n", ARRAY_LENGTH(free_area)); fprintf(fp, " free_area_DIMENSION: %d\n", ARRAY_LENGTH(free_area_DIMENSION)); fprintf(fp, " prio_array_queue: %d\n", get_array_length("prio_array.queue", NULL, SIZE(list_head))); fprintf(fp, " height_to_maxindex: %d\n", ARRAY_LENGTH(height_to_maxindex)); fprintf(fp, " pid_hash: %d\n", ARRAY_LENGTH(pid_hash)); fprintf(fp, " kmem_cache_node: %d\n", ARRAY_LENGTH(kmem_cache_node)); fprintf(fp, " kmem_cache_cpu_slab: %d\n", ARRAY_LENGTH(kmem_cache_cpu_slab)); fprintf(fp, " rt_prio_array_queue: %d\n", ARRAY_LENGTH(rt_prio_array_queue)); if (spec) { int in_size_table, in_array_table, arrays, offsets, sizes; in_size_table = in_array_table = arrays = offsets = sizes = 0; rewind(pc->tmpfile); while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (strstr(buf, "size_table:")) in_size_table = TRUE; if (strstr(buf, "array_table:")) { in_array_table = TRUE; in_size_table = FALSE; } if (strstr(buf, spec)) { if (in_size_table) { if (!sizes) fprintf(pc->saved_fp, "%s size_table:\n", offsets ? "\n" : ""); sizes++; } else if (in_array_table) { if (!arrays) fprintf(pc->saved_fp, "%s array_table:\n", offsets || sizes ? "\n" : ""); arrays++; } else { if (!offsets) fprintf(pc->saved_fp, " offset_table:\n"); offsets++; } if (strstr(buf, " size_table:") || strstr(buf, " array_table:") || strstr(buf, " offset_table:")) break; fprintf(pc->saved_fp, buf); } } close_tmpfile(); } if (makestruct) { fprintf(pc->saved_fp, "static struct builtin_debug_table %s;\n\n", revname); rewind(pc->tmpfile); while (fgets(buf, BUFSIZE, pc->tmpfile)) { if (strstr(buf, " offset_table:\n")) { fprintf(pc->saved_fp, "static struct offset_table %s_offset_table = {\n", revname); continue; } if (strstr(buf, " size_table:\n")) { fprintf(pc->saved_fp, "static struct size_table %s_size_table = {\n", revname); continue; } if (strstr(buf, " array_table:\n")) { fprintf(pc->saved_fp, "static struct array_table %s_array_table = {\n", revname); continue; } if (STREQ(buf, "\n")) { fprintf(pc->saved_fp, "};\n\n"); continue; } fprintf(pc->saved_fp, "%s,\n", strip_linefeeds(buf)); } fprintf(pc->saved_fp, "};\n\n"); close_tmpfile(); fprintf(fp, "static struct builtin_debug_table %s = {\n", revname); fprintf(fp, " release: \"%s\",\n", uts->release); fprintf(fp, " machine_type: \"%s\",\n", pc->machine_type); fprintf(fp, " offset_table: &%s_offset_table,\n", revname); fprintf(fp, " size_table: &%s_size_table,\n", revname); fprintf(fp, " array_table: &%s_array_table,\n", revname); fprintf(fp, "};\n\n"); } pc->flags |= data_debug; } #define NUMARGS_CACHE_ENTRIES (100) static struct numargs_cache { ulong function; int numargs; } numargs_cache[NUMARGS_CACHE_ENTRIES] = { {0} }; static int numargs_cache_index = 0; int get_function_numargs(ulong callpc) { int i; struct numargs_cache *na; struct gnu_request *req; int retval; ulong func; func = closest_symbol_value(callpc); if (!func) return -1; for (i = 0; i < NUMARGS_CACHE_ENTRIES; i++) { na = &numargs_cache[i]; if (!na->function) { numargs_cache_index = i; break; } if (na->function == func) return na->numargs; } req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); req->buf = GETBUF(BUFSIZE); req->command = GNU_FUNCTION_NUMARGS; req->flags |= GNU_RETURN_ON_ERROR; req->pc = func; gdb_interface(req); if (req->flags & GNU_COMMAND_FAILED) { retval = -1; goto func_done; } retval = (int)req->value; func_done: FREEBUF(req->buf); FREEBUF(req); numargs_cache_index %= NUMARGS_CACHE_ENTRIES; na = &numargs_cache[numargs_cache_index++]; na->function = func; na->numargs = retval; return retval; } /* * help -c output */ void dump_numargs_cache(void) { int i; struct numargs_cache *na; char buf[BUFSIZE]; fprintf(fp, "numargs_cache_index: %d\n", numargs_cache_index); for (i = 0; i < NUMARGS_CACHE_ENTRIES; i++) { na = &numargs_cache[i]; if (!na->function) break; fprintf(fp, "%lx (%s): %d\n", na->function, value_to_symstr(na->function, buf, 0), na->numargs); } } /* * This is the call-back function that is passed to bfd_map_over_sections(). * Based upon the request, check whether the passed-in section has what * the caller needs. The MODULE_SECTIONS code is tricky because it has * to keep a running alignment value as it walks through the section * headers in order to eventually calculate the module's base data address. */ static void section_header_info(bfd *bfd, asection *section, void *reqptr) { int i; struct load_module *lm; ulong request; asection **sec; request = ((ulong)reqptr); switch (request) { case (ulong)KERNEL_SECTIONS: sec = (asection **)st->sections; for (i = 0; (i < st->bfd->section_count) && *sec; i++) sec++; *sec = section; if (STREQ(bfd_get_section_name(bfd, section), ".text.init") || STREQ(bfd_get_section_name(bfd, section), ".init.text")) { kt->stext_init = (ulong) bfd_get_section_vma(bfd, section); kt->etext_init = kt->stext_init + (ulong)bfd_section_size(bfd, section); } if (STREQ(bfd_get_section_name(bfd, section), ".text") || STREQ(bfd_get_section_name(bfd, section), ".data")) { if (!(bfd_get_section_flags(bfd, section) & SEC_LOAD)) st->flags |= NO_SEC_LOAD; if (!(bfd_get_section_flags(bfd, section) & SEC_HAS_CONTENTS)) st->flags |= NO_SEC_CONTENTS; } if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { st->dwarf_eh_frame_file_offset = (off_t)section->filepos; st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); } if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) { st->dwarf_debug_frame_file_offset = (off_t)section->filepos; st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section); } break; case (ulong)MODULE_SECTIONS: lm = st->current; store_section_data(lm, bfd, section); break; case (ulong)VERIFY_SECTIONS: if (STREQ(bfd_get_section_name(bfd, section), ".text") || STREQ(bfd_get_section_name(bfd, section), ".data")) { if (!(bfd_get_section_flags(bfd, section) & SEC_LOAD)) st->flags |= NO_SEC_LOAD; if (!(bfd_get_section_flags(bfd, section) & SEC_HAS_CONTENTS)) st->flags |= NO_SEC_CONTENTS; } if (STREQ(bfd_get_section_name(bfd, section), ".eh_frame")) { st->dwarf_eh_frame_file_offset = (off_t)section->filepos; st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section); } if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) { st->dwarf_debug_frame_file_offset = (off_t)section->filepos; st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section); } break; default: error(FATAL, "invalid call to section_header_info\n"); break; } } /* * Emulate insmod by calculating the priorities of each section. * The priority number will be used later by calculate_load_order() * to determine the the starting addresses of the text and data * sections. * * insmod uses the following code sequence -- which references the actual ELF * section header structure data: * * ac = 0; * if (a->name[0] != '.' || strlen(a->name) != 10 || * strcmp(a->name + 5, ".init")) ac |= 32; * if (af & SHF_ALLOC) ac |= 16; * if (!(af & SHF_WRITE)) ac |= 8; * if (af & SHF_EXECINSTR) ac |= 4; * if (a->header.sh_type != SHT_NOBITS) ac |= 2; * * BFD abstracts the ELF section header into an asection structure, so this * code determines the priority using the relevant logic. */ static void store_section_data(struct load_module *lm, bfd *bfd, asection *section) { int i; int prio; char *name; prio = 0; name = (char *)bfd_get_section_name(bfd, section); if (name[0] != '.' || strlen(name) != 10 || strcmp(name + 5, ".init")) prio |= 32; if (section->flags & SEC_ALLOC) prio |= 16; if (section->flags & SEC_READONLY) prio |= 8; if (section->flags & SEC_CODE) prio |= 4; if (!STREQ(name, ".bss")) prio |= 2; i = lm->mod_sections; lm->mod_section_data[i].section = section; lm->mod_section_data[i].priority = prio; lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND; /* * The percpu section isn't included in kallsyms or module_core area. */ if (lm->mod_percpu && (STREQ(name,".data.percpu") || STREQ(name, ".data..percpu"))) { lm->mod_percpu_size = bfd_section_size(bfd, section); lm->mod_section_data[i].flags |= SEC_FOUND; } lm->mod_section_data[i].size = bfd_section_size(bfd, section); lm->mod_section_data[i].offset = 0; if (strlen(name) < MAX_MOD_SEC_NAME) strcpy(lm->mod_section_data[i].name, name); else strncpy(lm->mod_section_data[i].name, name, MAX_MOD_SEC_NAME-1); lm->mod_sections += 1; } /* * insmod first calculates a priority for each module section, and re-orders * the sections from their ELF object file position -- that priority was * determined in store_section_priority(). Now, based upon a priority-based * ordering, this routine calculates the starting offset for each section. * This is the code segment from insmod that is being emulated here: * * unsigned long * obj_load_size (struct obj_file *f) * { * unsigned long dot = 0; * struct obj_section *sec; * * /+ Finalize the positions of the sections relative to one another. +/ * * for (sec = f->load_order; sec ; sec = sec->load_next) * { * ElfW(Addr) align; * * align = sec->header.sh_addralign; * if (align && (dot & (align - 1))) * dot = (dot | (align - 1)) + 1; * * sec->header.sh_addr = dot; * dot += sec->header.sh_size; * } * * return dot; * } * * Another insmod hack extends the .kstrtab section with a string containing * the name of the module. If the .kstrtab comes before the .data section, * it in turn gets bumped up. * * BFD abstracts the ELF section header into an asection structure, so this * code determines the priority using the relevant logic. * * Later versions of insmod do the work for us by creating pseudo-symbols * that contain the base address of the text, rodata, data and bss sections. * When that's the case, veer off to check_insmod_builtin() to potentially * override the offset value calculated here. */ static void calculate_load_order_v1(struct load_module *lm, bfd *bfd) { int i; asection *section; ulong alignment; ulong offset; offset = 0; switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V1: offset = lm->mod_size_of_struct; break; case KMOD_V2: offset = lm->mod_base; break; } qsort(&lm->mod_section_data[0], lm->mod_sections, sizeof(struct mod_section_data), compare_prios); for (i = (lm->mod_sections-1); i >= 0; i--) { section = lm->mod_section_data[i].section; alignment = power(2, bfd_get_section_alignment(bfd, section)); if (alignment && (offset & (alignment - 1))) offset = (offset | (alignment - 1)) + 1; lm->mod_section_data[i].offset = offset; if (CRASHDEBUG(1)) fprintf(fp, "%12s prio: %x flags: %x offset: %lx\n", lm->mod_section_data[i].name, lm->mod_section_data[i].priority, lm->mod_section_data[i].flags, lm->mod_section_data[i].offset); if (st->flags & INSMOD_BUILTIN) check_insmod_builtin(lm, i, &offset); if (STREQ(lm->mod_section_data[i].name, ".text")) lm->mod_text_start = lm->mod_base + offset; if (STREQ(lm->mod_section_data[i].name, ".data")) lm->mod_data_start = lm->mod_base + offset; if (STREQ(lm->mod_section_data[i].name, ".bss")) lm->mod_bss_start = lm->mod_base + offset; if (STREQ(lm->mod_section_data[i].name, ".rodata")) lm->mod_rodata_start = lm->mod_base + offset; offset += bfd_section_size(bfd, section); if (STREQ(bfd_get_section_name(bfd, section), ".kstrtab")) offset += strlen(lm->mod_name)+1; } } /* * Later versions of kmod no longer get the help from insmod, * and while the heuristics might work, it's relatively * straightforward to just try to match the sections in the object file * with exported symbols. * * This works well if kallsyms is set, but may not work so well in other * instances. */ static void calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, void *minisyms, long symcount, unsigned int size) { struct syment *s1, *s2; ulong sec_start; bfd_byte *from, *fromend; asymbol *store; asymbol *sym; symbol_info syminfo; char *secname; int i; if ((store = bfd_make_empty_symbol(bfd)) == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); s1 = lm->mod_symtable; s2 = lm->mod_symend; while (s1 < s2) { ulong sym_offset = s1->value - lm->mod_base; if (MODULE_PSEUDO_SYMBOL(s1)) { s1++; continue; } /* Skip over symbols whose sections have been identified. */ for (i = 0; i < lm->mod_sections; i++) { if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0) continue; if (sym_offset >= lm->mod_section_data[i].offset && sym_offset < lm->mod_section_data[i].offset + lm->mod_section_data[i].size) { break; } } /* Matched one of the sections. Skip symbol. */ if (i < lm->mod_sections) { if (CRASHDEBUG(2)) { fprintf(fp, "skip %lx %s %s\n", s1->value, s1->name, lm->mod_section_data[i].name); } s1++; continue; } /* Find the symbol in the object file. */ from = (bfd_byte *) minisyms; fromend = from + symcount * size; secname = NULL; for (; from < fromend; from += size) { if ((sym = bfd_minisymbol_to_symbol(bfd, dynamic, from, store)) == NULL) error(FATAL, "bfd_minisymbol_to_symbol() failed\n"); bfd_get_symbol_info(bfd, sym, &syminfo); if (CRASHDEBUG(3)) { fprintf(fp,"matching sym %s %lx against bfd %s %lx\n", s1->name, (long) s1->value, syminfo.name, (long) syminfo.value); } if (strcmp(syminfo.name, s1->name) == 0) { secname = (char *)bfd_get_section_name(bfd, sym->section); break; } } if (secname == NULL) { if (CRASHDEBUG(1)) { fprintf(fp, "symbol %s not found in module\n", s1->name); } s1++; continue; } /* Match the section it came in. */ for (i = 0; i < lm->mod_sections; i++) { if (STREQ(lm->mod_section_data[i].name, secname)) { break; } } if (i == lm->mod_sections) { fprintf(fp, "?? Section %s not found for symbol %s\n", secname, s1->name); s1++; continue; } /* Update the offset information for the section */ sec_start = s1->value - syminfo.value; // sec_end = sec_start + lm->mod_section_data[i].size; lm->mod_section_data[i].offset = sec_start - lm->mod_base; lm->mod_section_data[i].flags |= SEC_FOUND; if (CRASHDEBUG(2)) { fprintf(fp, "update sec offset sym %s @ %lx val %lx section %s\n", s1->name, s1->value, (ulong)syminfo.value, secname); } if (strcmp(secname, ".text") == 0) lm->mod_text_start = sec_start; if (strcmp(secname, ".bss") == 0) lm->mod_bss_start = sec_start; if (strcmp(secname, ".data") == 0) lm->mod_data_start = sec_start; if (strcmp(secname, ".data") == 0) lm->mod_data_start = sec_start; if (strcmp(secname, ".rodata") == 0) lm->mod_rodata_start = sec_start; s1++; } } /* * Later versons of insmod store basic address information of each * module in a format that looks like the following example of the * nfsd module: * * d004d000 __insmod_nfsd_O/lib/modules/2.2.17/fs/nfsd.o_M3A7EE300_V131601 * d004d054 __insmod_nfsd_S.text_L30208 * d0054840 __insmod_nfsd_S.rodata_L8930 * d0056b40 __insmod_nfsd_S.data_L1220 * d00570c0 __insmod_nfsd_S.bss_L123840 * * When that's true, override the offset value made by calculate_load_order(). */ static void check_insmod_builtin(struct load_module *lm, int index, ulong *offset) { struct syment *sp; char buf[BUFSIZE]; ulong offs; sprintf(buf, "__insmod_%s_S%s", lm->mod_name, lm->mod_section_data[index].name); if (symbol_query(buf, NULL, &sp) == 1) { if (CRASHDEBUG(1)) fprintf(fp, "check_insmod_builtin: %lx %s\n", sp->value, sp->name); offs = sp->value - lm->mod_base; if (offs != *offset) { if (CRASHDEBUG(1)) fprintf(fp, "check_insmod_builtin: [%s] %s %lx != %lx\n", lm->mod_name, lm->mod_section_data[index].name, offs, *offset); *offset = offs; } } } /* * Determine whether a module symbol is one of the insmod-created symbols * described above. */ static int is_insmod_builtin(struct load_module *lm, struct syment *sp) { char buf[BUFSIZE]; if (!(st->flags & INSMOD_BUILTIN)) return FALSE; sprintf(buf, "__insmod_%s_S", lm->mod_name); if (strstr(sp->name, buf)) return TRUE; return FALSE; } /* * Modified from typical "qsort" help functions to simulate section-ordering * done by insmod when loading modules. */ static int compare_prios(const void *v1, const void *v2) { struct mod_section_data *md1, *md2; md1 = (struct mod_section_data *)v1; md2 = (struct mod_section_data *)v2; return (md1->priority < md2->priority ? -1 : 1); } /* * This routine scours a module object file namelist for global text and * data symbols, sorting and storing them in a static table for quick * reference. This allows access to non-EXPORT_SYMBOL() symbols. * The object file is then passed to gdb for loading of all symbolic * and debugging data. * * Thanks to David Addison (addy@quadrics.com) for the suggestion. */ int load_module_symbols(char *modref, char *namelist, ulong base_addr) { static bfd *mbfd; char **matching; long symcount; void *minisyms; unsigned int size; int result; struct load_module *lm; asymbol *sort_x; asymbol *sort_y; if (!is_module_name(modref, NULL, &lm)) error(FATAL, "%s: not a loaded module name\n", modref); if ((lm->mod_flags & MOD_LOAD_SYMS) || strlen(lm->mod_namelist)) { if (CRASHDEBUG(1)) fprintf(fp, "%s: module symbols are already loaded\n", modref); return TRUE; } if (CRASHDEBUG(2)) fprintf(fp, "load_module_symbols: %s %s %lx %lx\n", modref, namelist, base_addr, kt->flags); switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V1: break; case KMOD_V2: st->current = lm; BZERO(lm->mod_namelist, MAX_MOD_NAMELIST); if (strlen(namelist) < MAX_MOD_NAMELIST) strcpy(lm->mod_namelist, namelist); else strncpy(lm->mod_namelist, namelist, MAX_MOD_NAMELIST-1); if (st->flags & USE_OLD_ADD_SYM) goto add_symbols; } if ((mbfd = bfd_openr(namelist, NULL)) == NULL) error(FATAL, "cannot open object file: %s\n", namelist); if (!bfd_check_format_matches(mbfd, bfd_object, &matching)) error(FATAL, "cannot determine object file format: %s\n", namelist); if (LKCD_KERNTYPES() && (file_elf_version(namelist) == EV_DWARFEXTRACT)) goto add_symbols; /* no symbols, add the debuginfo */ if (!(bfd_get_file_flags(mbfd) & HAS_SYMS)) error(FATAL, "no symbols in object file: %s\n", namelist); symcount = bfd_read_minisymbols(mbfd, FALSE, &minisyms, &size); if (symcount < 0) error(FATAL, "cannot access symbol table data: %s\n", namelist); else if (symcount == 0) error(FATAL, "no symbols in object file: %s\n", namelist); if (CRASHDEBUG(2)) { fprintf(fp, "%ld symbols found in obj file %s\n", symcount, namelist); } sort_x = bfd_make_empty_symbol(mbfd); sort_y = bfd_make_empty_symbol(mbfd); if (sort_x == NULL || sort_y == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); gnu_qsort(mbfd, minisyms, symcount, size, sort_x, sort_y); store_load_module_symbols(mbfd, FALSE, minisyms, symcount, size, base_addr, namelist); free(minisyms); bfd_close(mbfd); add_symbols: result = add_symbol_file(st->current); if (CRASHDEBUG(2)) check_for_dups(st->current); st->current = NULL; return result; } /* * Add a module's symbol file data to gdb's notion of the world. */ static int add_symbol_file(struct load_module *lm) { struct gnu_request request, *req; char buf[BUFSIZE]; int i, len; char *secname; req = &request; BZERO(req, sizeof(struct gnu_request)); if ((lm->mod_flags & MOD_KALLSYMS) && add_symbol_file_kallsyms(lm, req)) return TRUE; for (i = len = 0; i < lm->mod_sections; i++) { secname = lm->mod_section_data[i].name; if ((lm->mod_section_data[i].flags & SEC_FOUND) && (!STREQ(secname, ".text") && !STREQ(secname, ".data.percpu") && !STREQ(secname, ".data..percpu"))) { sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].offset + lm->mod_base); len += strlen(buf); } } for (i = 0; i < lm->mod_sections; i++) { secname = lm->mod_section_data[i].name; if ((lm->mod_section_data[i].flags & SEC_FOUND) && (STREQ(secname, ".data.percpu") || STREQ(secname, ".data..percpu"))) { sprintf(buf, " -s %s 0x%lx", secname, lm->mod_percpu); len += strlen(buf); } } if (pc->curcmd_flags & MOD_READNOW) lm->mod_flags |= MOD_DO_READNOW; req->command = GNU_ADD_SYMBOL_FILE; req->addr = (ulong)lm; req->buf = GETBUF(len+BUFSIZE); if (!CRASHDEBUG(1)) req->fp = pc->nullfp; st->flags |= ADD_SYMBOL_FILE; gdb_interface(req); st->flags &= ~ADD_SYMBOL_FILE; FREEBUF(req->buf); sprintf(buf, "set complaints 0"); gdb_pass_through(buf, NULL, GNU_RETURN_ON_ERROR); return(!(req->flags & GNU_COMMAND_FAILED)); } static int add_symbol_file_percpu(struct load_module *lm, struct gnu_request *req, int buflen) { char pbuf[BUFSIZE]; int i, len; char *secname; len = strlen(req->buf); for (i = 0; i < lm->mod_sections; i++) { secname = lm->mod_section_data[i].name; if ((lm->mod_section_data[i].flags & SEC_FOUND) && (STREQ(secname, ".data.percpu") || STREQ(secname, ".data..percpu"))) { sprintf(pbuf, " -s %s 0x%lx", secname, lm->mod_percpu); while ((len + strlen(pbuf)) >= buflen) { RESIZEBUF(req->buf, buflen, buflen * 2); buflen *= 2; } strcat(req->buf, pbuf); len += strlen(pbuf); } } return buflen; } /* * Gather the module section data from the in-kernel data structures. */ static int add_symbol_file_kallsyms(struct load_module *lm, struct gnu_request *req) { int len, buflen, done, nsections, retval; ulong vaddr, array_entry, attribute, owner, name, address; long name_type; char buf[BUFSIZE]; char section_name[BUFSIZE]; ulong section_vaddr; #if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) return FALSE; #endif if (!(st->flags & (MODSECT_VMASK|MODSECT_UNKNOWN))) { STRUCT_SIZE_INIT(module_sect_attr, "module_sect_attr"); MEMBER_OFFSET_INIT(module_sect_attrs, "module", "sect_attrs"); MEMBER_OFFSET_INIT(module_sect_attrs_attrs, "module_sect_attrs", "attrs"); MEMBER_OFFSET_INIT(module_sect_attrs_nsections, "module_sect_attrs", "nsections"); MEMBER_OFFSET_INIT(module_sect_attr_mattr, "module_sect_attr", "mattr"); MEMBER_OFFSET_INIT(module_sect_attr_name, "module_sect_attr", "name"); MEMBER_OFFSET_INIT(module_sect_attr_address, "module_sect_attr", "address"); MEMBER_OFFSET_INIT(module_attribute_attr, "module_attribute", "attr"); MEMBER_OFFSET_INIT(module_sect_attr_attr, "module_sect_attr", "attr"); MEMBER_OFFSET_INIT(module_sections_attrs, "module_sections", "attrs"); MEMBER_OFFSET_INIT(attribute_owner, "attribute", "owner"); if (VALID_MEMBER(module_sect_attrs_attrs) && VALID_MEMBER(module_sect_attr_mattr) && VALID_MEMBER(module_attribute_attr) && VALID_MEMBER(module_sect_attrs_nsections)) st->flags |= MODSECT_V3; else if (VALID_MEMBER(module_sect_attrs_attrs) && VALID_MEMBER(module_sect_attr_mattr) && VALID_MEMBER(module_attribute_attr)) st->flags |= MODSECT_V2; else if (VALID_MEMBER(module_sect_attr_attr) && VALID_MEMBER(module_sections_attrs)) st->flags |= MODSECT_V1; else st->flags |= MODSECT_UNKNOWN; if ((st->flags & MODSECT_UNKNOWN) || !VALID_STRUCT(module_sect_attr) || (INVALID_MEMBER(attribute_owner) && (st->flags & (MODSECT_V1|MODSECT_V2))) || INVALID_MEMBER(module_sect_attrs) || INVALID_MEMBER(module_sect_attr_name) || INVALID_MEMBER(module_sect_attr_address)) { if (CRASHDEBUG(1)) error(WARNING, "module section data structures " "unrecognized or changed\n"); st->flags &= ~(MODSECT_VMASK); st->flags |= MODSECT_UNKNOWN; return FALSE; } } else if (st->flags & MODSECT_UNKNOWN) return FALSE; if (!readmem(lm->module_struct + OFFSET(module_sect_attrs), KVADDR, &vaddr, sizeof(void *), "module.sect_attrs", RETURN_ON_ERROR|QUIET)) return FALSE; array_entry = attribute = 0; switch (st->flags & MODSECT_VMASK) { case MODSECT_V1: array_entry = vaddr + OFFSET(module_sections_attrs); nsections = UNUSED; break; case MODSECT_V2: array_entry = vaddr + OFFSET(module_sect_attrs_attrs); nsections = UNUSED; break; case MODSECT_V3: array_entry = vaddr + OFFSET(module_sect_attrs_attrs); if (!readmem(vaddr + OFFSET(module_sect_attrs_nsections), KVADDR, &nsections, sizeof(int), "module_sect_attrs.nsections", RETURN_ON_ERROR|QUIET)) return FALSE; if (CRASHDEBUG(2)) fprintf(fp, "nsections: %d\n", nsections); break; } if (CRASHDEBUG(2)) fprintf(fp, "%s:\n", lm->mod_namelist); name_type = MEMBER_TYPE("module_sect_attr", "name"); req->buf = GETBUF(buflen = 1024); retval = FALSE; for (done = FALSE; !done; array_entry += SIZE(module_sect_attr)) { switch (st->flags & MODSECT_VMASK) { case MODSECT_V1: attribute = array_entry + OFFSET(module_sect_attr_attr); break; case MODSECT_V2: case MODSECT_V3: attribute = array_entry + OFFSET(module_sect_attr_mattr) + OFFSET(module_attribute_attr); break; } if (st->flags & (MODSECT_V1|MODSECT_V2)) owner = attribute + OFFSET(attribute_owner); else owner = UNUSED; address = array_entry + OFFSET(module_sect_attr_address); switch (name_type) { case TYPE_CODE_ARRAY: name = array_entry + OFFSET(module_sect_attr_name); break; case TYPE_CODE_PTR: if (!readmem(array_entry + OFFSET(module_sect_attr_name), KVADDR, &name, sizeof(void *), "module_sect_attr.name", RETURN_ON_ERROR|QUIET)) { done = TRUE; retval = FALSE; continue; } break; default: done = TRUE; retval = FALSE; } if (CRASHDEBUG(2)) { fprintf(fp, "attribute: %lx ", attribute); if (owner == UNUSED) fprintf(fp, " owner: (not used)"); else fprintf(fp, " owner: %lx ", owner); fprintf(fp, " name: %lx ", name); fprintf(fp, " address: %lx\n", address); } if (nsections == UNUSED) { if (!readmem(owner, KVADDR, &vaddr, sizeof(void *), "attribute.owner", RETURN_ON_ERROR|QUIET)) { done = TRUE; continue; } if (lm->module_struct != vaddr) { done = TRUE; continue; } } BZERO(section_name, BUFSIZE); if (!read_string(name, section_name, 32)) { done = TRUE; retval = FALSE; continue; } if (!readmem(address, KVADDR, §ion_vaddr, sizeof(void *), "module_sect_attr.address", RETURN_ON_ERROR|QUIET)) { done = TRUE; retval = FALSE; continue; } if (CRASHDEBUG(1)) fprintf(fp, "%lx %s\n", section_vaddr, section_name); len = strlen(req->buf); if (STREQ(section_name, ".text")) { sprintf(buf, "add-symbol-file %s 0x%lx %s", lm->mod_namelist, section_vaddr, pc->curcmd_flags & MOD_READNOW ? "-readnow" : ""); while ((len + strlen(buf)) >= buflen) { RESIZEBUF(req->buf, buflen, buflen * 2); buflen *= 2; } shift_string_right(req->buf, strlen(buf)); strncpy(req->buf, buf, strlen(buf)); retval = TRUE; } else { sprintf(buf, " -s %s 0x%lx", section_name, section_vaddr); while ((len + strlen(buf)) >= buflen) { RESIZEBUF(req->buf, buflen, buflen * 2); buflen *= 2; } strcat(req->buf, buf); } if (nsections != UNUSED) { if (--nsections == 0) done = TRUE; } } if (retval == FALSE) { if (CRASHDEBUG(1)) fprintf(fp, "%s: add_symbol_file_kallsyms failed\n", lm->mod_namelist); FREEBUF(req->buf); req->buf = NULL; return FALSE; } /* * Special case for per-cpu symbols */ buflen = add_symbol_file_percpu(lm, req, buflen); lm->mod_flags |= MOD_NOPATCH; req->command = GNU_ADD_SYMBOL_FILE; req->addr = (ulong)lm; if (!CRASHDEBUG(1)) req->fp = pc->nullfp; st->flags |= ADD_SYMBOL_FILE; gdb_interface(req); st->flags &= ~ADD_SYMBOL_FILE; FREEBUF(req->buf); sprintf(buf, "set complaints 0"); gdb_pass_through(buf, NULL, GNU_RETURN_ON_ERROR); return(!(req->flags & GNU_COMMAND_FAILED)); } /* * Given a syment structure of a valid symbol, determine which * load_module (if any) it belongs to. */ static int load_module_index(struct syment *sp) { int i; ulong value; struct load_module *lm; value = sp->value; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (IN_MODULE(value, lm)) return i; if (IN_MODULE_INIT(value, lm)) return i; } return (error(FATAL, "cannot find %lx (%s) in module space\n", sp->value, sp->name)); } /* * Return the syment of a kallsyms-generated module symbol. */ static struct syment * kallsyms_module_symbol(struct load_module *lm, symbol_info *syminfo) { struct syment *sp, *spx; int cnt; if (!(lm->mod_flags & MOD_KALLSYMS)) return NULL; sp = NULL; cnt = 0; for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { if (!STREQ(spx->name, syminfo->name)) continue; if (spx->cnt) { cnt++; continue; } spx->cnt++; sp = spx; break; } if (CRASHDEBUG(2)) { if (cnt) fprintf(fp, "kallsyms [%s] %s: multiply defined\n", lm->mod_name, syminfo->name); if (sp) fprintf(fp, "kallsyms [%s] %s: %lx\n", lm->mod_name, syminfo->name, sp->value); else fprintf(fp, "kallsyms [%s] %s: NOT FOUND\n", lm->mod_name, syminfo->name); } return sp; } /* * Replace the externally-defined module symbols found in store_load_modules() * with all the text and data symbols found in the load module object file. */ static void store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, long symcount, unsigned int size, ulong base_addr, char *namelist) { int i; asymbol *store; asymbol *sym; bfd_byte *from, *fromend; symbol_info syminfo; struct syment *sp, *spx; struct load_module *lm; char name[BUFSIZE]; char *nameptr, *secname; long index; long symalloc; int found; if ((store = bfd_make_empty_symbol(bfd)) == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); st->current = lm = NULL; /* * Find out whether this module has already been loaded. Coming * out of this for loop, lm->mod_load_symtable will either be set to * a reusable symbol table, or NULL if it needs to be re-malloc'd. */ for (i = symalloc = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_base == base_addr) { symalloc = symcount + lm->mod_ext_symcnt; if (lm->mod_load_symtable && (lm->mod_symalloc < symalloc)) { free(lm->mod_load_symtable); namespace_ctl(NAMESPACE_FREE, &lm->mod_load_namespace, NULL, NULL); lm->mod_load_symtable = NULL; } break; } } if (i == st->mods_installed) error(FATAL, "cannot find module at %lx\n", base_addr); if (!lm->mod_load_symtable) { if ((lm->mod_load_symtable = (struct syment *) calloc(symalloc, sizeof(struct syment))) == NULL) error(FATAL, "module syment space malloc: %s\n", strerror(errno)); if (!namespace_ctl(NAMESPACE_INIT, &lm->mod_load_namespace, (void *)symalloc, NULL)) error(FATAL, "module name space malloc: %s\n", strerror(errno)); } else namespace_ctl(NAMESPACE_REUSE, &lm->mod_load_namespace, NULL, NULL); st->current = lm; lm->mod_symalloc = symalloc; BZERO(lm->mod_namelist, MAX_MOD_NAMELIST); if (strlen(namelist) < MAX_MOD_NAMELIST) strcpy(lm->mod_namelist, namelist); else strncpy(lm->mod_namelist, namelist, MAX_MOD_NAMELIST-1); lm->mod_text_start = lm->mod_data_start = 0; lm->mod_rodata_start = lm->mod_bss_start = 0; lm->mod_load_symcnt = 0; lm->mod_sections = 0; for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) spx->cnt = 0; sp = lm->mod_load_symtable; if (!(lm->mod_section_data = (struct mod_section_data *) malloc(sizeof(struct mod_section_data) * (bfd->section_count+1)))) error(FATAL, "module section data array malloc: %s\n", strerror(errno)); bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS); if (kt->flags & KMOD_V1) calculate_load_order_v1(lm, bfd); else calculate_load_order_v2(lm, bfd, dynamic, minisyms, symcount, size); from = (bfd_byte *) minisyms; fromend = from + symcount * size; for (; from < fromend; from += size) { if ((sym = bfd_minisymbol_to_symbol(bfd, dynamic, from, store)) == NULL) error(FATAL, "bfd_minisymbol_to_symbol() failed\n"); bfd_get_symbol_info(bfd, sym, &syminfo); secname = (char *)bfd_get_section_name(bfd, sym->section); found = 0; if (kt->flags & KMOD_V1) { switch (syminfo.type) { case 'b': case 'B': if (CRASHDEBUG(2)) fprintf(fp, "%08lx (%c) [%s] %s\n", (ulong)syminfo.value, syminfo.type, secname, syminfo.name); if (!lm->mod_bss_start) break; syminfo.value += lm->mod_bss_start; found = 1; break; case 'd': case 'D': if (CRASHDEBUG(2)) fprintf(fp, "%08lx (%c) [%s] %s\n", (ulong)syminfo.value, syminfo.type, secname, syminfo.name); if (STREQ(secname, ".rodata")) { if (!lm->mod_rodata_start) break; syminfo.value += lm->mod_rodata_start; } else { if (!lm->mod_data_start) break; syminfo.value += lm->mod_data_start; } found = 1; break; case 't': case 'T': if (CRASHDEBUG(2)) fprintf(fp, "%08lx (%c) [%s] %s\n", (ulong)syminfo.value, syminfo.type, secname, syminfo.name); if (! lm->mod_text_start) { break; } if ((st->flags & INSMOD_BUILTIN) && (STREQ(name, "init_module") || STREQ(name, "cleanup_module"))) break; syminfo.value += lm->mod_text_start; found = 1; break; default: break; } } else { /* Match the section it came in. */ for (i = 0; i < lm->mod_sections; i++) { if (STREQ(lm->mod_section_data[i].name, secname) && (lm->mod_section_data[i].flags & SEC_FOUND)) { break; } } if (i < lm->mod_sections) { if (CRASHDEBUG(2)) fprintf(fp, "%08lx (%c) [%s] %s\n", (ulong)syminfo.value, syminfo.type, secname, syminfo.name); if ((st->flags & INSMOD_BUILTIN) && (STREQ(name, "init_module") || STREQ(name, "cleanup_module"))) found = FALSE; else if (syminfo.name[0] == '.') found = FALSE; else if ((spx = kallsyms_module_symbol(lm, &syminfo))) { syminfo.value = spx->value; found = TRUE; } else if (lm->mod_percpu && (STREQ(secname, ".data.percpu") || STREQ(secname, ".data..percpu"))) { syminfo.value += lm->mod_percpu; found = TRUE; } else { syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; found = TRUE; } } } if (found) { strcpy(name, syminfo.name); strip_module_symbol_end(name); strip_symbol_end(name, NULL); if (machdep->verify_symbol(name, syminfo.value, syminfo.type)) { sp->value = syminfo.value; sp->type = syminfo.type; sp->flags |= MODULE_SYMBOL; namespace_ctl(NAMESPACE_INSTALL, &lm->mod_load_namespace, sp, name); if (CRASHDEBUG(2)) fprintf(fp, "installing %c %08lx %s\n", syminfo.type, sp->value, name); sp++; lm->mod_load_symcnt++; } } } lm->mod_load_symend = &lm->mod_load_symtable[lm->mod_load_symcnt]; /* * Merge in any externals that didn't show up in the four * syminfo data types accepted above, plus the two pseudo symbols. * Note that the new syment name pointers haven't been resolved yet. */ for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { found = FALSE; for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { index = (long)sp->name; nameptr = &lm->mod_load_namespace.address[index]; if (STREQ(spx->name, nameptr)) { found = TRUE; if (spx->value == sp->value) { if (CRASHDEBUG(2)) fprintf(fp, "%s: %s matches!\n", lm->mod_name, nameptr); } else { if (CRASHDEBUG(2)) fprintf(fp, "[%s] %s: %lx != extern'd value: %lx\n", lm->mod_name, nameptr, sp->value, spx->value); } break; } } if (!found) { if (CRASHDEBUG(2)) fprintf(fp, "append ext %s (%lx)\n", spx->name, spx->value); /* append it here... */ namespace_ctl(NAMESPACE_INSTALL, &lm->mod_load_namespace, lm->mod_load_symend, spx->name); lm->mod_load_symend->value = spx->value; lm->mod_load_symend->type = spx->type; lm->mod_load_symend->flags |= MODULE_SYMBOL; lm->mod_load_symend++; lm->mod_load_symcnt++; } } /* * Append helpful pseudo symbols about found out sections. * Use 'S' as its type which is never seen in existing symbols. */ for (i = 0; (pc->curcmd_flags & MOD_SECTIONS) && (i < lm->mod_sections); i++) { if (!(lm->mod_section_data[i].flags & SEC_FOUND)) continue; /* Section start */ lm->mod_load_symend->value = lm->mod_base + lm->mod_section_data[i].offset; lm->mod_load_symend->type = 'S'; lm->mod_load_symend->flags |= MODULE_SYMBOL; sprintf(name, "_MODULE_SECTION_START [%s]", lm->mod_section_data[i].name); namespace_ctl(NAMESPACE_INSTALL, &lm->mod_load_namespace, lm->mod_load_symend, name); lm->mod_load_symend++; lm->mod_load_symcnt++; /* Section end */ lm->mod_load_symend->value = lm->mod_base + lm->mod_section_data[i].offset + lm->mod_section_data[i].size; lm->mod_load_symend->type = 'S'; lm->mod_load_symend->flags |= MODULE_SYMBOL; sprintf(name, "_MODULE_SECTION_END [%s]", lm->mod_section_data[i].name); namespace_ctl(NAMESPACE_INSTALL, &lm->mod_load_namespace, lm->mod_load_symend, name); lm->mod_load_symend++; lm->mod_load_symcnt++; } namespace_ctl(NAMESPACE_COMPLETE, &lm->mod_load_namespace, lm->mod_load_symtable, lm->mod_load_symend); qsort(lm->mod_load_symtable, lm->mod_load_symcnt, sizeof(struct syment), compare_syms); lm->mod_load_symend--; if (!MODULE_END(lm->mod_load_symend) && !IN_MODULE_PERCPU(lm->mod_load_symend->value, lm)) error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n", lm->mod_name, lm->mod_load_symend->name, lm->mod_name); lm->mod_symtable = lm->mod_load_symtable; lm->mod_symend = lm->mod_load_symend; lm->mod_flags &= ~MOD_EXT_SYMS; lm->mod_flags |= MOD_LOAD_SYMS; st->flags |= LOAD_MODULE_SYMS; } /* * Delete a load module's symbol table. If base_addr is NULL, delete the * complete list of modules. */ void delete_load_module(ulong base_addr) { int i; struct load_module *lm; struct gnu_request request, *req; req = &request; BZERO(req, sizeof(struct gnu_request)); req->command = GNU_DELETE_SYMBOL_FILE; if (base_addr == ALL_MODULES) { for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_flags & MOD_LOAD_SYMS) { req->name = lm->mod_namelist; gdb_interface(req); } if (lm->mod_load_symtable) { free(lm->mod_load_symtable); namespace_ctl(NAMESPACE_FREE, &lm->mod_load_namespace, NULL, NULL); } if (lm->mod_flags & MOD_REMOTE) unlink_module(lm); lm->mod_symtable = lm->mod_ext_symtable; lm->mod_symend = lm->mod_ext_symend; lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); lm->mod_flags |= MOD_EXT_SYMS; lm->mod_load_symtable = NULL; lm->mod_load_symend = NULL; lm->mod_namelist[0] = NULLCHAR; lm->mod_load_symcnt = lm->mod_symalloc = 0; lm->mod_text_start = lm->mod_data_start = 0; lm->mod_bss_start = lm->mod_rodata_start = 0; lm->mod_sections = 0; lm->mod_percpu_size = 0; if (lm->mod_section_data) free(lm->mod_section_data); lm->mod_section_data = (struct mod_section_data *)0; } st->flags &= ~LOAD_MODULE_SYMS; return; } st->flags &= ~LOAD_MODULE_SYMS; /* restored below (if any found) */ for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (lm->mod_base == base_addr) { if (lm->mod_flags & MOD_LOAD_SYMS) { req->name = lm->mod_namelist; gdb_interface(req); } if (lm->mod_load_symtable) { free(lm->mod_load_symtable); namespace_ctl(NAMESPACE_FREE, &lm->mod_load_namespace, NULL, NULL); } if (lm->mod_flags & MOD_REMOTE) unlink_module(lm); lm->mod_symtable = lm->mod_ext_symtable; lm->mod_symend = lm->mod_ext_symend; lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); lm->mod_flags |= MOD_EXT_SYMS; lm->mod_load_symtable = NULL; lm->mod_load_symend = NULL; lm->mod_namelist[0] = NULLCHAR; lm->mod_load_symcnt = lm->mod_symalloc = 0; lm->mod_text_start = lm->mod_data_start = 0; lm->mod_bss_start = lm->mod_rodata_start = 0; lm->mod_percpu_size = 0; lm->mod_sections = 0; if (lm->mod_section_data) free(lm->mod_section_data); lm->mod_section_data = (struct mod_section_data *)0; } else if (lm->mod_flags & MOD_LOAD_SYMS) st->flags |= LOAD_MODULE_SYMS; } } /* * Check whether a string is the name of a module. If requested, return * the base address of the module. */ int is_module_name(char *s, ulong *addr, struct load_module **lmp) { int i; struct load_module *lm; if (NO_MODULES()) return FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (STREQ(s, lm->mod_name)) { if (addr) *addr = lm->mod_base; if (lmp) *lmp = lm; return TRUE; } } return FALSE; } /* * Check whether an value is the base address of a module. If requested, * return the module name. */ int is_module_address(ulong check_addr, char *module_name) { int i; struct load_module *lm; if (NO_MODULES()) return FALSE; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (check_addr == lm->mod_base) { if (module_name) strcpy(module_name, lm->mod_name); return TRUE; } } return FALSE; } /* * In a MOD_EXT_SYMBOLS module, find a rough estimate as to where the * .rodata section starts. The value will be used by is_kernel_text() * when symbols are not loaded. */ static void find_mod_etext(struct load_module *lm) { ulong start, end; char *modbuf; ulong maxchunk, alloc; long offset = 0; start = roundup(lm->mod_size_of_struct, sizeof(long)) + lm->mod_base; end = lm->mod_base + lm->mod_size; maxchunk = MIN(end-start, KILOBYTES(32)); modbuf = GETBUF(maxchunk); while (start < end) { alloc = MIN(maxchunk, end-start); readmem(start, KVADDR, modbuf, alloc, "module rodata search chunk", FAULT_ON_ERROR); if ((offset = rodata_search((ulong *)modbuf, alloc)) >= 0) break; start += alloc; } FREEBUF(modbuf); if (offset >= 0) lm->mod_etext_guess = start + offset; else lm->mod_etext_guess = end; } #define ASCII_WORD_COUNT (16/sizeof(ulong)) static long rodata_search(ulong *buf, ulong size) { int i, acnt, words; long offset; ulong *wordptr; words = size/sizeof(ulong); wordptr = buf; for (i = acnt = 0, offset = -1; i < words; i++, wordptr++) { if (ascii_long(*wordptr)) { if (acnt++ == 0) offset = i * sizeof(ulong); } else { acnt = 0; offset = -1; } if (acnt == ASCII_WORD_COUNT) break; } return offset; } static int ascii_long(ulong word) { int i, cnt; unsigned char c; for (i = cnt = 0; i < sizeof(ulong); i++) { c = (unsigned char)((word >> (i*BITS_PER_BYTE)) & 0xff); if ((c >= ' ') && (c < 0x7f)) cnt++; } return (cnt == sizeof(ulong)); } /* * Symbol sorting routines adapted from binutils/nm.c */ /* nm.c -- Describe symbol table of a rel file. Copyright 1991, 92, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static bfd *gnu_sort_bfd; static asymbol *gnu_sort_x; static asymbol *gnu_sort_y; #define valueof(x) ((x)->section->vma + (x)->value) static int non_numeric_forward(const void *P_x, const void *P_y) { asymbol *x, *y; const char *xn, *yn; x = bfd_minisymbol_to_symbol(gnu_sort_bfd, FALSE, P_x, gnu_sort_x); y = bfd_minisymbol_to_symbol(gnu_sort_bfd, FALSE, P_y, gnu_sort_y); if (x == NULL || y == NULL) error(FATAL, "bfd_minisymbol_to_symbol failed\n"); xn = bfd_asymbol_name(x); yn = bfd_asymbol_name(y); return ((xn == NULL) ? ((yn == NULL) ? 0 : -1) : ((yn == NULL) ? 1 : strcmp (xn, yn))); } static int numeric_forward(const void *P_x, const void *P_y) { asymbol *x, *y; asection *xs, *ys; x = bfd_minisymbol_to_symbol(gnu_sort_bfd, FALSE, P_x, gnu_sort_x); y = bfd_minisymbol_to_symbol(gnu_sort_bfd, FALSE, P_y, gnu_sort_y); if (x == NULL || y == NULL) error(FATAL, "bfd_minisymbol_to_symbol failed\n"); xs = bfd_get_section(x); ys = bfd_get_section(y); if (bfd_is_und_section(xs)) { if (!bfd_is_und_section(ys)) return -1; } else if (bfd_is_und_section (ys)) return 1; else if (valueof (x) != valueof (y)) return valueof (x) < valueof (y) ? -1 : 1; return non_numeric_forward(P_x, P_y); } static void gnu_qsort(bfd *bfd, void *minisyms, long symcount, unsigned int size, asymbol *x, asymbol *y) { gnu_sort_bfd = bfd; gnu_sort_x = x; gnu_sort_y = y; qsort(minisyms, symcount, size, numeric_forward); } /* * Keep a stash of commonly-accessed text locations checked by the * back_trace code. The saved values unsigned 32-bit values. * The same routine is used to store and query, based upon whether * the passed-in value and valptr args are non-zero. */ #define TEXT_CACHE (50) #define MAX_TEXT_CACHE (TEXT_CACHE*4) struct text_cache_entry { ulong vaddr; uint32_t value; }; static struct text_cache { int index; int entries; ulong hits; ulong refs; struct text_cache_entry *cache; } text_cache = { 0 }; /* * Cache the contents of 32-bit text addresses. If "value" is set, the purpose * is to cache it. If "valptr" is set, a query is being made for the text * address. */ int text_value_cache(ulong vaddr, uint32_t value, uint32_t *valptr) { int i; struct text_cache *tc; if (!is_kernel_text(vaddr)) return FALSE; tc = &text_cache; if (!tc->cache) { if (!(tc->cache = (struct text_cache_entry *) malloc(sizeof(struct text_cache_entry) * TEXT_CACHE))) return FALSE; BZERO(tc->cache, sizeof(struct text_cache_entry) * TEXT_CACHE); tc->index = 0; tc->entries = TEXT_CACHE; } if (value) { for (i = 0; i < tc->entries; i++) { if (tc->cache[i].vaddr == vaddr) return TRUE; } i = tc->index; tc->cache[i].vaddr = vaddr; tc->cache[i].value = value; tc->index++; if (tc->index == MAX_TEXT_CACHE) { tc->index = 0; } else if (tc->index == tc->entries) { struct text_cache_entry *old_cache; old_cache = tc->cache; if ((tc->cache = (struct text_cache_entry *) realloc(old_cache, sizeof(struct text_cache_entry) * (TEXT_CACHE+tc->entries)))) { BZERO(&tc->cache[tc->index], sizeof(struct text_cache_entry) * TEXT_CACHE); tc->entries += TEXT_CACHE; } else { tc->cache = old_cache; tc->index = 0; } } return TRUE; } if (valptr) { tc->refs++; for (i = 0; i < tc->entries; i++) { if (!tc->cache[i].vaddr) return FALSE; if (tc->cache[i].vaddr == vaddr) { *valptr = tc->cache[i].value; tc->hits++; return TRUE; } } } return FALSE; } /* * The gdb disassembler reads text memory byte-by-byte, so this routine * acts as a front-end to the 32-bit (4-byte) text storage. */ int text_value_cache_byte(ulong vaddr, unsigned char *valptr) { int i; int shift; struct text_cache *tc; ulong valtmp; if (!is_kernel_text(vaddr)) return FALSE; tc = &text_cache; tc->refs++; for (i = 0; i < tc->entries; i++) { if (!tc->cache[i].vaddr) return FALSE; if ((vaddr >= tc->cache[i].vaddr) && (vaddr < (tc->cache[i].vaddr+SIZEOF_32BIT))) { valtmp = tc->cache[i].value; shift = (vaddr - tc->cache[i].vaddr) * 8; valtmp >>= shift; *valptr = valtmp & 0xff; tc->hits++; return TRUE; } } return FALSE; } void dump_text_value_cache(int verbose) { int i; struct syment *sp; ulong offset; struct text_cache *tc; tc = &text_cache; if (!verbose) { if (!tc->refs || !tc->cache) return; fprintf(stderr, " text hit rate: %2ld%% (%ld of %ld)\n", (tc->hits * 100)/tc->refs, (ulong)tc->hits, (ulong)tc->refs); return; } for (i = 0; tc->cache && (i < tc->entries); i++) { if (!tc->cache[i].vaddr) break; fprintf(fp, "[%2d]: %lx %08x ", i, tc->cache[i].vaddr, tc->cache[i].value); if ((sp = value_search(tc->cache[i].vaddr, &offset))) { fprintf(fp, "(%s+", sp->name); switch (pc->output_radix) { case 10: fprintf(fp, "%ld)", offset); break; case 16: fprintf(fp, "%lx)", offset); break; } } fprintf(fp, "\n"); } fprintf(fp, "text_cache entries: %d index: %d hit rate: %ld%% (%ld of %ld)\n", tc->entries, tc->index, (tc->hits * 100)/(tc->refs ? tc->refs : 1), tc->hits, tc->refs); } void clear_text_value_cache(void) { int i; struct text_cache *tc; tc = &text_cache; tc->index = 0; for (i = 0; tc->cache && (i < tc->entries); i++) { tc->cache[i].vaddr = 0; tc->cache[i].value = 0; } } /* * If a System.map file or a debug kernel was specified, the name hash * has been filled -- so sync up gdb's notion of symbol values with * the local values, taking dups into account. Given that gdb's * minimal_symbol dump is sorted by value, shortcut the get_syment_array() * call if the sp after the last one found is associated with the * new one. */ #define last_sp addr2 int patch_kernel_symbol(struct gnu_request *req) { int i, c; struct syment *sp_array[1000], *sp; if (req->name == PATCH_KERNEL_SYMBOLS_START) { if (kt->flags & RELOC_FORCE) error(WARNING, "\nkernel relocated [%ldMB]: patching %ld gdb minimal_symbol values\n", kt->relocate >> 20, st->symcnt); fprintf(fp, (pc->flags & SILENT) || !(pc->flags & TTY) ? "" : "\nplease wait... (patching %ld gdb minimal_symbol values) ", st->symcnt); fflush(fp); req->count = 0; req->length = 0; req->last_sp = 0; return TRUE; } if (req->name == PATCH_KERNEL_SYMBOLS_STOP) { fprintf(fp, (pc->flags & SILENT) || !(pc->flags & TTY) ? "" : "\r \r"); st->flags |= GDB_SYMS_PATCHED; return TRUE; } if (!req->name || !req->addr) return FALSE; sp = (struct syment *)req->last_sp; sp += sp ? 1 : 0; if (sp && (sp->cnt == 1) && !(sp->flags & SYMBOL_NAME_USED) && STREQ(sp->name, req->name)) { *((ulong *)req->addr) = sp->value; sp->flags |= SYMBOL_NAME_USED; req->last_sp = (ulong)sp; } else { switch (c = get_syment_array(req->name, sp_array, 1000)) { case 0: req->last_sp = 0; return TRUE; case 1: *((ulong *)req->addr) = sp_array[0]->value; sp_array[0]->flags |= SYMBOL_NAME_USED; req->last_sp = (ulong)sp_array[0]; break; default: for (i = 0; i < c; i++) { if (sp_array[i]->flags & SYMBOL_NAME_USED) continue; *((ulong *)req->addr) = sp_array[i]->value; sp_array[i]->flags |= SYMBOL_NAME_USED; req->last_sp = (ulong)sp_array[i]; break; } break; } } return TRUE; } #undef last_sp /* * If the first offset/size is bogus, then use the second if it's OK. * But if both are bogus, then check whether we're debugging datatypes, * and act accordingly. */ long OFFSET_option(long offset1, long offset2, char *func, char *file, int line, char *item1, char *item2) { char errmsg[BUFSIZE]; if (offset1 >= 0) return offset1; if (offset2 >= 0) return offset2; if (pc->flags & DATADEBUG) { void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid (optional) structure member offsets: %s or %s", item1, item2); datatype_error(retaddr, errmsg, func, file, line); } return -1; } long SIZE_option(long size1, long size2, char *func, char *file, int line, char *item1, char *item2) { char errmsg[BUFSIZE]; if (size1 >= 0) return size1; if (size2 >= 0) return size2; if (pc->flags & DATADEBUG) { void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid (optional) structure sizes: %s or %s", item1, item2); datatype_error(retaddr, errmsg, func, file, line); } return -1; } /* * Do the work of the former OFFSET() and SIZE() macros. * * For now verification that the offset is legitimate is only done * if the "--data_debug" command line option was used. There * could still be constructs like "OFFSET(x) >= 0" in the current * code, or in user extensions. Perhaps there should be an option * to turn it off instead? */ long OFFSET_verify(long offset, char *func, char *file, int line, char *item) { char errmsg[BUFSIZE]; if (!(pc->flags & DATADEBUG)) return offset; if (offset < 0) { void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid structure member offset: %s", item); datatype_error(retaddr, errmsg, func, file, line); } return offset; } long SIZE_verify(long size, char *func, char *file, int line, char *item) { char errmsg[BUFSIZE]; if (!(pc->flags & DATADEBUG)) return size; if (size < 0) { void *retaddr[NUMBER_STACKFRAMES] = { 0 }; SAVE_RETURN_ADDRESS(retaddr); sprintf(errmsg, "invalid structure size: %s", item); datatype_error(retaddr, errmsg, func, file, line); } return size; } /* * Perform the common datatype error handling. */ static void datatype_error(void **retaddr, char *errmsg, char *func, char *file, int line) { char buf[BUFSIZE]; int fd; fprintf(stderr, "\n%s: %s\n", pc->curcmd, errmsg); fprintf(stderr, "%s FILE: %s LINE: %d FUNCTION: %s()\n\n", space(strlen(pc->curcmd)), file, line, func); fflush(stderr); dump_trace(retaddr); if (pc->flags & TTY) { if ((fd = open("/dev/tty", O_RDONLY)) >= 0) { tcsetattr(fd, TCSANOW, &pc->termios_orig); close(fd); } } if (pc->flags & DROP_CORE) drop_core("DROP_CORE flag set: forcing a segmentation fault\n"); if (CRASHDEBUG(1)) gdb_readnow_warning(); if (pc->flags & RUNTIME) { sprintf(buf, "%s\n%s FILE: %s LINE: %d FUNCTION: %s()\n", errmsg, space(strlen(pc->curcmd)), file, line, func); error(FATAL, "%s\n", buf); } exit(1); } /* * Dump a trace leading to the improper datatype usage. */ void dump_trace(void **retaddr) { int i, c; char *thisfile; char *arglist[MAXARGS]; char buf[BUFSIZE]; FILE *pipe; ulong vaddr, size, lookfor; ulong last_vaddr, last_size; char symbol[BUFSIZE]; const char *nm_call; fflush(fp); fflush(stdout); fflush(pc->stdpipe); thisfile = get_thisfile(); fprintf(stderr, "[%s] error trace: ", thisfile); for (i = (NUMBER_STACKFRAMES-1); i >= 0; i--) { if (retaddr[i]) fprintf(stderr, "%s%lx%s", i == 3 ? "" : "=> ", (ulong)retaddr[i], i == 0 ? "\n" : " "); } fflush(stderr); if (!file_exists("/usr/bin/nm", NULL)) { fprintf(stderr, "crash: /usr/bin/nm: no such file\n"); return; } if (is_binary_stripped(thisfile)) nm_call = "/usr/bin/nm -DSBn %s"; else nm_call = "/usr/bin/nm -BSn %s"; last_size = 0; for (i = 0; i < NUMBER_STACKFRAMES; i++) { if (!(lookfor = (ulong)retaddr[i])) continue; sprintf(buf, nm_call, thisfile); if (!(pipe = popen(buf, "r"))) { perror("pipe"); break; } last_vaddr = 0; BZERO(symbol, BUFSIZE); while (fgets(buf, BUFSIZE, pipe)) { c = parse_line(strip_linefeeds(buf), arglist); if (c != 4) continue; vaddr = htol(arglist[0], FAULT_ON_ERROR, NULL); size = htol(arglist[1], FAULT_ON_ERROR, NULL); if (vaddr > lookfor) { if ((lookfor - last_vaddr) > last_size) fprintf(stderr, "%s %lx: (undetermined)\n", i == 0 ? "\n" : "", lookfor); else fprintf(stderr, "%s %lx: %s+%ld\n", i == 0 ? "\n" : "", lookfor, symbol, lookfor-last_vaddr); break; } strcpy(symbol, arglist[3]); last_vaddr = vaddr; last_size = size; } pclose(pipe); } fprintf(stderr, "\n"); } /* * Try best to determine which executable this is. */ static char * get_thisfile(void) { char *buf1; char buf2[BUFSIZE]; char *tok, *path; if (pc->program_path[0] == '.' || pc->program_path[0] == '/') return pc->program_path; if ((path = getenv("PATH"))) { strcpy(buf2, path); } else return pc->program_path; buf1 = GETBUF(BUFSIZE); tok = strtok(buf2, ":"); while (tok) { sprintf(buf1, "%s/%s", tok, pc->program_name); if (file_exists(buf1, NULL) && is_elf_file(buf1)) { return buf1; } tok = strtok(NULL, ":"); } return pc->program_path; } /* * Check whether an address fits into any existing init_module() functions, * and if so, return the load_module. */ struct load_module * init_module_function(ulong vaddr) { int i; struct load_module *lm; if (((kt->flags & (KMOD_V1|KMOD_V2)) == KMOD_V1) || INVALID_MEMBER(module_init_text_size) || INVALID_MEMBER(module_module_init)) return NULL; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; if (!lm->mod_init_module_ptr || !lm->mod_init_text_size) continue; if ((vaddr >= lm->mod_init_module_ptr) && (vaddr < (lm->mod_init_module_ptr+lm->mod_init_text_size)) && accessible(vaddr)) return lm; } return NULL; }