From 11f5e8bfef1c2e0432717f7aab71089cf8a878ca Mon Sep 17 00:00:00 2001 From: Packit Date: Sep 09 2020 11:59:12 +0000 Subject: Apply patch github_b97e7fd4e826_to_8b50d94ada21.patch patch_name: github_b97e7fd4e826_to_8b50d94ada21.patch present_in_specfile: true --- diff --git a/defs.h b/defs.h index d0b021f..00971ba 100644 --- a/defs.h +++ b/defs.h @@ -2697,6 +2697,7 @@ struct symbol_table_data { ulong pti_init_vmlinux; ulong kaiser_init_vmlinux; int kernel_symbol_type; + ulong linux_banner_vmlinux; }; /* flags for st */ diff --git a/defs.hgithub_b97e7fd4e826_to_8b50d94ada21.patch b/defs.hgithub_b97e7fd4e826_to_8b50d94ada21.patch new file mode 100644 index 0000000..d0b021f --- /dev/null +++ b/defs.hgithub_b97e7fd4e826_to_8b50d94ada21.patch @@ -0,0 +1,7010 @@ +/* defs.h - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. + * Copyright (C) 2002-2020 David Anderson + * Copyright (C) 2002-2020 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002 Silicon Graphics, Inc. + * + * 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. + */ + +#ifndef GDB_COMMON + +#include +#include +#include +#include +#include +#include +#include +#undef basename +#if !defined(__USE_GNU) +#define __USE_GNU +#include +#undef __USE_GNU +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* backtrace() */ +#include +#ifdef LZO +#include +#endif +#ifdef SNAPPY +#include +#endif + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#undef TRUE +#undef FALSE + +#define TRUE (1) +#define FALSE (0) +#define STR(x) #x +#ifndef offsetof +# define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER) +#endif + +#if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \ + !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \ + !defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(SPARC64) +#ifdef __alpha__ +#define ALPHA +#endif +#ifdef __i386__ +#define X86 +#endif +#ifdef __powerpc64__ +#define PPC64 +#else +#ifdef __powerpc__ +#define PPC +#endif +#endif +#ifdef __ia64__ +#define IA64 +#endif +#ifdef __s390__ +#define S390 +#endif +#ifdef __s390x__ +#define S390X +#endif +#ifdef __x86_64__ +#define X86_64 +#endif +#ifdef __arm__ +#define ARM +#endif +#ifdef __aarch64__ +#define ARM64 +#endif +#ifdef __mipsel__ +#define MIPS +#endif +#ifdef __sparc_v9__ +#define SPARC64 +#endif +#endif + +#ifdef X86 +#define NR_CPUS (256) +#endif +#ifdef X86_64 +#define NR_CPUS (8192) +#endif +#ifdef ALPHA +#define NR_CPUS (64) +#endif +#ifdef PPC +#define NR_CPUS (32) +#endif +#ifdef IA64 +#define NR_CPUS (4096) +#endif +#ifdef PPC64 +#define NR_CPUS (2048) +#endif +#ifdef S390 +#define NR_CPUS (512) +#endif +#ifdef S390X +#define NR_CPUS (512) +#endif +#ifdef ARM +#define NR_CPUS (32) +#endif +#ifdef ARM64 +#define NR_CPUS (4096) /* TBD */ +#endif +#ifdef MIPS +#define NR_CPUS (32) +#endif +#ifdef SPARC64 +#define NR_CPUS (4096) +#endif + +#define NR_DEVICE_DUMPS (64) + +/* Some architectures require memory accesses to be aligned. */ +#if defined(SPARC64) +#define NEED_ALIGNED_MEM_ACCESS +#endif + +#define BUFSIZE (1500) +#define NULLCHAR ('\0') + +#define MAXARGS (100) /* max number of arguments to one function */ +#define MAXARGLEN (40) /* max length of argument */ + +#define HIST_BLKSIZE (4096) + +static inline int string_exists(char *s) { return (s ? TRUE : FALSE); } +#define STREQ(A, B) (string_exists((char *)A) && string_exists((char *)B) && \ + (strcmp((char *)(A), (char *)(B)) == 0)) +#define STRNEQ(A, B) (string_exists((char *)A) && string_exists((char *)B) && \ + (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) +#define BZERO(S, N) (memset(S, NULLCHAR, N)) +#define BCOPY(S, D, C) (memcpy(D, S, C)) +#define BNEG(S, N) (memset(S, 0xff, N)) +#define BEEP() fprintf(stderr, "%c", 0x7) +#define LASTCHAR(s) (s[strlen(s)-1]) +#define FIRSTCHAR(s) (s[0]) +#define QUOTED_STRING(s) ((FIRSTCHAR(s) == '"') && (LASTCHAR(s) == '"')) +#define SINGLE_QUOTED_STRING(s) ((FIRSTCHAR(s) == '\'') && (LASTCHAR(s) == '\'')) +#define PATHEQ(A, B) ((A) && (B) && (pathcmp((char *)(A), (char *)(B)) == 0)) + +#ifdef roundup +#undef roundup +#endif +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +typedef uint64_t physaddr_t; + +#define PADDR_NOT_AVAILABLE (0x1ULL) +#define KCORE_USE_VADDR (-1ULL) + +typedef unsigned long long int ulonglong; +struct number_option { + ulong num; + ulonglong ll_num; + ulong retflags; +}; + +/* + * program_context flags + */ +#define LIVE_SYSTEM (0x1ULL) +#define TTY (0x2ULL) +#define RUNTIME (0x4ULL) +#define IN_FOREACH (0x8ULL) +#define MCLXCD (0x10ULL) +#define CMDLINE_IFILE (0x20ULL) +#define MFD_RDWR (0x40ULL) +#define KVMDUMP (0x80ULL) +#define SILENT (0x100ULL) +#define SADUMP (0x200ULL) +#define HASH (0x400ULL) +#define SCROLL (0x800ULL) +#define NO_CONSOLE (0x1000ULL) +#define RUNTIME_IFILE (0x2000ULL) +#define DROP_CORE (0x4000ULL) +#define LKCD (0x8000ULL) +#define GDB_INIT (0x10000ULL) +#define IN_GDB (0x20000ULL) +#define RCLOCAL_IFILE (0x40000ULL) +#define RCHOME_IFILE (0x80000ULL) +#define VMWARE_VMSS (0x100000ULL) +#define READLINE (0x200000ULL) +#define _SIGINT_ (0x400000ULL) +#define IN_RESTART (0x800000ULL) +#define KERNEL_DEBUG_QUERY (0x1000000ULL) +#define DEVMEM (0x2000000ULL) +#define REM_LIVE_SYSTEM (0x4000000ULL) +#define NAMELIST_LOCAL (0x8000000ULL) +#define LIVE_RAMDUMP (0x10000000ULL) +#define NAMELIST_SAVED (0x20000000ULL) +#define DUMPFILE_SAVED (0x40000000ULL) +#define UNLINK_NAMELIST (0x80000000ULL) +#define NAMELIST_UNLINKED (0x100000000ULL) +#define REM_MCLXCD (0x200000000ULL) +#define REM_LKCD (0x400000000ULL) +#define NAMELIST_NO_GZIP (0x800000000ULL) +#define UNLINK_MODULES (0x1000000000ULL) +#define S390D (0x2000000000ULL) +#define REM_S390D (0x4000000000ULL) +#define SYSRQ (0x8000000000ULL) +#define KDUMP (0x10000000000ULL) +#define NETDUMP (0x20000000000ULL) +#define REM_NETDUMP (0x40000000000ULL) +#define SYSMAP (0x80000000000ULL) +#define SYSMAP_ARG (0x100000000000ULL) +#define MEMMOD (0x200000000000ULL) +#define MODPRELOAD (0x400000000000ULL) +#define DISKDUMP (0x800000000000ULL) +#define DATADEBUG (0x1000000000000ULL) +#define FINDKERNEL (0x2000000000000ULL) +#define VERSION_QUERY (0x4000000000000ULL) +#define READNOW (0x8000000000000ULL) +#define NOCRASHRC (0x10000000000000ULL) +#define INIT_IFILE (0x20000000000000ULL) +#define XENDUMP (0x40000000000000ULL) +#define XEN_HYPER (0x80000000000000ULL) +#define XEN_CORE (0x100000000000000ULL) +#define PLEASE_WAIT (0x200000000000000ULL) +#define IFILE_ERROR (0x400000000000000ULL) +#define KERNTYPES (0x800000000000000ULL) +#define MINIMAL_MODE (0x1000000000000000ULL) +#define CRASHBUILTIN (0x2000000000000000ULL) +#define PRELOAD_EXTENSIONS \ + (0x4000000000000000ULL) +#define PROC_KCORE (0x8000000000000000ULL) + +#define ACTIVE() (pc->flags & LIVE_SYSTEM) +#define LOCAL_ACTIVE() ((pc->flags & (LIVE_SYSTEM|LIVE_RAMDUMP)) == LIVE_SYSTEM) +#define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) +#define LIVE() (pc->flags2 & LIVE_DUMP || pc->flags & LIVE_SYSTEM) +#define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP|CRASHBUILTIN|KVMDUMP|PROC_KCORE|SADUMP|VMWARE_VMSS|LIVE_RAMDUMP) +#define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP|SADUMP|VMWARE_VMSS|LIVE_RAMDUMP) +#define REMOTE() (pc->flags2 & REMOTE_DAEMON) +#define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) +#define REMOTE_DUMPFILE() \ + (pc->flags & (REM_NETDUMP|REM_MCLXCD|REM_LKCD|REM_S390D)) +#define REMOTE_MEMSRC() (REMOTE_ACTIVE() || REMOTE_PAUSED() || REMOTE_DUMPFILE()) +#define LKCD_DUMPFILE() (pc->flags & (LKCD|REM_LKCD)) +#define NETDUMP_DUMPFILE() (pc->flags & (NETDUMP|REM_NETDUMP)) +#define DISKDUMP_DUMPFILE() (pc->flags & DISKDUMP) +#define KDUMP_DUMPFILE() (pc->flags & KDUMP) +#define XENDUMP_DUMPFILE() (pc->flags & XENDUMP) +#define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) +#define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) +#define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) +#define LKCD_KERNTYPES() (pc->flags & KERNTYPES) +#define KVMDUMP_DUMPFILE() (pc->flags & KVMDUMP) +#define SADUMP_DUMPFILE() (pc->flags & SADUMP) +#define VMSS_DUMPFILE() (pc->flags & VMWARE_VMSS) +#define QEMU_MEM_DUMP_NO_VMCOREINFO() \ + ((pc->flags2 & (QEMU_MEM_DUMP_ELF|QEMU_MEM_DUMP_COMPRESSED)) && !(pc->flags2 & VMCOREINFO)) + + +#define NETDUMP_LOCAL (0x1) /* netdump_data flags */ +#define NETDUMP_REMOTE (0x2) +#define VMCORE_VALID() (nd->flags & (NETDUMP_LOCAL|NETDUMP_REMOTE|KDUMP_LOCAL)) +#define NETDUMP_ELF32 (0x4) +#define NETDUMP_ELF64 (0x8) +#define PARTIAL_DUMP (0x10) /* netdump or diskdump */ +#define KDUMP_ELF32 (0x20) +#define KDUMP_ELF64 (0x40) +#define KDUMP_LOCAL (0x80) +#define KCORE_LOCAL (0x100) +#define KCORE_ELF32 (0x200) +#define KCORE_ELF64 (0x400) +#define QEMU_MEM_DUMP_KDUMP_BACKUP \ + (0x800) +#define KVMDUMP_LOCAL (0x1) +#define KVMDUMP_VALID() (kvm->flags & (KVMDUMP_LOCAL)) + +#define DUMPFILE_FORMAT(flags) ((flags) & \ + (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64)) + +#define DISKDUMP_LOCAL (0x1) +#define KDUMP_CMPRS_LOCAL (0x2) +#define ERROR_EXCLUDED (0x4) +#define ZERO_EXCLUDED (0x8) +#define DUMPFILE_SPLIT (0x10) +#define NO_ELF_NOTES (0x20) +#define LZO_SUPPORTED (0x40) +#define SNAPPY_SUPPORTED (0x80) +#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) +#define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) +#define KDUMP_SPLIT() (dd->flags & DUMPFILE_SPLIT) + +#define XENDUMP_LOCAL (0x1) +#define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) + +#define SADUMP_LOCAL (0x1) +#define SADUMP_DISKSET (0x2) +#define SADUMP_MEDIA (0x4) +#define SADUMP_ZERO_EXCLUDED (0x8) +#define SADUMP_KDUMP_BACKUP (0x10) +#define SADUMP_VALID() (sd->flags & SADUMP_LOCAL) + +#define CRASHDEBUG(x) (pc->debug >= (x)) + +#define CRASHDEBUG_SUSPEND(X) { pc->debug_save = pc->debug; pc->debug = X; } +#define CRASHDEBUG_RESTORE() { pc->debug = pc->debug_save; } + +#define VERBOSE (0x1) +#define ADDRESS_SPECIFIED (0x2) + +#define FAULT_ON_ERROR (0x1) +#define RETURN_ON_ERROR (0x2) +#define QUIET (0x4) +#define HEX_BIAS (0x8) +#define LONG_LONG (0x10) +#define RETURN_PARTIAL (0x20) +#define NO_DEVMEM_SWITCH (0x40) + +#define SEEK_ERROR (-1) +#define READ_ERROR (-2) +#define WRITE_ERROR (-3) +#define PAGE_EXCLUDED (-4) + +#define RESTART() (longjmp(pc->main_loop_env, 1)) +#define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) + +#define INFO (1) +#define FATAL (2) +#define FATAL_RESTART (3) +#define WARNING (4) +#define NOTE (5) +#define CONT (6) +#define FATAL_ERROR(x) (((x) == FATAL) || ((x) == FATAL_RESTART)) + +#define CONSOLE_OFF(x) ((x) = console_off()) +#define CONSOLE_ON(x) (console_on(x)) + +#define RADIX(X) (X) + +#define NUM_HEX (0x1) +#define NUM_DEC (0x2) +#define NUM_EXPR (0x4) +#define NUM_ANY (NUM_HEX|NUM_DEC|NUM_EXPR) + +/* + * program context redirect flags + */ +#define FROM_COMMAND_LINE (0x1) +#define FROM_INPUT_FILE (0x2) +#define REDIRECT_NOT_DONE (0x4) +#define REDIRECT_TO_PIPE (0x8) +#define REDIRECT_TO_STDPIPE (0x10) +#define REDIRECT_TO_FILE (0x20) +#define REDIRECT_FAILURE (0x40) +#define REDIRECT_SHELL_ESCAPE (0x80) +#define REDIRECT_SHELL_COMMAND (0x100) +#define REDIRECT_PID_KNOWN (0x200) +#define REDIRECT_MULTI_PIPE (0x400) + +#define PIPE_OPTIONS (FROM_COMMAND_LINE | FROM_INPUT_FILE | REDIRECT_TO_PIPE | \ + REDIRECT_TO_STDPIPE | REDIRECT_TO_FILE) + +#define DEFAULT_REDHAT_DEBUG_LOCATION "/usr/lib/debug/lib/modules" + +#define MEMORY_DRIVER_MODULE "crash" +#define MEMORY_DRIVER_DEVICE "/dev/crash" +#define MEMORY_DRIVER_DEVICE_MODE (S_IFCHR|S_IRUSR) + +/* + * structure definitions + */ +struct program_context { + char *program_name; /* this program's name */ + char *program_path; /* unadulterated argv[0] */ + char *program_version; /* this program's version */ + char *gdb_version; /* embedded gdb version */ + char *prompt; /* this program's prompt */ + unsigned long long flags; /* flags from above */ + char *namelist; /* linux namelist */ + char *dumpfile; /* dumpfile or /dev/kmem */ + char *live_memsrc; /* live memory driver */ + char *system_map; /* get symbol values from System.map */ + char *namelist_debug; /* namelist containing debug data */ + char *debuginfo_file; /* separate debuginfo file */ + char *memory_module; /* alternative to mem.c driver */ + char *memory_device; /* alternative to /dev/[k]mem device */ + char *machine_type; /* machine's processor type */ + char *editing_mode; /* readline vi or emacs */ + char *server; /* network daemon */ + char *server_memsrc; /* memory source on server */ + char *server_namelist; /* kernel namelist on server */ + int nfd; /* linux namelist fd */ + int mfd; /* /dev/mem fd */ + int kfd; /* /dev/kmem fd */ + int dfd; /* dumpfile fd */ + int confd; /* console fd */ + int sockfd; /* network daemon socket */ + ushort port; /* network daemon port */ + int rmfd; /* remote server memory source fd */ + int rkfd; /* remote server /dev/kmem fd */ + ulong program_pid; /* program pid */ + ulong server_pid; /* server pid */ + ulong rcvbufsize; /* client-side receive buffer size */ + char *home; /* user's home directory */ + char command_line[BUFSIZE]; /* possibly parsed input command line */ + char orig_line[BUFSIZE]; /* original input line */ + char *readline; /* pointer to last readline() return */ + char my_tty[10]; /* real tty name (shown by ps -ef) */ + ulong debug; /* level of debug */ + ulong debug_save; /* saved level for debug-suspend */ + char *console; /* current debug console device */ + char *redhat_debug_loc; /* location of matching debug objects */ + int pipefd[2]; /* output pipe file descriptors */ + FILE *nullfp; /* bitbucket */ + FILE *stdpipe; /* standard pipe for output */ + FILE *pipe; /* command line specified pipe */ + FILE *ofile; /* command line specified output file */ + FILE *ifile; /* command line specified input file */ + FILE *ifile_pipe; /* output pipe specified from file */ + FILE *ifile_ofile; /* output file specified from file */ + FILE *symfile; /* symbol table data file */ + FILE *symfile2; /* alternate access to above */ + FILE *tmpfile; /* tmpfile for selective data output */ + FILE *saved_fp; /* for printing while parsing tmpfile */ + FILE *tmp_fp; /* stored tmpfile pointer */ + char *input_file; /* input file specified at invocation */ + FILE *tmpfile2; /* tmpfile2 does not use save_fp! */ + int eoc_index; /* end of redirected command index */ + int scroll_command; /* default scroll command for output */ +#define SCROLL_NONE 0 +#define SCROLL_LESS 1 +#define SCROLL_MORE 2 +#define SCROLL_CRASHPAGER 3 + ulong redirect; /* per-cmd origin and output flags */ + pid_t stdpipe_pid; /* per-cmd standard output pipe's pid */ + pid_t pipe_pid; /* per-cmd output pipe's pid */ + pid_t pipe_shell_pid; /* per-cmd output pipe's shell pid */ + char pipe_command[BUFSIZE]; /* pipe command line */ + struct command_table_entry *cmd_table; /* linux/xen command table */ + char *curcmd; /* currently-executing command */ + char *lastcmd; /* previously-executed command */ + ulong cmdgencur; /* current command generation number */ + ulong curcmd_flags; /* general purpose per-command flag */ +#define XEN_MACHINE_ADDR (0x1) +#define REPEAT (0x2) +#define IDLE_TASK_SHOWN (0x4) +#define TASK_SPECIFIED (0x8) +#define MEMTYPE_UVADDR (0x10) +#define MEMTYPE_FILEADDR (0x20) +#define HEADER_PRINTED (0x40) +#define BAD_INSTRUCTION (0x80) +#define UD2A_INSTRUCTION (0x100) +#define IRQ_IN_USE (0x200) +#define NO_MODIFY (0x400) +#define IGNORE_ERRORS (0x800) +#define FROM_RCFILE (0x1000) +#define MEMTYPE_KVADDR (0x2000) +#define MOD_SECTIONS (0x4000) +#define MOD_READNOW (0x8000) +#define MM_STRUCT_FORCE (0x10000) +#define CPUMASK (0x20000) +#define PARTIAL_READ_OK (0x40000) + ulonglong curcmd_private; /* general purpose per-command info */ + int cur_gdb_cmd; /* current gdb command */ + int last_gdb_cmd; /* previously-executed gdb command */ + int sigint_cnt; /* number of ignored SIGINTs */ + struct gnu_request *cur_req; /* current gdb gnu_request */ + struct sigaction sigaction; /* general usage sigaction. */ + struct sigaction gdb_sigaction; /* gdb's SIGINT sigaction. */ + jmp_buf main_loop_env; /* longjmp target default */ + jmp_buf foreach_loop_env; /* longjmp target within foreach */ + jmp_buf gdb_interface_env; /* longjmp target for gdb error catch */ + struct termios termios_orig; /* non-raw settings */ + struct termios termios_raw; /* while gathering command input */ + int ncmds; /* number of commands in menu */ + char **cmdlist; /* current list of available commands */ + int cmdlistsz; /* space available in cmdlist */ + unsigned output_radix; /* current gdb output_radix */ + void *sbrk; /* current sbrk value */ + struct extension_table *curext; /* extension being loaded */ + int (*readmem)(int, void *, int, ulong, physaddr_t); /* memory access */ + int (*writemem)(int, void *, int, ulong, physaddr_t);/* memory access */ + ulong ifile_in_progress; /* original xxx_IFILE flags */ + off_t ifile_offset; /* current offset into input file */ + char *runtime_ifile_cmd; /* runtime command using input file */ + char *kvmdump_mapfile; /* storage of physical to file offsets */ + ulonglong flags2; /* flags overrun */ +#define FLAT (0x01ULL) +#define ELF_NOTES (0x02ULL) +#define GET_OSRELEASE (0x04ULL) +#define REMOTE_DAEMON (0x08ULL) +#define ERASEINFO_DATA (0x10ULL) +#define GDB_CMD_MODE (0x20ULL) +#define LIVE_DUMP (0x40ULL) +#define FLAT_FORMAT() (pc->flags2 & FLAT) +#define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES) +#define RADIX_OVERRIDE (0x80ULL) +#define QEMU_MEM_DUMP_ELF (0x100ULL) +#define GET_LOG (0x200ULL) +#define VMCOREINFO (0x400ULL) +#define ALLOW_FP (0x800ULL) +#define REM_PAUSED_F (0x1000ULL) +#define RAMDUMP (0x2000ULL) +#define REMOTE_PAUSED() (pc->flags2 & REM_PAUSED_F) +#define OFFLINE_HIDE (0x4000ULL) +#define INCOMPLETE_DUMP (0x8000ULL) +#define is_incomplete_dump() (pc->flags2 & INCOMPLETE_DUMP) +#define QEMU_MEM_DUMP_COMPRESSED (0x10000ULL) +#define SNAP (0x20000ULL) +#define EXCLUDED_VMEMMAP (0x40000ULL) +#define is_excluded_vmemmap() (pc->flags2 & EXCLUDED_VMEMMAP) +#define MEMSRC_LOCAL (0x80000ULL) +#define REDZONE (0x100000ULL) + char *cleanup; + char *namelist_orig; + char *namelist_debug_orig; + FILE *args_ifile; /* per-command args input file */ + void (*cmd_cleanup)(void *); /* per-command cleanup function */ + void *cmd_cleanup_arg; /* optional cleanup function argument */ + ulong scope; /* optional text context address */ + ulong nr_hash_queues; /* hash queue head count */ + char *(*read_vmcoreinfo)(const char *); + FILE *error_fp; /* error() message direction */ + char *error_path; /* stderr path information */ +}; + +#define READMEM pc->readmem + +typedef void (*cmd_func_t)(void); + +struct command_table_entry { /* one for each command in menu */ + char *name; + cmd_func_t func; + char **help_data; + ulong flags; +}; + +struct args_input_file { + int index; + int args_used; + int is_gdb_cmd; + int in_expression; + int start; + int resume; + char *fileptr; +}; + +#define REFRESH_TASK_TABLE (0x1) /* command_table_entry flags */ +#define HIDDEN_COMMAND (0x2) +#define CLEANUP (0x4) /* for extensions only */ +#define MINIMAL (0x8) + +/* + * A linked list of extension table structures keeps track of the current + * set of shared library extensions. + */ +struct extension_table { + void *handle; /* handle from dlopen() */ + char *filename; /* name of shared library */ + struct command_table_entry *command_table; /* list of commands */ + ulong flags; /* registration flags */ + struct extension_table *next, *prev; /* bookkeeping */ +}; + +#define REGISTERED (0x1) /* extension_table flags */ +#define DUPLICATE_COMMAND_NAME (0x2) +#define NO_MINIMAL_COMMANDS (0x4) + +struct new_utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#define NO_MODULE_ACCESS (0x1) +#define TVEC_BASES_V1 (0x2) +#define GCC_3_2 (0x4) +#define GCC_3_2_3 (0x8) +#define GCC_2_96 (0x10) +#define RA_SEEK (0x20) +#define NO_RA_SEEK (0x40) +#define KALLSYMS_V1 (0x80) +#define NO_KALLSYMS (0x100) +#define PER_CPU_OFF (0x200) +#define SMP (0x400) +#define GCC_3_3_2 (0x800) +#define KMOD_V1 (0x1000) +#define KMOD_V2 (0x2000) +#define KALLSYMS_V2 (0x2000) +#define TVEC_BASES_V2 (0x4000) +#define GCC_3_3_3 (0x8000) +#define USE_OLD_BT (0x10000) +#define USE_OPT_BT (0x10000) +#define ARCH_XEN (0x20000) +#define NO_IKCONFIG (0x40000) +#define DWARF_UNWIND (0x80000) +#define NO_DWARF_UNWIND (0x100000) +#define DWARF_UNWIND_MEMORY (0x200000) +#define DWARF_UNWIND_EH_FRAME (0x400000) +#define DWARF_UNWIND_CAPABLE (DWARF_UNWIND_MEMORY|DWARF_UNWIND_EH_FRAME) +#define DWARF_UNWIND_MODULES (0x800000) +#define BUGVERBOSE_OFF (0x1000000) +#define RELOC_SET (0x2000000) +#define RELOC_FORCE (0x4000000) +#define ARCH_OPENVZ (0x8000000) +#define ARCH_PVOPS (0x10000000) +#define PRE_KERNEL_INIT (0x20000000) +#define ARCH_PVOPS_XEN (0x40000000) + +#define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3) + +/* flags2 */ +#define RELOC_AUTO (0x1ULL) +#define KASLR (0x2ULL) +#define KASLR_CHECK (0x4ULL) +#define GET_TIMESTAMP (0x8ULL) +#define TVEC_BASES_V3 (0x10ULL) +#define TIMER_BASES (0x20ULL) +#define IRQ_DESC_TREE_RADIX (0x40ULL) +#define IRQ_DESC_TREE_XARRAY (0x80ULL) + +#define XEN() (kt->flags & ARCH_XEN) +#define OPENVZ() (kt->flags & ARCH_OPENVZ) +#define PVOPS() (kt->flags & ARCH_PVOPS) +#define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN) + +#define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) +#define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) + +#define XEN_MFN_NOT_FOUND (~0UL) +#define XEN_PFNS_PER_PAGE (PAGESIZE()/sizeof(ulong)) +#define XEN_FOREIGN_FRAME (1UL << (BITS()-1)) + +#define XEN_MACHADDR_NOT_FOUND (~0ULL) + +#define XEN_P2M_PER_PAGE (PAGESIZE() / sizeof(unsigned long)) +#define XEN_P2M_MID_PER_PAGE (PAGESIZE() / sizeof(unsigned long *)) +#define XEN_P2M_TOP_PER_PAGE (PAGESIZE() / sizeof(unsigned long **)) + +struct kernel_table { /* kernel data */ + ulong flags; + ulong stext; + ulong etext; + ulong stext_init; + ulong etext_init; + ulong init_begin; + ulong init_end; + ulong end; + int cpus; + char *cpus_override; + void (*display_bh)(void); + ulong module_list; + ulong kernel_module; + int mods_installed; + struct timespec date; + char proc_version[BUFSIZE]; + struct new_utsname utsname; + uint kernel_version[3]; + uint gcc_version[3]; + int runq_siblings; + int kernel_NR_CPUS; + long __per_cpu_offset[NR_CPUS]; + long *__rq_idx; + long *__cpu_idx; + ulong *cpu_flags; +#define POSSIBLE (0x1) +#define PRESENT (0x2) +#define ONLINE (0x4) +#define NMI (0x8) +#define POSSIBLE_MAP (POSSIBLE) +#define PRESENT_MAP (PRESENT) +#define ONLINE_MAP (ONLINE) +#define ACTIVE_MAP (0x10) + int BUG_bytes; + ulong xen_flags; +#define WRITABLE_PAGE_TABLES (0x1) +#define SHADOW_PAGE_TABLES (0x2) +#define CANONICAL_PAGE_TABLES (0x4) +#define XEN_SUSPEND (0x8) + char *m2p_page; + ulong phys_to_machine_mapping; + ulong p2m_table_size; +#define P2M_MAPPING_CACHE (512) + struct p2m_mapping_cache { + ulong mapping; + ulong pfn; + ulong start; + ulong end; + } p2m_mapping_cache[P2M_MAPPING_CACHE]; +#define P2M_MAPPING_PAGE_PFN(c) \ + (PVOPS_XEN() ? kt->p2m_mapping_cache[c].pfn : \ + (((kt->p2m_mapping_cache[c].mapping - kt->phys_to_machine_mapping)/PAGESIZE()) \ + * XEN_PFNS_PER_PAGE)) + ulong last_mapping_read; + ulong p2m_cache_index; + ulong p2m_pages_searched; + ulong p2m_mfn_cache_hits; + ulong p2m_page_cache_hits; + ulong relocate; + char *module_tree; + struct pvops_xen_info { + int p2m_top_entries; + ulong p2m_top; + ulong p2m_mid_missing; + ulong p2m_missing; + } pvops_xen; + int highest_irq; +#define IKCONFIG_AVAIL 0x1 /* kernel contains ikconfig data */ +#define IKCONFIG_LOADED 0x2 /* ikconfig data is currently loaded */ + int ikconfig_flags; + int ikconfig_ents; + char *hypervisor; + struct vmcoreinfo_data { + ulong log_buf_SYMBOL; + ulong log_end_SYMBOL; + ulong log_buf_len_SYMBOL; + ulong logged_chars_SYMBOL; + ulong log_first_idx_SYMBOL; + ulong log_next_idx_SYMBOL; + long log_SIZE; + long log_ts_nsec_OFFSET; + long log_len_OFFSET; + long log_text_len_OFFSET; + long log_dict_len_OFFSET; + ulong phys_base_SYMBOL; + ulong _stext_SYMBOL; + } vmcoreinfo; + ulonglong flags2; + char *source_tree; +}; + +/* + * Aid for the two versions of the kernel's module list linkage. + */ +#define NEXT_MODULE(next_module, modbuf) \ +{ \ + switch (kt->flags & (KMOD_V1|KMOD_V2)) \ + { \ + case KMOD_V1: \ + next_module = ULONG(modbuf + OFFSET(module_next)); \ + break; \ + case KMOD_V2: \ + next_module = ULONG(modbuf + OFFSET(module_list)); \ + if (next_module != kt->kernel_module) \ + next_module -= OFFSET(module_list); \ + break; \ + } \ +} + +#define THIS_KERNEL_VERSION ((kt->kernel_version[0] << 16) + \ + (kt->kernel_version[1] << 8) + \ + (kt->kernel_version[2])) +#define LINUX(x,y,z) (((uint)(x) << 16) + ((uint)(y) << 8) + (uint)(z)) + +#define THIS_GCC_VERSION ((kt->gcc_version[0] << 16) + \ + (kt->gcc_version[1] << 8) + \ + (kt->gcc_version[2])) +#define GCC(x,y,z) (((uint)(x) << 16) + ((uint)(y) << 8) + (uint)(z)) + +#define IS_KERNEL_STATIC_TEXT(x) (((ulong)(x) >= kt->stext) && \ + ((ulong)(x) < kt->etext)) + +#define TASK_COMM_LEN 16 /* task command name length including NULL */ + +struct task_context { /* context stored for each task */ + ulong task; + ulong thread_info; + ulong pid; + char comm[TASK_COMM_LEN+1]; + int processor; + ulong ptask; + ulong mm_struct; + struct task_context *tc_next; +}; + +struct tgid_context { /* tgid and task stored for each task */ + ulong tgid; + ulong task; +}; + +struct task_table { /* kernel/local task table data */ + struct task_context *current; + struct task_context *context_array; + void (*refresh_task_table)(void); + ulong flags; + ulong task_start; + ulong task_end; + void *task_local; + int max_tasks; + int nr_threads; + ulong running_tasks; + ulong retries; + ulong panicmsg; + int panic_processor; + ulong *idle_threads; + ulong *panic_threads; + ulong *active_set; + ulong *panic_ksp; + ulong *hardirq_ctx; + ulong *hardirq_tasks; + ulong *softirq_ctx; + ulong *softirq_tasks; + ulong panic_task; + ulong this_task; + int pidhash_len; + ulong pidhash_addr; + ulong last_task_read; + ulong last_thread_info_read; + ulong last_mm_read; + char *task_struct; + char *thread_info; + char *mm_struct; + ulong init_pid_ns; + struct tgid_context *tgid_array; + struct tgid_context *last_tgid; + ulong tgid_searches; + ulong tgid_cache_hits; + long filepages; + long anonpages; + ulong stack_end_magic; + ulong pf_kthread; + ulong pid_radix_tree; + int callbacks; + struct task_context **context_by_task; /* task_context sorted by task addr */ + ulong pid_xarray; +}; + +#define TASK_INIT_DONE (0x1) +#define TASK_ARRAY_EXISTS (0x2) +#define PANIC_TASK_NOT_FOUND (0x4) +#define TASK_REFRESH (0x8) +#define TASK_REFRESH_OFF (0x10) +#define PANIC_KSP (0x20) +#define ACTIVE_SET (0x40) +#define POPULATE_PANIC (0x80) +#define PIDHASH (0x100) +#define PID_HASH (0x200) +#define THREAD_INFO (0x400) +#define IRQSTACKS (0x800) +#define TIMESPEC (0x1000) +#define NO_TIMESPEC (0x2000) +#define ACTIVE_ONLY (0x4000) +#define START_TIME_NSECS (0x8000) +#define THREAD_INFO_IN_TASK (0x10000) +#define PID_RADIX_TREE (0x20000) +#define INDEXED_CONTEXTS (0x40000) +#define PID_XARRAY (0x80000) + +#define TASK_SLUSH (20) + +#define NO_PROC_ID 0xFF /* No processor magic marker (from kernel) */ + +/* + * Global "tt" points to task_table + */ +#define CURRENT_CONTEXT() (tt->current) +#define CURRENT_TASK() (tt->current->task) +#define CURRENT_PID() (tt->current->pid) +#define CURRENT_COMM() (tt->current->comm) +#define RUNNING_TASKS() (tt->running_tasks) +#define FIRST_CONTEXT() (tt->context_array) + +#define NO_PID ((ulong)-1) +#define NO_TASK (0) + +#define IS_TASK_ADDR(X) (machdep->is_task_addr(X)) +#define GET_STACKBASE(X) (machdep->get_stackbase(X)) +#define GET_STACKTOP(X) (machdep->get_stacktop(X)) +#define STACKSIZE() (machdep->stacksize) +#define LONGS_PER_STACK (machdep->stacksize/sizeof(ulong)) + +#define INSTACK(X,BT) \ + (((ulong)(X) >= (BT)->stackbase) && ((ulong)(X) < (BT)->stacktop)) + +#define ALIGNED_STACK_OFFSET(task) ((ulong)(task) & (STACKSIZE()-1)) + +#define BITS() (machdep->bits) +#define BITS32() (machdep->bits == 32) +#define BITS64() (machdep->bits == 64) +#define IS_KVADDR(X) (machdep->is_kvaddr(X)) +#define IS_UVADDR(X,C) (machdep->is_uvaddr(X,C)) + +#define PID_ALIVE(x) (kill(x, 0) == 0) + +struct kernel_list_head { + struct kernel_list_head *next, *prev; +}; + +struct stack_hook { + ulong esp; + ulong eip; +}; + +struct bt_info { + ulong task; + ulonglong flags; + ulong instptr; + ulong stkptr; + ulong bptr; + ulong stackbase; + ulong stacktop; + char *stackbuf; + struct task_context *tc; + struct stack_hook *hp; + struct stack_hook *textlist; + struct reference *ref; + ulong frameptr; + char *call_target; + void *machdep; + ulong debug; + ulong eframe_ip; + ulong radix; + ulong *cpumask; +}; + +#define STACK_OFFSET_TYPE(OFF) \ + (((ulong)(OFF) > STACKSIZE()) ? \ + (ulong)((ulong)(OFF) - (ulong)(bt->stackbase)) : (ulong)(OFF)) + +#define GET_STACK_ULONG(OFF) \ + *((ulong *)((char *)(&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(OFF))]))) + +#define GET_STACK_DATA(OFF, LOC, SZ) memcpy((void *)(LOC), \ + (void *)(&bt->stackbuf[(ulong)STACK_OFFSET_TYPE(OFF)]), (size_t)(SZ)) + +struct machine_specific; /* uniquely defined below each machine's area */ +struct xendump_data; +struct xen_kdump_data; + +struct vaddr_range { + ulong start; + ulong end; + ulong type; +#define KVADDR_UNITY_MAP (1) +#define KVADDR_VMALLOC (2) +#define KVADDR_VMEMMAP (3) +#define KVADDR_START_MAP (4) +#define KVADDR_MODULES (5) +#define MAX_KVADDR_RANGES KVADDR_MODULES +}; + +#define MAX_MACHDEP_ARGS 5 /* for --machdep/-m machine-specific args */ + +struct machdep_table { + ulong flags; + ulong kvbase; + ulong identity_map_base; + uint pagesize; + uint pageshift; + ulonglong pagemask; + ulong pageoffset; + ulong stacksize; + uint hz; + ulong mhz; + int bits; + int nr_irqs; + uint64_t memsize; + int (*eframe_search)(struct bt_info *); + void (*back_trace)(struct bt_info *); + ulong (*processor_speed)(void); + int (*uvtop)(struct task_context *, ulong, physaddr_t *, int); + int (*kvtop)(struct task_context *, ulong, physaddr_t *, int); + ulong (*get_task_pgd)(ulong); + void (*dump_irq)(int); + void (*get_stack_frame)(struct bt_info *, ulong *, ulong *); + ulong (*get_stackbase)(ulong); + ulong (*get_stacktop)(ulong); + int (*translate_pte)(ulong, void *, ulonglong); + uint64_t (*memory_size)(void); + ulong (*vmalloc_start)(void); + int (*is_task_addr)(ulong); + int (*verify_symbol)(const char *, ulong, char); + int (*dis_filter)(ulong, char *, unsigned int); + int (*get_smp_cpus)(void); + int (*is_kvaddr)(ulong); + int (*is_uvaddr)(ulong, struct task_context *); + int (*verify_paddr)(uint64_t); + void (*cmd_mach)(void); + void (*init_kernel_pgd)(void); + struct syment *(*value_to_symbol)(ulong, ulong *); + struct line_number_hook { + char *func; + char **file; + } *line_number_hooks; + ulong last_pgd_read; + ulong last_pud_read; + ulong last_pmd_read; + ulong last_ptbl_read; + char *pgd; + char *pud; + char *pmd; + char *ptbl; + int ptrs_per_pgd; + char *cmdline_args[MAX_MACHDEP_ARGS]; + struct machine_specific *machspec; + ulong section_size_bits; + ulong max_physmem_bits; + ulong sections_per_root; + int (*xendump_p2m_create)(struct xendump_data *); + ulong (*xendump_panic_task)(struct xendump_data *); + void (*get_xendump_regs)(struct xendump_data *, struct bt_info *, ulong *, ulong *); + void (*clear_machdep_cache)(void); + int (*xen_kdump_p2m_create)(struct xen_kdump_data *); + int (*in_alternate_stack)(int, ulong); + void (*dumpfile_init)(int, void *); + void (*process_elf_notes)(void *, unsigned long); + int (*get_kvaddr_ranges)(struct vaddr_range *); + int (*verify_line_number)(ulong, ulong, ulong); + void (*get_irq_affinity)(int); + void (*show_interrupts)(int, ulong *); + int (*is_page_ptr)(ulong, physaddr_t *); +}; + +/* + * Processor-common flags; processor-specific flags use the lower bits + * as defined in their processor-specific files below. (see KSYMS_START defs). + */ +#define HWRESET (0x80000000) +#define OMIT_FRAME_PTR (0x40000000) +#define FRAMESIZE_DEBUG (0x20000000) +#define MACHDEP_BT_TEXT (0x10000000) +#define DEVMEMRD (0x8000000) +#define INIT (0x4000000) +#define VM_4_LEVEL (0x2000000) +#define MCA (0x1000000) +#define PAE (0x800000) +#define VMEMMAP (0x400000) + +extern struct machdep_table *machdep; + +#ifndef HZ +#define HZ sysconf(_SC_CLK_TCK) +#endif + +#define IS_LAST_PGD_READ(pgd) ((ulong)(pgd) == machdep->last_pgd_read) +#define IS_LAST_PMD_READ(pmd) ((ulong)(pmd) == machdep->last_pmd_read) +#define IS_LAST_PTBL_READ(ptbl) ((ulong)(ptbl) == machdep->last_ptbl_read) +#define IS_LAST_PUD_READ(pud) ((ulong)(pud) == machdep->last_pud_read) + +#define FILL_PGD(PGD, TYPE, SIZE) \ + if (!IS_LAST_PGD_READ(PGD)) { \ + readmem((ulonglong)((ulong)(PGD)), TYPE, machdep->pgd, \ + SIZE, "pgd page", FAULT_ON_ERROR); \ + machdep->last_pgd_read = (ulong)(PGD); \ + } + +#define FILL_PUD(PUD, TYPE, SIZE) \ + if (!IS_LAST_PUD_READ(PUD)) { \ + readmem((ulonglong)((ulong)(PUD)), TYPE, machdep->pud, \ + SIZE, "pud page", FAULT_ON_ERROR); \ + machdep->last_pud_read = (ulong)(PUD); \ + } + +#define FILL_PMD(PMD, TYPE, SIZE) \ + if (!IS_LAST_PMD_READ(PMD)) { \ + readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ + SIZE, "pmd page", FAULT_ON_ERROR); \ + machdep->last_pmd_read = (ulong)(PMD); \ + } + +#define FILL_PTBL(PTBL, TYPE, SIZE) \ + if (!IS_LAST_PTBL_READ(PTBL)) { \ + readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ + SIZE, "page table", FAULT_ON_ERROR); \ + machdep->last_ptbl_read = (ulong)(PTBL); \ + } + +#define SETUP_ENV (0) +#define PRE_SYMTAB (1) +#define PRE_GDB (2) +#define POST_GDB (3) +#define POST_INIT (4) +#define POST_VM (5) +#define LOG_ONLY (6) +#define POST_RELOC (7) + +#define FOREACH_BT (1) +#define FOREACH_VM (2) +#define FOREACH_TASK (3) +#define FOREACH_SET (4) +#define FOREACH_FILES (5) +#define FOREACH_NET (6) +#define FOREACH_TEST (7) +#define FOREACH_VTOP (8) +#define FOREACH_SIG (9) +#define FOREACH_PS (10) + +#define MAX_FOREACH_KEYWORDS (10) +#define MAX_FOREACH_TASKS (50) +#define MAX_FOREACH_PIDS (50) +#define MAX_FOREACH_COMMS (50) +#define MAX_FOREACH_ARGS (50) +#define MAX_REGEX_ARGS (10) + +#define FOREACH_CMD (0x1) +#define FOREACH_r_FLAG (0x2) +#define FOREACH_s_FLAG (0x4) +#define FOREACH_S_FLAG (0x8) +#define FOREACH_i_FLAG (0x10) +#define FOREACH_e_FLAG (0x20) +#define FOREACH_g_FLAG (0x40) +#define FOREACH_l_FLAG (0x80) +#define FOREACH_p_FLAG (0x100) +#define FOREACH_t_FLAG (0x200) +#define FOREACH_u_FLAG (0x400) +#define FOREACH_m_FLAG (0x800) +#define FOREACH_v_FLAG (0x1000) +#define FOREACH_KERNEL (0x2000) +#define FOREACH_USER (0x4000) +#define FOREACH_SPECIFIED (0x8000) +#define FOREACH_ACTIVE (0x10000) +#define FOREACH_k_FLAG (0x20000) +#define FOREACH_c_FLAG (0x40000) +#define FOREACH_f_FLAG (0x80000) +#define FOREACH_o_FLAG (0x100000) +#define FOREACH_T_FLAG (0x200000) +#define FOREACH_F_FLAG (0x400000) +#define FOREACH_x_FLAG (0x800000) +#define FOREACH_d_FLAG (0x1000000) +#define FOREACH_STATE (0x2000000) +#define FOREACH_a_FLAG (0x4000000) +#define FOREACH_G_FLAG (0x8000000) +#define FOREACH_F_FLAG2 (0x10000000) +#define FOREACH_y_FLAG (0x20000000) +#define FOREACH_GLEADER (0x40000000) + +#define FOREACH_PS_EXCLUSIVE \ + (FOREACH_g_FLAG|FOREACH_a_FLAG|FOREACH_t_FLAG|FOREACH_c_FLAG|FOREACH_p_FLAG|FOREACH_l_FLAG|FOREACH_r_FLAG|FOREACH_m_FLAG) + +struct foreach_data { + ulong flags; + int keyword_array[MAX_FOREACH_KEYWORDS]; + ulong task_array[MAX_FOREACH_TASKS]; + char *comm_array[MAX_FOREACH_COMMS]; + ulong pid_array[MAX_FOREACH_PIDS]; + ulong arg_array[MAX_FOREACH_ARGS]; + struct regex_info { + char *pattern; + regex_t regex; + } regex_info[MAX_REGEX_ARGS]; + ulong state; + char *reference; + int keys; + int pids; + int tasks; + int comms; + int args; + int regexs; + int policy; +}; + +struct reference { + char *str; + ulong cmdflags; + ulong hexval; + ulong decval; + ulong ref1; + ulong ref2; + void *refp; +}; + +struct offset_table { /* stash of commonly-used offsets */ + long list_head_next; /* add new entries to end of table */ + long list_head_prev; + long task_struct_pid; + long task_struct_state; + long task_struct_comm; + long task_struct_mm; + long task_struct_tss; + long task_struct_thread; + long task_struct_active_mm; + long task_struct_tss_eip; + long task_struct_tss_esp; + long task_struct_tss_ksp; + long task_struct_processor; + long task_struct_p_pptr; + long task_struct_parent; + long task_struct_has_cpu; + long task_struct_cpus_runnable; + long task_struct_thread_eip; + long task_struct_thread_esp; + long task_struct_thread_ksp; + long task_struct_next_task; + long task_struct_files; + long task_struct_fs; + long task_struct_pidhash_next; + long task_struct_next_run; + long task_struct_flags; + long task_struct_sig; + long task_struct_signal; + long task_struct_blocked; + long task_struct_sigpending; + long task_struct_pending; + long task_struct_sigqueue; + long task_struct_sighand; + long task_struct_start_time; + long task_struct_times; + long task_struct_utime; + long task_struct_stime; + long task_struct_cpu; + long task_struct_run_list; + long task_struct_pgrp; + long task_struct_tgid; + long task_struct_namespace; + long task_struct_pids; + long task_struct_last_run; + long task_struct_timestamp; + long task_struct_thread_info; + long task_struct_nsproxy; + long task_struct_rlim; + long thread_info_task; + long thread_info_cpu; + long thread_info_previous_esp; + long thread_info_flags; + long nsproxy_mnt_ns; + long mnt_namespace_root; + long mnt_namespace_list; + long pid_link_pid; + long pid_hash_chain; + long hlist_node_next; + long hlist_node_pprev; + long pid_pid_chain; + long thread_struct_eip; + long thread_struct_esp; + long thread_struct_ksp; + long thread_struct_fph; + long thread_struct_rip; + long thread_struct_rsp; + long thread_struct_rsp0; + long tms_tms_utime; + long tms_tms_stime; + long signal_struct_count; + long signal_struct_action; + long signal_struct_shared_pending; + long signal_struct_rlim; + long k_sigaction_sa; + long sigaction_sa_handler; + long sigaction_sa_flags; + long sigaction_sa_mask; + long sigpending_head; + long sigpending_list; + long sigpending_signal; + long signal_queue_next; + long signal_queue_info; + long sigqueue_next; + long sigqueue_list; + long sigqueue_info; + long sighand_struct_action; + long siginfo_si_signo; + long thread_struct_cr3; + long thread_struct_ptbr; + long thread_struct_pg_tables; + long switch_stack_r26; + long switch_stack_b0; + long switch_stack_ar_bspstore; + long switch_stack_ar_pfs; + long switch_stack_ar_rnat; + long switch_stack_pr; + long cpuinfo_ia64_proc_freq; + long cpuinfo_ia64_unimpl_va_mask; + long cpuinfo_ia64_unimpl_pa_mask; + long device_node_type; + long device_node_allnext; + long device_node_properties; + long property_name; + long property_value; + long property_next; + long machdep_calls_setup_residual; + long RESIDUAL_VitalProductData; + long VPD_ProcessorHz; + long bd_info_bi_intfreq; + long hwrpb_struct_cycle_freq; + long hwrpb_struct_processor_offset; + long hwrpb_struct_processor_size; + long percpu_struct_halt_PC; + long percpu_struct_halt_ra; + long percpu_struct_halt_pv; + long mm_struct_mmap; + long mm_struct_pgd; + long mm_struct_rss; + long mm_struct_anon_rss; + long mm_struct_file_rss; + long mm_struct_total_vm; + long mm_struct_start_code; + long mm_struct_arg_start; + long mm_struct_arg_end; + long mm_struct_env_start; + long mm_struct_env_end; + long vm_area_struct_vm_mm; + long vm_area_struct_vm_next; + long vm_area_struct_vm_end; + long vm_area_struct_vm_start; + long vm_area_struct_vm_flags; + long vm_area_struct_vm_file; + long vm_area_struct_vm_offset; + long vm_area_struct_vm_pgoff; + long vm_struct_addr; + long vm_struct_size; + long vm_struct_next; + long module_size_of_struct; + long module_next; + long module_size; + long module_name; + long module_nsyms; + long module_syms; + long module_flags; + long module_num_syms; + long module_list; + long module_gpl_syms; + long module_num_gpl_syms; + long module_module_core; + long module_core_size; + long module_core_text_size; + long module_num_symtab; + long module_symtab; + long module_strtab; + + long module_kallsyms_start; + long kallsyms_header_sections; + long kallsyms_header_section_off; + long kallsyms_header_symbols; + long kallsyms_header_symbol_off; + long kallsyms_header_string_off; + long kallsyms_symbol_section_off; + long kallsyms_symbol_symbol_addr; + long kallsyms_symbol_name_off; + long kallsyms_section_start; + long kallsyms_section_size; + long kallsyms_section_name_off; + + long page_next; + long page_prev; + long page_next_hash; + long page_list; + long page_list_next; + long page_list_prev; + long page_inode; + long page_offset; + long page_count; + long page_flags; + long page_mapping; + long page_index; + long page_buffers; + long page_lru; + long page_pte; + long swap_info_struct_swap_file; + long swap_info_struct_swap_vfsmnt; + long swap_info_struct_flags; + long swap_info_struct_swap_map; + long swap_info_struct_swap_device; + long swap_info_struct_prio; + long swap_info_struct_max; + long swap_info_struct_pages; + long swap_info_struct_old_block_size; + long block_device_bd_inode; + long block_device_bd_list; + long block_device_bd_disk; + long irq_desc_t_status; + long irq_desc_t_handler; + long irq_desc_t_chip; + long irq_desc_t_action; + long irq_desc_t_depth; + long irqdesc_action; + long irqdesc_ctl; + long irqdesc_level; + long irqaction_handler; + long irqaction_flags; + long irqaction_mask; + long irqaction_name; + long irqaction_dev_id; + long irqaction_next; + long hw_interrupt_type_typename; + long hw_interrupt_type_startup; + long hw_interrupt_type_shutdown; + long hw_interrupt_type_handle; + long hw_interrupt_type_enable; + long hw_interrupt_type_disable; + long hw_interrupt_type_ack; + long hw_interrupt_type_end; + long hw_interrupt_type_set_affinity; + long irq_chip_typename; + long irq_chip_startup; + long irq_chip_shutdown; + long irq_chip_enable; + long irq_chip_disable; + long irq_chip_ack; + long irq_chip_end; + long irq_chip_set_affinity; + long irq_chip_mask; + long irq_chip_mask_ack; + long irq_chip_unmask; + long irq_chip_eoi; + long irq_chip_retrigger; + long irq_chip_set_type; + long irq_chip_set_wake; + long irq_cpustat_t___softirq_active; + long irq_cpustat_t___softirq_mask; + long fdtable_max_fds; + long fdtable_max_fdset; + long fdtable_open_fds; + long fdtable_fd; + long files_struct_fdt; + long files_struct_max_fds; + long files_struct_max_fdset; + long files_struct_open_fds; + long files_struct_fd; + long files_struct_open_fds_init; + long file_f_dentry; + long file_f_vfsmnt; + long file_f_count; + long file_f_path; + long path_mnt; + long path_dentry; + long fs_struct_root; + long fs_struct_pwd; + long fs_struct_rootmnt; + long fs_struct_pwdmnt; + long dentry_d_inode; + long dentry_d_parent; + long dentry_d_name; + long dentry_d_covers; + long dentry_d_iname; + long qstr_len; + long qstr_name; + long inode_i_mode; + long inode_i_op; + long inode_i_sb; + long inode_u; + long inode_i_flock; + long inode_i_fop; + long inode_i_mapping; + long address_space_nrpages; + long vfsmount_mnt_next; + long vfsmount_mnt_devname; + long vfsmount_mnt_dirname; + long vfsmount_mnt_sb; + long vfsmount_mnt_list; + long vfsmount_mnt_mountpoint; + long vfsmount_mnt_parent; + long namespace_root; + long namespace_list; + long super_block_s_dirty; + long super_block_s_type; + long super_block_s_files; + long file_system_type_name; + long nlm_file_f_file; + long file_lock_fl_owner; + long nlm_host_h_exportent; + long svc_client_cl_ident; + long kmem_cache_s_c_nextp; + long kmem_cache_s_c_name; + long kmem_cache_s_c_num; + long kmem_cache_s_c_org_size; + long kmem_cache_s_c_flags; + long kmem_cache_s_c_offset; + long kmem_cache_s_c_firstp; + long kmem_cache_s_c_gfporder; + long kmem_cache_s_c_magic; + long kmem_cache_s_num; + long kmem_cache_s_next; + long kmem_cache_s_name; + long kmem_cache_s_objsize; + long kmem_cache_s_flags; + long kmem_cache_s_gfporder; + long kmem_cache_s_slabs; + long kmem_cache_s_slabs_full; + long kmem_cache_s_slabs_partial; + long kmem_cache_s_slabs_free; + long kmem_cache_s_cpudata; + long kmem_cache_s_c_align; + long kmem_cache_s_colour_off; + long cpucache_s_avail; + long cpucache_s_limit; + long kmem_cache_s_array; + long array_cache_avail; + long array_cache_limit; + long kmem_cache_s_lists; + long kmem_list3_slabs_partial; + long kmem_list3_slabs_full; + long kmem_list3_slabs_free; + long kmem_list3_free_objects; + long kmem_list3_shared; + long kmem_slab_s_s_nextp; + long kmem_slab_s_s_freep; + long kmem_slab_s_s_inuse; + long kmem_slab_s_s_mem; + long kmem_slab_s_s_index; + long kmem_slab_s_s_offset; + long kmem_slab_s_s_magic; + long slab_s_list; + long slab_s_s_mem; + long slab_s_inuse; + long slab_s_free; + long slab_list; + long slab_s_mem; + long slab_inuse; + long slab_free; + long net_device_next; + long net_device_name; + long net_device_type; + long net_device_addr_len; + long net_device_ip_ptr; + long net_device_dev_list; + long net_dev_base_head; + long device_next; + long device_name; + long device_type; + long device_ip_ptr; + long device_addr_len; + long socket_sk; + long sock_daddr; + long sock_rcv_saddr; + long sock_dport; + long sock_sport; + long sock_num; + long sock_type; + long sock_family; + long sock_common_skc_family; + long sock_sk_type; + long inet_sock_inet; + long inet_opt_daddr; + long inet_opt_rcv_saddr; + long inet_opt_dport; + long inet_opt_sport; + long inet_opt_num; + long ipv6_pinfo_rcv_saddr; + long ipv6_pinfo_daddr; + long timer_list_list; + long timer_list_next; + long timer_list_entry; + long timer_list_expires; + long timer_list_function; + long timer_vec_root_vec; + long timer_vec_vec; + long tvec_root_s_vec; + long tvec_s_vec; + long tvec_t_base_s_tv1; + long wait_queue_task; + long wait_queue_next; + long __wait_queue_task; + long __wait_queue_head_task_list; + long __wait_queue_task_list; + long pglist_data_node_zones; + long pglist_data_node_mem_map; + long pglist_data_node_start_paddr; + long pglist_data_node_start_mapnr; + long pglist_data_node_size; + long pglist_data_node_id; + long pglist_data_node_next; + long pglist_data_nr_zones; + long pglist_data_node_start_pfn; + long pglist_data_pgdat_next; + long pglist_data_node_present_pages; + long pglist_data_node_spanned_pages; + long pglist_data_bdata; + long page_cache_bucket_chain; + long zone_struct_free_pages; + long zone_struct_free_area; + long zone_struct_zone_pgdat; + long zone_struct_name; + long zone_struct_size; + long zone_struct_memsize; + long zone_struct_zone_start_pfn; + long zone_struct_zone_start_paddr; + long zone_struct_zone_start_mapnr; + long zone_struct_zone_mem_map; + long zone_struct_inactive_clean_pages; + long zone_struct_inactive_clean_list; + long zone_struct_inactive_dirty_pages; + long zone_struct_active_pages; + long zone_struct_pages_min; + long zone_struct_pages_low; + long zone_struct_pages_high; + long zone_free_pages; + long zone_free_area; + long zone_zone_pgdat; + long zone_zone_mem_map; + long zone_name; + long zone_spanned_pages; + long zone_zone_start_pfn; + long zone_pages_min; + long zone_pages_low; + long zone_pages_high; + long zone_vm_stat; + long neighbour_next; + long neighbour_primary_key; + long neighbour_ha; + long neighbour_dev; + long neighbour_nud_state; + long neigh_table_hash_buckets; + long neigh_table_key_len; + long in_device_ifa_list; + long in_ifaddr_ifa_next; + long in_ifaddr_ifa_address; + long pci_dev_global_list; + long pci_dev_next; + long pci_dev_bus; + long pci_dev_devfn; + long pci_dev_class; + long pci_dev_device; + long pci_dev_vendor; + long pci_bus_number; + long resource_entry_t_from; + long resource_entry_t_num; + long resource_entry_t_name; + long resource_entry_t_next; + long resource_name; + long resource_start; + long resource_end; + long resource_sibling; + long resource_child; + long runqueue_curr; + long runqueue_idle; + long runqueue_active; + long runqueue_expired; + long runqueue_arrays; + long runqueue_cpu; + long cpu_s_idle; + long cpu_s_curr; + long prio_array_nr_active; + long prio_array_queue; + long user_regs_struct_ebp; + long user_regs_struct_esp; + long user_regs_struct_rip; + long user_regs_struct_cs; + long user_regs_struct_eflags; + long user_regs_struct_rsp; + long user_regs_struct_ss; + long e820map_nr_map; + long e820entry_addr; + long e820entry_size; + long e820entry_type; + long char_device_struct_next; + long char_device_struct_name; + long char_device_struct_fops; + long char_device_struct_major; + long gendisk_major; + long gendisk_disk_name; + long gendisk_fops; + long blk_major_name_next; + long blk_major_name_major; + long blk_major_name_name; + long radix_tree_root_height; + long radix_tree_root_rnode; + long x8664_pda_pcurrent; + long x8664_pda_data_offset; + long x8664_pda_kernelstack; + long x8664_pda_irqrsp; + long x8664_pda_irqstackptr; + long x8664_pda_level4_pgt; + long x8664_pda_cpunumber; + long x8664_pda_me; + long tss_struct_ist; + long mem_section_section_mem_map; + long vcpu_guest_context_user_regs; + long cpu_user_regs_eip; + long cpu_user_regs_esp; + long cpu_user_regs_rip; + long cpu_user_regs_rsp; + long unwind_table_core; + long unwind_table_init; + long unwind_table_address; + long unwind_table_size; + long unwind_table_link; + long unwind_table_name; + long rq_cfs; + long rq_rt; + long rq_nr_running; + long cfs_rq_rb_leftmost; + long cfs_rq_nr_running; + long cfs_rq_tasks_timeline; + long task_struct_se; + long sched_entity_run_node; + long rt_rq_active; + long kmem_cache_size; + long kmem_cache_objsize; + long kmem_cache_offset; + long kmem_cache_order; + long kmem_cache_local_node; + long kmem_cache_objects; + long kmem_cache_inuse; + long kmem_cache_align; + long kmem_cache_name; + long kmem_cache_list; + long kmem_cache_node; + long kmem_cache_cpu_slab; + long page_inuse; +/* long page_offset; use "old" page->offset */ + long page_slab; + long page_first_page; + long page_freelist; + long kmem_cache_node_nr_partial; + long kmem_cache_node_nr_slabs; + long kmem_cache_node_partial; + long kmem_cache_node_full; + long pid_numbers; + long upid_nr; + long upid_ns; + long upid_pid_chain; + long pid_tasks; + long kmem_cache_cpu_freelist; + long kmem_cache_cpu_page; + long kmem_cache_cpu_node; + long kmem_cache_flags; + long zone_nr_active; + long zone_nr_inactive; + long zone_all_unreclaimable; + long zone_present_pages; + long zone_flags; + long zone_pages_scanned; + long pcpu_info_vcpu; + long pcpu_info_idle; + long vcpu_struct_rq; + long task_struct_sched_info; + long sched_info_last_arrival; + long page_objects; + long kmem_cache_oo; + long char_device_struct_cdev; + long char_device_struct_baseminor; + long cdev_ops; + long probe_next; + long probe_dev; + long probe_data; + long kobj_map_probes; + long task_struct_prio; + long zone_watermark; + long module_sect_attrs; + long module_sect_attrs_attrs; + long module_sect_attrs_nsections; + long module_sect_attr_mattr; + long module_sect_attr_name; + long module_sect_attr_address; + long module_attribute_attr; + long attribute_owner; + long module_sect_attr_attr; + long module_sections_attrs; + long swap_info_struct_inuse_pages; + long s390_lowcore_psw_save_area; + long mm_struct_rss_stat; + long mm_rss_stat_count; + long module_module_init; + long module_init_text_size; + long cpu_context_save_fp; + long cpu_context_save_sp; + long cpu_context_save_pc; + long elf_prstatus_pr_pid; + long elf_prstatus_pr_reg; + long irq_desc_t_name; + long thread_info_cpu_context; + long unwind_table_list; + long unwind_table_start; + long unwind_table_stop; + long unwind_table_begin_addr; + long unwind_table_end_addr; + long unwind_idx_addr; + long unwind_idx_insn; + long signal_struct_nr_threads; + long module_init_size; + long module_percpu; + long radix_tree_node_slots; + long s390_stack_frame_back_chain; + long s390_stack_frame_r14; + long user_regs_struct_eip; + long user_regs_struct_rax; + long user_regs_struct_eax; + long user_regs_struct_rbx; + long user_regs_struct_ebx; + long user_regs_struct_rcx; + long user_regs_struct_ecx; + long user_regs_struct_rdx; + long user_regs_struct_edx; + long user_regs_struct_rsi; + long user_regs_struct_esi; + long user_regs_struct_rdi; + long user_regs_struct_edi; + long user_regs_struct_ds; + long user_regs_struct_es; + long user_regs_struct_fs; + long user_regs_struct_gs; + long user_regs_struct_rbp; + long user_regs_struct_r8; + long user_regs_struct_r9; + long user_regs_struct_r10; + long user_regs_struct_r11; + long user_regs_struct_r12; + long user_regs_struct_r13; + long user_regs_struct_r14; + long user_regs_struct_r15; + long sched_entity_cfs_rq; + long sched_entity_my_q; + long sched_entity_on_rq; + long task_struct_on_rq; + long cfs_rq_curr; + long irq_desc_t_irq_data; + long irq_desc_t_kstat_irqs; + long irq_desc_t_affinity; + long irq_data_chip; + long irq_data_affinity; + long kernel_stat_irqs; + long socket_alloc_vfs_inode; + long class_devices; + long class_p; + long class_private_devices; + long device_knode_class; + long device_node; + long gendisk_dev; + long gendisk_kobj; + long gendisk_part0; + long gendisk_queue; + long hd_struct_dev; + long klist_k_list; + long klist_node_n_klist; + long klist_node_n_node; + long kobject_entry; + long kset_list; + long request_list_count; + long request_queue_in_flight; + long request_queue_rq; + long subsys_private_klist_devices; + long subsystem_kset; + long mount_mnt_parent; + long mount_mnt_mountpoint; + long mount_mnt_list; + long mount_mnt_devname; + long mount_mnt; + long task_struct_exit_state; + long timekeeper_xtime; + long file_f_op; + long file_private_data; + long hstate_order; + long hugetlbfs_sb_info_hstate; + long idr_layer_ary; + long idr_layer_layer; + long idr_layers; + long idr_top; + long ipc_id_ary_p; + long ipc_ids_entries; + long ipc_ids_max_id; + long ipc_ids_ipcs_idr; + long ipc_ids_in_use; + long ipc_namespace_ids; + long kern_ipc_perm_deleted; + long kern_ipc_perm_key; + long kern_ipc_perm_mode; + long kern_ipc_perm_uid; + long kern_ipc_perm_id; + long kern_ipc_perm_seq; + long nsproxy_ipc_ns; + long shmem_inode_info_swapped; + long shmem_inode_info_vfs_inode; + long shm_file_data_file; + long shmid_kernel_shm_file; + long shmid_kernel_shm_nattch; + long shmid_kernel_shm_perm; + long shmid_kernel_shm_segsz; + long shmid_kernel_id; + long sem_array_sem_perm; + long sem_array_sem_id; + long sem_array_sem_nsems; + long msg_queue_q_perm; + long msg_queue_q_id; + long msg_queue_q_cbytes; + long msg_queue_q_qnum; + long super_block_s_fs_info; + long rq_timestamp; + long radix_tree_node_height; + long rb_root_rb_node; + long rb_node_rb_left; + long rb_node_rb_right; + long rt_prio_array_queue; + long task_struct_rt; + long sched_rt_entity_run_list; + long log_ts_nsec; + long log_len; + long log_text_len; + long log_dict_len; + long log_level; + long log_flags_level; + long timekeeper_xtime_sec; + long neigh_table_hash_mask; + long sched_rt_entity_my_q; + long neigh_table_hash_shift; + long neigh_table_nht_ptr; + long task_group_parent; + long task_group_css; + long cgroup_subsys_state_cgroup; + long cgroup_dentry; + long task_group_rt_rq; + long rt_rq_tg; + long task_group_cfs_rq; + long cfs_rq_tg; + long task_group_siblings; + long task_group_children; + long task_group_cfs_bandwidth; + long cfs_rq_throttled; + long task_group_rt_bandwidth; + long rt_rq_rt_throttled; + long rt_rq_highest_prio; + long rt_rq_rt_nr_running; + long vmap_area_va_start; + long vmap_area_va_end; + long vmap_area_list; + long vmap_area_flags; + long vmap_area_vm; + long hrtimer_cpu_base_clock_base; + long hrtimer_clock_base_offset; + long hrtimer_clock_base_active; + long hrtimer_clock_base_first; + long hrtimer_clock_base_get_time; + long hrtimer_base_first; + long hrtimer_base_pending; + long hrtimer_base_get_time; + long hrtimer_node; + long hrtimer_list; + long hrtimer_softexpires; + long hrtimer_expires; + long hrtimer_function; + long timerqueue_head_next; + long timerqueue_node_expires; + long timerqueue_node_node; + long ktime_t_tv64; + long ktime_t_sec; + long ktime_t_nsec; + long module_taints; + long module_gpgsig_ok; + long module_license_gplok; + long tnt_bit; + long tnt_true; + long tnt_false; + long task_struct_thread_context_fp; + long task_struct_thread_context_sp; + long task_struct_thread_context_pc; + long page_slab_page; + long trace_print_flags_mask; + long trace_print_flags_name; + long task_struct_rss_stat; + long task_rss_stat_count; + long page_s_mem; + long page_active; + long hstate_nr_huge_pages; + long hstate_free_huge_pages; + long hstate_name; + long cgroup_kn; + long kernfs_node_name; + long kernfs_node_parent; + long kmem_cache_cpu_partial; + long kmem_cache_cpu_cache; + long nsproxy_net_ns; + long atomic_t_counter; + long percpu_counter_count; + long mm_struct_mm_count; + long task_struct_thread_reg29; + long task_struct_thread_reg31; + long pt_regs_regs; + long pt_regs_cp0_badvaddr; + long address_space_page_tree; + long page_compound_head; + long irq_desc_irq_data; + long kmem_cache_node_total_objects; + long timer_base_vectors; + long request_queue_mq_ops; + long request_queue_queue_ctx; + long blk_mq_ctx_rq_dispatched; + long blk_mq_ctx_rq_completed; + long task_struct_stack; + long tnt_mod; + long radix_tree_node_shift; + long kmem_cache_red_left_pad; + long inactive_task_frame_ret_addr; + long sk_buff_head_next; + long sk_buff_head_qlen; + long sk_buff_next; + long sk_buff_len; + long sk_buff_data; + long nlmsghdr_nlmsg_type; + long module_arch; + long mod_arch_specific_num_orcs; + long mod_arch_specific_orc_unwind_ip; + long mod_arch_specific_orc_unwind; + long task_struct_policy; + long kmem_cache_random; + long pid_namespace_idr; + long idr_idr_rt; + long bpf_prog_aux; + long bpf_prog_type; + long bpf_prog_tag; + long bpf_prog_jited_len; + long bpf_prog_bpf_func; + long bpf_prog_len; + long bpf_prog_insnsi; + long bpf_prog_pages; + long bpf_map_map_type; + long bpf_map_map_flags; + long bpf_map_pages; + long bpf_map_key_size; + long bpf_map_value_size; + long bpf_map_max_entries; + long bpf_map_user; + long bpf_map_name; + long bpf_prog_aux_used_map_cnt; + long bpf_prog_aux_used_maps; + long bpf_prog_aux_load_time; + long bpf_prog_aux_user; + long user_struct_uid; + long idr_cur; + long kmem_cache_memcg_params; + long memcg_cache_params___root_caches_node; + long memcg_cache_params_children; + long memcg_cache_params_children_node; + long task_struct_pid_links; + long kernel_symbol_value; + long pci_dev_dev; + long pci_dev_hdr_type; + long pci_dev_pcie_flags_reg; + long pci_bus_node; + long pci_bus_devices; + long pci_bus_dev; + long pci_bus_children; + long pci_bus_parent; + long pci_bus_self; + long device_kobj; + long kobject_name; + long memory_block_dev; + long memory_block_start_section_nr; + long memory_block_end_section_nr; + long memory_block_state; + long memory_block_nid; + long mem_section_pageblock_flags; + long bus_type_p; + long device_private_device; + long device_private_knode_bus; + long xarray_xa_head; + long xa_node_slots; + long xa_node_shift; + long hd_struct_dkstats; + long disk_stats_in_flight; + long cpu_context_save_r7; + long dentry_d_sb; + long device_private_knode_class; + long timerqueue_head_rb_root; + long rb_root_cached_rb_leftmost; +}; + +struct size_table { /* stash of commonly-used sizes */ + long page; + long free_area_struct; + long zone_struct; + long free_area; + long zone; + long kmem_slab_s; + long kmem_cache_s; + long kmem_bufctl_t; + long slab_s; + long slab; + long cpucache_s; + long array_cache; + long swap_info_struct; + long mm_struct; + long vm_area_struct; + long pglist_data; + long page_cache_bucket; + long pt_regs; + long task_struct; + long thread_info; + long softirq_state; + long desc_struct; + long umode_t; + long dentry; + long files_struct; + long fdtable; + long fs_struct; + long file; + long inode; + long vfsmount; + long super_block; + long irqdesc; + long module; + long list_head; + long hlist_node; + long hlist_head; + long irq_cpustat_t; + long cpuinfo_x86; + long cpuinfo_ia64; + long timer_list; + long timer_vec_root; + long timer_vec; + long tvec_root_s; + long tvec_s; + long tvec_t_base_s; + long wait_queue; + long __wait_queue; + long device; + long net_device; + long sock; + long signal_struct; + long sigpending_signal; + long signal_queue; + long sighand_struct; + long sigqueue; + long k_sigaction; + long resource_entry_t; + long resource; + long runqueue; + long irq_desc_t; + long task_union; + long thread_union; + long prio_array; + long user_regs_struct; + long switch_stack; + long vm_area_struct_vm_flags; + long e820map; + long e820entry; + long cpu_s; + long pgd_t; + long kallsyms_header; + long kallsyms_symbol; + long kallsyms_section; + long irq_ctx; + long block_device; + long blk_major_name; + long gendisk; + long address_space; + long char_device_struct; + long inet_sock; + long in6_addr; + long socket; + long spinlock_t; + long radix_tree_root; + long radix_tree_node; + long x8664_pda; + long ppc64_paca; + long gate_struct; + long tss_struct; + long task_struct_start_time; + long cputime_t; + long mem_section; + long pid_link; + long unwind_table; + long rlimit; + long kmem_cache; + long kmem_cache_node; + long upid; + long kmem_cache_cpu; + long cfs_rq; + long pcpu_info; + long vcpu_struct; + long cdev; + long probe; + long kobj_map; + long page_flags; + long module_sect_attr; + long task_struct_utime; + long task_struct_stime; + long cpu_context_save; + long elf_prstatus; + long note_buf; + long unwind_idx; + long softirq_action; + long irq_data; + long s390_stack_frame; + long percpu_data; + long sched_entity; + long kernel_stat; + long subsystem; + long class_private; + long rq_in_flight; + long class_private_devices; + long mount; + long hstate; + long ipc_ids; + long shmid_kernel; + long sem_array; + long msg_queue; + long log; + long log_level; + long rt_rq; + long task_group; + long vmap_area; + long hrtimer_clock_base; + long hrtimer_base; + long tnt; + long trace_print_flags; + long task_struct_flags; + long timer_base; + long taint_flag; + long nlmsghdr; + long nlmsghdr_nlmsg_type; + long sk_buff_head_qlen; + long sk_buff_len; + long orc_entry; + long task_struct_policy; + long pid; + long bpf_prog; + long bpf_prog_aux; + long bpf_map; + long bpf_insn; + long xarray; + long xa_node; +}; + +struct array_table { + int kmem_cache_s_name; + int kmem_cache_s_c_name; + int kmem_cache_s_array; + int kmem_cache_s_cpudata; + int irq_desc; + int irq_action; + int log_buf; + int timer_vec_vec; + int timer_vec_root_vec; + int tvec_s_vec; + int tvec_root_s_vec; + int page_hash_table; + int net_device_name; + int neigh_table_hash_buckets; + int neighbour_ha; + int swap_info; + int pglist_data_node_zones; + int zone_struct_free_area; + int zone_free_area; + int free_area; + int free_area_DIMENSION; + int prio_array_queue; + int height_to_maxindex; + int pid_hash; + int kmem_cache_node; + int kmem_cache_cpu_slab; + int rt_prio_array_queue; + int height_to_maxnodes; + int task_struct_rlim; + int signal_struct_rlim; + int vm_numa_stat; +}; + +/* + * The following set of macros use gdb to determine structure, union, + * or member sizes/offsets. They should be used only during initialization + * of the offset_table or size_table, or with data structures whose names + * or members are only known/specified during runtime. + */ +#define MEMBER_SIZE_REQUEST ((struct datatype_member *)(-1)) +#define ANON_MEMBER_OFFSET_REQUEST ((struct datatype_member *)(-2)) +#define MEMBER_TYPE_REQUEST ((struct datatype_member *)(-3)) +#define STRUCT_SIZE_REQUEST ((struct datatype_member *)(-4)) +#define MEMBER_TYPE_NAME_REQUEST ((struct datatype_member *)(-5)) + +#define STRUCT_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) +#define UNION_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) +#define STRUCT_EXISTS(X) (datatype_info((X), NULL, STRUCT_SIZE_REQUEST) >= 0) +#define DATATYPE_SIZE(X) datatype_info((X)->name, NULL, (X)) +#define MEMBER_OFFSET(X,Y) datatype_info((X), (Y), NULL) +#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 MEMBER_TYPE_NAME(X,Y) ((char *)datatype_info((X), (Y), MEMBER_TYPE_NAME_REQUEST)) +#define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) + +/* + * The following set of macros can only be used with pre-intialized fields + * in the offset table, size table or array_table. + */ +#define OFFSET(X) (OFFSET_verify(offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) +#define SIZE(X) (SIZE_verify(size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X)) +#define INVALID_OFFSET (-1) +#define INVALID_MEMBER(X) (offset_table.X == INVALID_OFFSET) +#define INVALID_SIZE(X) (size_table.X == -1) +#define VALID_SIZE(X) (size_table.X >= 0) +#define VALID_STRUCT(X) (size_table.X >= 0) +#define VALID_MEMBER(X) (offset_table.X >= 0) +#define ARRAY_LENGTH(X) (array_table.X) +#define ASSIGN_OFFSET(X) (offset_table.X) +#define ASSIGN_SIZE(X) (size_table.X) +#define OFFSET_OPTION(X,Y) (OFFSET_option(offset_table.X, offset_table.Y, (char *)__FUNCTION__, __FILE__, __LINE__, #X, #Y)) +#define SIZE_OPTION(X,Y) (SIZE_option(size_table.X, size_table.Y, (char *)__FUNCTION__, __FILE__, __LINE__, #X, #Y)) + +#define MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = MEMBER_OFFSET(Y, Z)) +#define STRUCT_SIZE_INIT(X, Y) (ASSIGN_SIZE(X) = STRUCT_SIZE(Y)) +#define ARRAY_LENGTH_INIT(A, B, C, D, E) ((A) = get_array_length(C, D, E)) +#define ARRAY_LENGTH_INIT_ALT(A, B, C, D, E) ((A) = get_array_length_alt(B, C, D, E)) +#define MEMBER_SIZE_INIT(X, Y, Z) (ASSIGN_SIZE(X) = MEMBER_SIZE(Y, Z)) +#define ANON_MEMBER_OFFSET_INIT(X, Y, Z) (ASSIGN_OFFSET(X) = ANON_MEMBER_OFFSET(Y, Z)) + +/* + * For use with non-debug kernels. + */ +struct builtin_debug_table { + char *release; + char *machine_type; + struct offset_table *offset_table; + struct size_table *size_table; + struct array_table *array_table; +}; + +/* + * Facilitators for pulling correctly-sized data out of a buffer at a + * known address. + */ + +#ifdef NEED_ALIGNED_MEM_ACCESS + +#define DEF_LOADER(TYPE) \ +static inline TYPE \ +load_##TYPE (char *addr) \ +{ \ + TYPE ret; \ + size_t i = sizeof(TYPE); \ + while (i--) \ + ((char *)&ret)[i] = addr[i]; \ + return ret; \ +} + +DEF_LOADER(int); +DEF_LOADER(uint); +DEF_LOADER(long); +DEF_LOADER(ulong); +DEF_LOADER(ulonglong); +DEF_LOADER(ushort); +DEF_LOADER(short); +typedef void *pointer_t; +DEF_LOADER(pointer_t); + +#define LOADER(TYPE) load_##TYPE + +#define INT(ADDR) LOADER(int) ((char *)(ADDR)) +#define UINT(ADDR) LOADER(uint) ((char *)(ADDR)) +#define LONG(ADDR) LOADER(long) ((char *)(ADDR)) +#define ULONG(ADDR) LOADER(ulong) ((char *)(ADDR)) +#define ULONGLONG(ADDR) LOADER(ulonglong) ((char *)(ADDR)) +#define ULONG_PTR(ADDR) ((ulong *) (LOADER(pointer_t) ((char *)(ADDR)))) +#define USHORT(ADDR) LOADER(ushort) ((char *)(ADDR)) +#define SHORT(ADDR) LOADER(short) ((char *)(ADDR)) +#define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR))) +#define VOID_PTR(ADDR) ((void *) (LOADER(pointer_t) ((char *)(ADDR)))) + +#else + +#define INT(ADDR) *((int *)((char *)(ADDR))) +#define UINT(ADDR) *((uint *)((char *)(ADDR))) +#define LONG(ADDR) *((long *)((char *)(ADDR))) +#define ULONG(ADDR) *((ulong *)((char *)(ADDR))) +#define ULONGLONG(ADDR) *((ulonglong *)((char *)(ADDR))) +#define ULONG_PTR(ADDR) *((ulong **)((char *)(ADDR))) +#define USHORT(ADDR) *((ushort *)((char *)(ADDR))) +#define SHORT(ADDR) *((short *)((char *)(ADDR))) +#define UCHAR(ADDR) *((unsigned char *)((char *)(ADDR))) +#define VOID_PTR(ADDR) *((void **)((char *)(ADDR))) + +#endif /* NEED_ALIGNED_MEM_ACCESS */ + +struct node_table { + int node_id; + ulong pgdat; + ulong mem_map; + ulong size; + ulong present; + ulonglong start_paddr; + ulong start_mapnr; +}; + +struct meminfo; +struct slab_data; + +#define VMA_CACHE (20) + +struct vm_table { /* kernel VM-related data */ + ulong flags; + ulong kernel_pgd[NR_CPUS]; + ulong high_memory; + ulong vmalloc_start; + ulong mem_map; + long total_pages; + ulong totalram_pages; + ulong totalhigh_pages; + ulong num_physpages; + ulong max_mapnr; + ulong kmem_max_c_num; + ulong kmem_max_limit; + ulong kmem_max_cpus; + ulong kmem_cache_count; + ulong kmem_cache_len_nodes; + ulong PG_reserved; + ulong PG_slab; + ulong PG_head_tail_mask; + int kmem_cache_namelen; + ulong page_hash_table; + int page_hash_table_len; + int paddr_prlen; + int numnodes; + int nr_zones; + int nr_free_areas; + struct node_table *node_table; + void (*dump_free_pages)(struct meminfo *); + void (*dump_kmem_cache)(struct meminfo *); + struct slab_data *slab_data; + uint nr_swapfiles; + ulong last_swap_read; + char *swap_info_struct; + char *vma_cache; + ulong cached_vma[VMA_CACHE]; + ulong cached_vma_hits[VMA_CACHE]; + int vma_cache_index; + ulong vma_cache_fills; + void *mem_sec; + char *mem_section; + int ZONE_HIGHMEM; + ulong *node_online_map; + int node_online_map_len; + int nr_vm_stat_items; + char **vm_stat_items; + int cpu_slab_type; + int nr_vm_event_items; + char **vm_event_items; + int nr_bad_slab_caches; + ulong *bad_slab_caches; + int nr_pageflags; + struct pageflags_data { + ulong mask; + char *name; + } *pageflags_data; + ulong max_mem_section_nr; +}; + +#define NODES (0x1) +#define ZONES (0x2) +#define PERCPU_KMALLOC_V1 (0x4) +#define COMMON_VADDR (0x8) +#define KMEM_CACHE_INIT (0x10) +#define V_MEM_MAP (0x20) +#define PERCPU_KMALLOC_V2 (0x40) +#define KMEM_CACHE_UNAVAIL (0x80) +#define FLATMEM (0x100) +#define DISCONTIGMEM (0x200) +#define SPARSEMEM (0x400) +#define SPARSEMEM_EX (0x800) +#define PERCPU_KMALLOC_V2_NODES (0x1000) +#define KMEM_CACHE_DELAY (0x2000) +#define NODES_ONLINE (0x4000) +#define VM_STAT (0x8000) +#define KMALLOC_SLUB (0x10000) +#define CONFIG_NUMA (0x20000) +#define VM_EVENT (0x40000) +#define PGCNT_ADJ (0x80000) +#define VM_INIT (0x100000) +#define SWAPINFO_V1 (0x200000) +#define SWAPINFO_V2 (0x400000) +#define NODELISTS_IS_PTR (0x800000) +#define KMALLOC_COMMON (0x1000000) +#define USE_VMAP_AREA (0x2000000) +#define PAGEFLAGS (0x4000000) +#define SLAB_OVERLOAD_PAGE (0x8000000) +#define SLAB_CPU_CACHE (0x10000000) +#define SLAB_ROOT_CACHES (0x20000000) + +#define IS_FLATMEM() (vt->flags & FLATMEM) +#define IS_DISCONTIGMEM() (vt->flags & DISCONTIGMEM) +#define IS_SPARSEMEM() (vt->flags & SPARSEMEM) +#define IS_SPARSEMEM_EX() (vt->flags & SPARSEMEM_EX) + +#define COMMON_VADDR_SPACE() (vt->flags & COMMON_VADDR) +#define PADDR_PRLEN (vt->paddr_prlen) + +struct datatype_member { /* minimal definition of a structure/union */ + char *name; /* and possibly a member within it */ + char *member; + ulong type; + long size; + long member_offset; + long member_size; + int member_typecode; + ulong flags; + char *tagname; /* tagname and value for enums */ + long value; + ulong vaddr; +}; + +#define union_name struct_name + +struct list_data { /* generic structure used by do_list() to walk */ + ulong flags; /* through linked lists in the kernel */ + ulong start; + long member_offset; + long list_head_offset; + ulong end; + ulong searchfor; + char **structname; + int structname_args; + char *header; + ulong *list_ptr; + int (*callback_func)(void *, void *); + void *callback_data; + long struct_list_offset; +}; +#define LIST_OFFSET_ENTERED (VERBOSE << 1) +#define LIST_START_ENTERED (VERBOSE << 2) +#define LIST_HEAD_FORMAT (VERBOSE << 3) +#define LIST_HEAD_POINTER (VERBOSE << 4) +#define RETURN_ON_DUPLICATE (VERBOSE << 5) +#define RETURN_ON_LIST_ERROR (VERBOSE << 6) +#define LIST_STRUCT_RADIX_10 (VERBOSE << 7) +#define LIST_STRUCT_RADIX_16 (VERBOSE << 8) +#define LIST_HEAD_REVERSE (VERBOSE << 9) +#define LIST_ALLOCATE (VERBOSE << 10) +#define LIST_CALLBACK (VERBOSE << 11) +#define CALLBACK_RETURN (VERBOSE << 12) +#define LIST_PARSE_MEMBER (VERBOSE << 13) +#define LIST_READ_MEMBER (VERBOSE << 14) +#define LIST_BRENT_ALGO (VERBOSE << 15) + +struct tree_data { + ulong flags; + ulong start; + long node_member_offset; + char **structname; + int structname_args; + int count; +}; + +#define TREE_ROOT_OFFSET_ENTERED (VERBOSE << 1) +#define TREE_NODE_OFFSET_ENTERED (VERBOSE << 2) +#define TREE_NODE_POINTER (VERBOSE << 3) +#define TREE_POSITION_DISPLAY (VERBOSE << 4) +#define TREE_STRUCT_RADIX_10 (VERBOSE << 5) +#define TREE_STRUCT_RADIX_16 (VERBOSE << 6) +#define TREE_PARSE_MEMBER (VERBOSE << 7) +#define TREE_READ_MEMBER (VERBOSE << 8) +#define TREE_LINEAR_ORDER (VERBOSE << 9) + +#define ALIAS_RUNTIME (1) +#define ALIAS_RCLOCAL (2) +#define ALIAS_RCHOME (3) +#define ALIAS_BUILTIN (4) + +struct alias_data { /* command alias storage */ + struct alias_data *next; + char *alias; + int argcnt; + int size; + int origin; + char *args[MAXARGS]; + char argbuf[1]; +}; + +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +}; + +struct rb_root +{ + struct rb_node *rb_node; +}; + +#define NUMBER_STACKFRAMES 4 + +#define SAVE_RETURN_ADDRESS(retaddr) \ +{ \ + int i; \ + int saved_stacks; \ + \ + saved_stacks = backtrace((void **)retaddr, NUMBER_STACKFRAMES); \ + \ + /* explicitely zero out the invalid addresses */ \ + for (i = saved_stacks; i < NUMBER_STACKFRAMES; i++) \ + retaddr[i] = 0; \ +} + +#endif /* !GDB_COMMON */ + + +#define SYMBOL_NAME_USED (0x1) +#define MODULE_SYMBOL (0x2) +#define IS_MODULE_SYMBOL(SYM) ((SYM)->flags & MODULE_SYMBOL) + +struct syment { + ulong value; + char *name; + struct syment *val_hash_next; + struct syment *name_hash_next; + char type; + unsigned char cnt; + unsigned char flags; + unsigned char pad2; +}; + +#define NAMESPACE_INIT (1) +#define NAMESPACE_REUSE (2) +#define NAMESPACE_FREE (3) +#define NAMESPACE_INSTALL (4) +#define NAMESPACE_COMPLETE (5) + +struct symbol_namespace { + char *address; + size_t size; + long index; + long cnt; +}; + +struct downsized { + char *name; + struct downsized *next; +}; + +#define SYMVAL_HASH (512) +#define SYMVAL_HASH_INDEX(vaddr) \ + (((vaddr) >> machdep->pageshift) % SYMVAL_HASH) + +#define SYMNAME_HASH (512) +#define SYMNAME_HASH_INDEX(name) \ + ((name[0] ^ (name[strlen(name)-1] * name[strlen(name)/2])) % SYMNAME_HASH) + +#define PATCH_KERNEL_SYMBOLS_START ((char *)(1)) +#define PATCH_KERNEL_SYMBOLS_STOP ((char *)(2)) + +#ifndef GDB_COMMON + +struct symbol_table_data { + ulong flags; +#ifdef GDB_5_3 + struct _bfd *bfd; +#else + struct bfd *bfd; +#endif + struct sec *sections; + struct syment *symtable; + struct syment *symend; + long symcnt; + ulong syment_size; + struct symval_hash_chain { + struct syment *val_hash_head; + struct syment *val_hash_last; + } symval_hash[SYMVAL_HASH]; + double val_hash_searches; + double val_hash_iterations; + struct syment *symname_hash[SYMNAME_HASH]; + struct symbol_namespace kernel_namespace; + struct syment *ext_module_symtable; + struct syment *ext_module_symend; + long ext_module_symcnt; + struct symbol_namespace ext_module_namespace; + int mods_installed; + struct load_module *current; + struct load_module *load_modules; + off_t dwarf_eh_frame_file_offset; + ulong dwarf_eh_frame_size; + ulong first_ksymbol; + ulong __per_cpu_start; + ulong __per_cpu_end; + off_t dwarf_debug_frame_file_offset; + ulong dwarf_debug_frame_size; + ulong first_section_start; + ulong last_section_end; + ulong _stext_vmlinux; + struct downsized downsized; + ulong divide_error_vmlinux; + ulong idt_table_vmlinux; + ulong saved_command_line_vmlinux; + ulong pti_init_vmlinux; + ulong kaiser_init_vmlinux; + int kernel_symbol_type; +}; + +/* flags for st */ +#define KERNEL_SYMS (0x1) +#define MODULE_SYMS (0x2) +#define LOAD_MODULE_SYMS (0x4) +#define INSMOD_BUILTIN (0x8) +#define GDB_SYMS_PATCHED (0x10) +#define GDB_PATCHED() (st->flags & GDB_SYMS_PATCHED) +#define NO_SEC_LOAD (0x20) +#define NO_SEC_CONTENTS (0x40) +#define FORCE_DEBUGINFO (0x80) +#define CRC_MATCHES (0x100) +#define ADD_SYMBOL_FILE (0x200) +#define USE_OLD_ADD_SYM (0x400) +#define PERCPU_SYMS (0x800) +#define MODSECT_UNKNOWN (0x1000) +#define MODSECT_V1 (0x2000) +#define MODSECT_V2 (0x4000) +#define MODSECT_V3 (0x8000) +#define MODSECT_VMASK (MODSECT_V1|MODSECT_V2|MODSECT_V3) +#define NO_STRIP (0x10000) + +#define NO_LINE_NUMBERS() ((st->flags & GDB_SYMS_PATCHED) && !(kt->flags2 & KASLR)) + +#endif /* !GDB_COMMON */ + +#define ALL_MODULES (0) + +#define MAX_MOD_NAMELIST (256) +#define MAX_MOD_NAME (64) +#define MAX_MOD_SEC_NAME (64) + +#define MOD_EXT_SYMS (0x1) +#define MOD_LOAD_SYMS (0x2) +#define MOD_REMOTE (0x4) +#define MOD_KALLSYMS (0x8) +#define MOD_INITRD (0x10) +#define MOD_NOPATCH (0x20) +#define MOD_INIT (0x40) +#define MOD_DO_READNOW (0x80) + +#define SEC_FOUND (0x10000) + +struct mod_section_data { +#if defined(GDB_5_3) || defined(GDB_6_0) + struct sec *section; +#else + struct bfd_section *section; +#endif + char name[MAX_MOD_SEC_NAME]; + ulong offset; + ulong size; + int priority; + int flags; +}; + +struct load_module { + ulong mod_base; + ulong module_struct; + long mod_size; + char mod_namelist[MAX_MOD_NAMELIST]; + char mod_name[MAX_MOD_NAME]; + ulong mod_flags; + struct syment *mod_symtable; + struct syment *mod_symend; + long mod_ext_symcnt; + struct syment *mod_ext_symtable; + struct syment *mod_ext_symend; + long mod_load_symcnt; + struct syment *mod_load_symtable; + struct syment *mod_load_symend; + long mod_symalloc; + struct symbol_namespace mod_load_namespace; + ulong mod_size_of_struct; + ulong mod_text_start; + ulong mod_etext_guess; + ulong mod_rodata_start; + ulong mod_data_start; + ulong mod_bss_start; + int mod_sections; + struct mod_section_data *mod_section_data; + ulong mod_init_text_size; + ulong mod_init_module_ptr; + ulong mod_init_size; + struct syment *mod_init_symtable; + struct syment *mod_init_symend; + ulong mod_percpu; + ulong mod_percpu_size; + struct objfile *loaded_objfile; +}; + +#define IN_MODULE(A,L) \ + (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size))) + +#define IN_MODULE_INIT(A,L) \ + (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size))) + +#define IN_MODULE_PERCPU(A,L) \ + (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size))) + +#define MODULE_PERCPU_SYMS_LOADED(L) ((L)->mod_percpu && (L)->mod_percpu_size) + +#ifndef GDB_COMMON + +#define KVADDR (0x1) +#define UVADDR (0x2) +#define PHYSADDR (0x4) +#define XENMACHADDR (0x8) +#define FILEADDR (0x10) +#define AMBIGUOUS (~0) + +#define USE_USER_PGD (UVADDR << 2) + +#define VERIFY_ADDR (0x8) /* vm_area_dump() flags -- must follow */ +#define PRINT_INODES (0x10) /* KVADDR, UVADDR, and PHYSADDR */ +#define PRINT_MM_STRUCT (0x20) +#define PRINT_VMA_STRUCTS (0x40) +#define PRINT_SINGLE_VMA (0x80) +#define PRINT_RADIX_10 (0x100) +#define PRINT_RADIX_16 (0x200) +#define PRINT_NRPAGES (0x400) + +#define MIN_PAGE_SIZE (4096) + +#define PTOB(X) ((ulonglong)(X) << machdep->pageshift) +#define BTOP(X) ((ulonglong)(X) >> machdep->pageshift) + +#define PAGESIZE() (machdep->pagesize) +#define PAGESHIFT() (machdep->pageshift) + +#define PAGEOFFSET(X) (((ulong)(X)) & machdep->pageoffset) +#define VIRTPAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) +#define PHYSPAGEBASE(X) (((physaddr_t)(X)) & (physaddr_t)machdep->pagemask) + +/* + * Sparse memory stuff + * These must follow the definitions in the kernel mmzone.h + */ +#define SECTION_SIZE_BITS() (machdep->section_size_bits) +#define MAX_PHYSMEM_BITS() (machdep->max_physmem_bits) +#define SECTIONS_SHIFT() (MAX_PHYSMEM_BITS() - SECTION_SIZE_BITS()) +#define PA_SECTION_SHIFT() (SECTION_SIZE_BITS()) +#define PFN_SECTION_SHIFT() (SECTION_SIZE_BITS() - PAGESHIFT()) +#define NR_MEM_SECTIONS() (1UL << SECTIONS_SHIFT()) +#define PAGES_PER_SECTION() (1UL << PFN_SECTION_SHIFT()) +#define PAGE_SECTION_MASK() (~(PAGES_PER_SECTION()-1)) + +#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT()) +#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT()) + +#define SECTIONS_PER_ROOT() (machdep->sections_per_root) + +/* CONFIG_SPARSEMEM_EXTREME */ +#define _SECTIONS_PER_ROOT_EXTREME() (PAGESIZE() / SIZE(mem_section)) +/* !CONFIG_SPARSEMEM_EXTREME */ +#define _SECTIONS_PER_ROOT() (1) + +#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT()) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define NR_SECTION_ROOTS() (DIV_ROUND_UP(NR_MEM_SECTIONS(), SECTIONS_PER_ROOT())) +#define SECTION_ROOT_MASK() (SECTIONS_PER_ROOT() - 1) + +struct QEMUCPUSegment { + uint32_t selector; + uint32_t limit; + uint32_t flags; + uint32_t pad; + uint64_t base; +}; + +typedef struct QEMUCPUSegment QEMUCPUSegment; + +struct QEMUCPUState { + uint32_t version; + uint32_t size; + uint64_t rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; + uint64_t rip, rflags; + QEMUCPUSegment cs, ds, es, fs, gs, ss; + QEMUCPUSegment ldt, tr, gdt, idt; + uint64_t cr[5]; +}; + +typedef struct QEMUCPUState QEMUCPUState; + +/* + * Machine specific stuff + */ + +#ifdef ARM +#define _32BIT_ +#define MACHINE_TYPE "ARM" + +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) + +#define PTOV(X) \ + ((unsigned long)(X)-(machdep->machspec->phys_base)+(machdep->kvbase)) +#define VTOP(X) \ + ((unsigned long)(X)-(machdep->kvbase)+(machdep->machspec->phys_base)) + +#define IS_VMALLOC_ADDR(X) arm_is_vmalloc_addr((ulong)(X)) + +#define DEFAULT_MODULES_VADDR (machdep->kvbase - 16 * 1024 * 1024) +#define MODULES_VADDR (machdep->machspec->modules_vaddr) +#define MODULES_END (machdep->machspec->modules_end) +#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) +#define VMALLOC_END (machdep->machspec->vmalloc_end) + +#define PGDIR_SHIFT (21) +#define PTRS_PER_PTE (512) +#define PTRS_PER_PGD (2048) + +#define PGD_OFFSET(vaddr) ((vaddr) >> PGDIR_SHIFT) +#define PTE_OFFSET(vaddr) (((vaddr) >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) + +#define __SWP_TYPE_SHIFT 3 +#define __SWP_TYPE_BITS 6 +#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) +#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) + +#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) +#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) + +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#define _SECTION_SIZE_BITS 28 +#define _MAX_PHYSMEM_BITS 32 + +/*add for LPAE*/ +typedef unsigned long long u64; +typedef signed int s32; +typedef u64 pgd_t; +typedef u64 pmd_t; +typedef u64 pte_t; + +#define PMDSIZE() (PAGESIZE()) +#define LPAE_PGDIR_SHIFT (30) +#define LPAE_PMDIR_SHIFT (21) + +#define LPAE_PGD_OFFSET(vaddr) ((vaddr) >> LPAE_PGDIR_SHIFT) +#define LPAE_PMD_OFFSET(vaddr) (((vaddr) >> LPAE_PMDIR_SHIFT) & \ + ((1<<(LPAE_PGDIR_SHIFT-LPAE_PMDIR_SHIFT))-1)) + +#define _SECTION_SIZE_BITS_LPAE 28 +#define _MAX_PHYSMEM_BITS_LPAE 36 + +/* + * #define PTRS_PER_PTE 512 + * #define PTRS_PER_PMD 512 + * #define PTRS_PER_PGD 4 + * + */ + +#define LPAE_PGDIR_SIZE() 32 +#define LPAE_PGDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PGDIR_SIZE() - 1)) + +#define LPAE_PMDIR_SIZE() 4096 +#define LPAE_PMDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PMDIR_SIZE() - 1)) + +#define LPAE_PTEDIR_SIZE() 4096 +#define LPAE_PTEDIR_OFFSET(X) (((ulong)(X)) & (LPAE_PTEDIR_SIZE() - 1)) + +/*section size for LPAE is 2MiB*/ +#define LPAE_SECTION_PAGE_MASK (~((MEGABYTES(2))-1)) + +#define _PHYSICAL_MASK_LPAE ((1ULL << _MAX_PHYSMEM_BITS_LPAE) - 1) +#define PAGE_BASE_MASK ((u64)((s32)machdep->pagemask & _PHYSICAL_MASK_LPAE)) +#define LPAE_PAGEBASE(X) (((ulonglong)(X)) & PAGE_BASE_MASK) + +#define LPAE_VTOP(X) \ + ((unsigned long long)(unsigned long)(X) - \ + (machdep->kvbase) + (machdep->machspec->phys_base)) + +#define IS_LAST_PGD_READ_LPAE(pgd) ((pgd) == \ + machdep->machspec->last_pgd_read_lpae) +#define IS_LAST_PMD_READ_LPAE(pmd) ((pmd) == \ + machdep->machspec->last_pmd_read_lpae) +#define IS_LAST_PTBL_READ_LPAE(ptbl) ((ptbl) == \ + machdep->machspec->last_ptbl_read_lpae) + +#define FILL_PGD_LPAE(PGD, TYPE, SIZE) \ + if (!IS_LAST_PGD_READ_LPAE(PGD)) { \ + readmem((ulonglong)(PGD), TYPE, machdep->pgd, \ + SIZE, "pmd page", FAULT_ON_ERROR); \ + machdep->machspec->last_pgd_read_lpae \ + = (ulonglong)(PGD); \ + } +#define FILL_PMD_LPAE(PMD, TYPE, SIZE) \ + if (!IS_LAST_PMD_READ_LPAE(PMD)) { \ + readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ + SIZE, "pmd page", FAULT_ON_ERROR); \ + machdep->machspec->last_pmd_read_lpae \ + = (ulonglong)(PMD); \ + } + +#define FILL_PTBL_LPAE(PTBL, TYPE, SIZE) \ + if (!IS_LAST_PTBL_READ_LPAE(PTBL)) { \ + readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ + SIZE, "page table", FAULT_ON_ERROR); \ + machdep->machspec->last_ptbl_read_lpae \ + = (ulonglong)(PTBL); \ + } +#endif /* ARM */ + +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif + +#ifdef ARM64 +#define _64BIT_ +#define MACHINE_TYPE "ARM64" + +#define PTOV(X) \ + ((unsigned long)(X)-(machdep->machspec->phys_offset)+(machdep->machspec->page_offset)) + +#define VTOP(X) arm64_VTOP((ulong)(X)) + +#define USERSPACE_TOP (machdep->machspec->userspace_top) +#define PAGE_OFFSET (machdep->machspec->page_offset) +#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) +#define VMALLOC_END (machdep->machspec->vmalloc_end) +#define VMEMMAP_VADDR (machdep->machspec->vmemmap_vaddr) +#define VMEMMAP_END (machdep->machspec->vmemmap_end) +#define MODULES_VADDR (machdep->machspec->modules_vaddr) +#define MODULES_END (machdep->machspec->modules_end) + +#define IS_VMALLOC_ADDR(X) arm64_IS_VMALLOC_ADDR((ulong)(X)) + +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) + +/* + * 48-bit physical address supported. + */ +#define PHYS_MASK_SHIFT (48) +#define PHYS_MASK (((1UL) << PHYS_MASK_SHIFT) - 1) + +typedef signed int s32; + +/* + * 3-levels / 4K pages + */ +#define PTRS_PER_PGD_L3_4K (512) +#define PTRS_PER_PMD_L3_4K (512) +#define PTRS_PER_PTE_L3_4K (512) +#define PGDIR_SHIFT_L3_4K (30) +#define PGDIR_SIZE_L3_4K ((1UL) << PGDIR_SHIFT_L3_4K) +#define PGDIR_MASK_L3_4K (~(PGDIR_SIZE_L3_4K-1)) +#define PMD_SHIFT_L3_4K (21) +#define PMD_SIZE_L3_4K (1UL << PMD_SHIFT_L3_4K) +#define PMD_MASK_L3_4K (~(PMD_SIZE_L3_4K-1)) + +/* + * 4-levels / 4K pages + * 48-bit VA + */ +#define PTRS_PER_PGD_L4_4K ((1UL) << (48 - 39)) +#define PTRS_PER_PUD_L4_4K (512) +#define PTRS_PER_PMD_L4_4K (512) +#define PTRS_PER_PTE_L4_4K (512) +#define PGDIR_SHIFT_L4_4K (39) +#define PGDIR_SIZE_L4_4K ((1UL) << PGDIR_SHIFT_L4_4K) +#define PGDIR_MASK_L4_4K (~(PGDIR_SIZE_L4_4K-1)) +#define PUD_SHIFT_L4_4K (30) +#define PUD_SIZE_L4_4K ((1UL) << PUD_SHIFT_L4_4K) +#define PUD_MASK_L4_4K (~(PUD_SIZE_L4_4K-1)) +#define PMD_SHIFT_L4_4K (21) +#define PMD_SIZE_L4_4K (1UL << PMD_SHIFT_L4_4K) +#define PMD_MASK_L4_4K (~(PMD_SIZE_L4_4K-1)) + +#define PGDIR_SIZE_48VA (1UL << ((48 - 39) + 3)) +#define PGDIR_MASK_48VA (~(PGDIR_SIZE_48VA - 1)) +#define PGDIR_OFFSET_48VA(X) (((ulong)(X)) & (PGDIR_SIZE_48VA - 1)) + +/* + * 3-levels / 64K pages + */ +#define PTRS_PER_PGD_L3_64K (64) +#define PTRS_PER_PMD_L3_64K (8192) +#define PTRS_PER_PTE_L3_64K (8192) +#define PGDIR_SHIFT_L3_64K (42) +#define PGDIR_SIZE_L3_64K ((1UL) << PGDIR_SHIFT_L3_64K) +#define PGDIR_MASK_L3_64K (~(PGDIR_SIZE_L3_64K-1)) +#define PMD_SHIFT_L3_64K (29) +#define PMD_SIZE_L3_64K (1UL << PMD_SHIFT_L3_64K) +#define PMD_MASK_L3_64K (~(PMD_SIZE_L3_64K-1)) +#define PGDIR_OFFSET_L3_64K(X) (((ulong)(X)) & ((machdep->ptrs_per_pgd * 8) - 1)) + +/* + * 2-levels / 64K pages + */ +#define PTRS_PER_PGD_L2_64K (8192) +#define PTRS_PER_PTE_L2_64K (8192) +#define PGDIR_SHIFT_L2_64K (29) +#define PGDIR_SIZE_L2_64K ((1UL) << PGDIR_SHIFT_L2_64K) +#define PGDIR_MASK_L2_64K (~(PGDIR_SIZE_L2_64K-1)) + +/* + * Software defined PTE bits definition. + * (arch/arm64/include/asm/pgtable.h) + */ +#define PTE_VALID (1UL << 0) +#define PTE_DIRTY (1UL << 55) +#define PTE_SPECIAL (1UL << 56) + +/* + * Level 3 descriptor (PTE). + * (arch/arm64/include/asm/pgtable-hwdef.h) + */ +#define PTE_TYPE_MASK (3UL << 0) +#define PTE_TYPE_FAULT (0UL << 0) +#define PTE_TYPE_PAGE (3UL << 0) +#define PTE_USER (1UL << 6) /* AP[1] */ +#define PTE_RDONLY (1UL << 7) /* AP[2] */ +#define PTE_SHARED (3UL << 8) /* SH[1:0], inner shareable */ +#define PTE_AF (1UL << 10) /* Access Flag */ +#define PTE_NG (1UL << 11) /* nG */ +#define PTE_PXN (1UL << 53) /* Privileged XN */ +#define PTE_UXN (1UL << 54) /* User XN */ + +#define __swp_type(x) arm64_swp_type(x) +#define __swp_offset(x) arm64_swp_offset(x) +#define SWP_TYPE(x) __swp_type(x) +#define SWP_OFFSET(x) __swp_offset(x) + +#define KSYMS_START (0x1) +#define PHYS_OFFSET (0x2) +#define VM_L2_64K (0x4) +#define VM_L3_64K (0x8) +#define VM_L3_4K (0x10) +#define KDUMP_ENABLED (0x20) +#define IRQ_STACKS (0x40) +#define NEW_VMEMMAP (0x80) +#define VM_L4_4K (0x100) +#define UNW_4_14 (0x200) + +/* + * Get kimage_voffset from /dev/crash + */ +#define DEV_CRASH_ARCH_DATA _IOR('c', 1, unsigned long) + +/* + * sources: Documentation/arm64/memory.txt + * arch/arm64/include/asm/memory.h + * arch/arm64/include/asm/pgtable.h + */ +#define ARM64_VA_START ((0xffffffffffffffffUL) \ + << machdep->machspec->VA_BITS) +#define ARM64_PAGE_OFFSET ((0xffffffffffffffffUL) \ + << (machdep->machspec->VA_BITS - 1)) +#define ARM64_USERSPACE_TOP ((1UL) << machdep->machspec->VA_BITS) + +/* only used for v4.6 or later */ +#define ARM64_MODULES_VSIZE MEGABYTES(128) +#define ARM64_KASAN_SHADOW_SIZE (1UL << (machdep->machspec->VA_BITS - 3)) + +/* + * The following 3 definitions are the original values, but are obsolete + * for 3.17 and later kernels because they are now build-time calculations. + * They all depend on the kernel's new VMEMMAP_SIZE value, which is dependent + * upon the size of struct page. Accordingly, arm64_calc_virtual_memory_ranges() + * determines their values at POST_GDB time. + */ +#define ARM64_VMALLOC_END (ARM64_PAGE_OFFSET - 0x400000000UL - KILOBYTES(64) - 1) +#define ARM64_VMEMMAP_VADDR ((ARM64_VMALLOC_END+1) + KILOBYTES(64)) +#define ARM64_VMEMMAP_END (ARM64_VMEMMAP_VADDR + GIGABYTES(8UL) - 1) + +#define ARM64_STACK_SIZE (16384) +#define ARM64_IRQ_STACK_SIZE ARM64_STACK_SIZE + +#define _SECTION_SIZE_BITS 30 +#define _MAX_PHYSMEM_BITS 40 +#define _MAX_PHYSMEM_BITS_3_17 48 +#define _MAX_PHYSMEM_BITS_52 52 + +typedef unsigned long long __u64; +typedef unsigned long long u64; + +struct arm64_user_pt_regs { + __u64 regs[31]; + __u64 sp; + __u64 pc; + __u64 pstate; +}; + +struct arm64_pt_regs { + union { + struct arm64_user_pt_regs user_regs; + struct { + u64 regs[31]; + u64 sp; + u64 pc; + u64 pstate; + }; + }; + u64 orig_x0; + u64 syscallno; +}; + +/* AArch32 CPSR bits */ +#define PSR_MODE32_BIT 0x00000010 + +#define TIF_SIGPENDING (0) +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to ARM64 architecture\n") + +struct machine_specific { + ulong flags; + ulong userspace_top; + ulong page_offset; + ulong vmalloc_start_addr; + ulong vmalloc_end; + ulong vmemmap_vaddr; + ulong vmemmap_end; + ulong modules_vaddr; + ulong modules_end; + ulong phys_offset; + ulong __exception_text_start; + ulong __exception_text_end; + struct arm64_pt_regs *panic_task_regs; + ulong PTE_PROT_NONE; + ulong PTE_FILE; + ulong VA_BITS; + ulong __SWP_TYPE_BITS; + ulong __SWP_TYPE_SHIFT; + ulong __SWP_TYPE_MASK; + ulong __SWP_OFFSET_BITS; + ulong __SWP_OFFSET_SHIFT; + ulong __SWP_OFFSET_MASK; + ulong crash_kexec_start; + ulong crash_kexec_end; + ulong crash_save_cpu_start; + ulong crash_save_cpu_end; + ulong kernel_flags; + ulong irq_stack_size; + ulong *irq_stacks; + char *irq_stackbuf; + ulong __irqentry_text_start; + ulong __irqentry_text_end; + /* for exception vector code */ + ulong exp_entry1_start; + ulong exp_entry1_end; + ulong exp_entry2_start; + ulong exp_entry2_end; + /* only needed for v4.6 or later kernel */ + ulong kimage_voffset; + ulong kimage_text; + ulong kimage_end; + ulong user_eframe_offset; + /* for v4.14 or later */ + ulong kern_eframe_offset; + ulong machine_kexec_start; + ulong machine_kexec_end; + ulong vabits_user; +}; + +struct arm64_stackframe { + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +#endif /* ARM64 */ + +#ifdef MIPS +#define _32BIT_ +#define MACHINE_TYPE "MIPS" + +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) + +#define PTOV(X) ((unsigned long)(X) + 0x80000000lu) +#define VTOP(X) ((unsigned long)(X) & 0x1ffffffflu) + +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) + +#define DEFAULT_MODULES_VADDR (machdep->kvbase - 16 * 1024 * 1024) +#define MODULES_VADDR (machdep->machspec->modules_vaddr) +#define MODULES_END (machdep->machspec->modules_end) +#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) +#define VMALLOC_END (machdep->machspec->vmalloc_end) + +#define __SWP_TYPE_SHIFT 3 +#define __SWP_TYPE_BITS 6 +#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1) +#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT) + +#define SWP_TYPE(entry) (((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK) +#define SWP_OFFSET(entry) ((entry) >> __SWP_OFFSET_SHIFT) + +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#define _SECTION_SIZE_BITS 26 +#define _MAX_PHYSMEM_BITS 32 +#endif /* MIPS */ + +#ifdef X86 +#define _32BIT_ +#define MACHINE_TYPE "X86" +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) +#define KVBASE_MASK (0x1ffffff) + +#define PGDIR_SHIFT_2LEVEL (22) +#define PTRS_PER_PTE_2LEVEL (1024) +#define PTRS_PER_PGD_2LEVEL (1024) + +#define PGDIR_SHIFT_3LEVEL (30) +#define PTRS_PER_PTE_3LEVEL (512) +#define PTRS_PER_PGD_3LEVEL (4) +#define PMD_SHIFT (21) /* only used by PAE translators */ +#define PTRS_PER_PMD (512) /* only used by PAE translators */ + +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PWT 0x008 +#define _PAGE_PCD 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_4M 0x080 /* 4 MB page, Pentium+, if present.. */ +#define _PAGE_PSE 0x080 /* 4 MB (or 2MB) page, Pentium+, if present.. */ +#define _PAGE_GLOBAL 0x100 /* Global TLB entry PPro+ */ +#define _PAGE_PROTNONE (machdep->machspec->page_protnone) +#define _PAGE_NX (0x8000000000000000ULL) + +#define NONPAE_PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) +#define NX_BIT_MASK (0x7fffffffffffffffULL) +#define PAE_PAGEBASE(X) (((unsigned long long)(X)) & ((unsigned long long)machdep->pagemask) & NX_BIT_MASK) + +#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) +#define SWP_OFFSET(entry) ((entry) >> 8) +#define __swp_type_PAE(entry) (((entry) >> 32) & 0x1f) +#define __swp_type_nonPAE(entry) (((entry) >> 1) & 0x1f) +#define __swp_offset_PAE(entry) (((entry) >> 32) >> 5) +#define __swp_offset_nonPAE(entry) ((entry) >> 8) +#define __swp_type(entry) (machdep->flags & PAE ? \ + __swp_type_PAE(entry) : __swp_type_nonPAE(entry)) +#define __swp_offset(entry) (machdep->flags & PAE ? \ + __swp_offset_PAE(entry) : __swp_offset_nonPAE(entry)) + +#define TIF_SIGPENDING (2) + +// CONFIG_X86_PAE +#define _SECTION_SIZE_BITS_PAE_ORIG 30 +#define _SECTION_SIZE_BITS_PAE_2_6_26 29 +#define _MAX_PHYSMEM_BITS_PAE 36 + +// !CONFIG_X86_PAE +#define _SECTION_SIZE_BITS 26 +#define _MAX_PHYSMEM_BITS 32 + +#define IS_LAST_PMD_READ_PAE(pmd) ((ulong)(pmd) == machdep->machspec->last_pmd_read_PAE) +#define IS_LAST_PTBL_READ_PAE(ptbl) ((ulong)(ptbl) == machdep->machspec->last_ptbl_read_PAE) + +#define FILL_PMD_PAE(PMD, TYPE, SIZE) \ + if (!IS_LAST_PMD_READ_PAE(PMD)) { \ + readmem((ulonglong)(PMD), TYPE, machdep->pmd, \ + SIZE, "pmd page", FAULT_ON_ERROR); \ + machdep->machspec->last_pmd_read_PAE = (ulonglong)(PMD); \ + } + +#define FILL_PTBL_PAE(PTBL, TYPE, SIZE) \ + if (!IS_LAST_PTBL_READ_PAE(PTBL)) { \ + readmem((ulonglong)(PTBL), TYPE, machdep->ptbl, \ + SIZE, "page table", FAULT_ON_ERROR); \ + machdep->machspec->last_ptbl_read_PAE = (ulonglong)(PTBL); \ + } + +#endif /* X86 */ + +#ifdef X86_64 +#define _64BIT_ +#define MACHINE_TYPE "X86_64" + +#define USERSPACE_TOP (machdep->machspec->userspace_top) +#define PAGE_OFFSET (machdep->machspec->page_offset) +#define VMALLOC_START (machdep->machspec->vmalloc_start_addr) +#define VMALLOC_END (machdep->machspec->vmalloc_end) +#define VMEMMAP_VADDR (machdep->machspec->vmemmap_vaddr) +#define VMEMMAP_END (machdep->machspec->vmemmap_end) +#define MODULES_VADDR (machdep->machspec->modules_vaddr) +#define MODULES_END (machdep->machspec->modules_end) + +#define __START_KERNEL_map 0xffffffff80000000UL +#define MODULES_LEN (MODULES_END - MODULES_VADDR) + +#define USERSPACE_TOP_ORIG 0x0000008000000000 +#define PAGE_OFFSET_ORIG 0x0000010000000000 +#define VMALLOC_START_ADDR_ORIG 0xffffff0000000000 +#define VMALLOC_END_ORIG 0xffffff7fffffffff +#define MODULES_VADDR_ORIG 0xffffffffa0000000 +#define MODULES_END_ORIG 0xffffffffafffffff + +#define USERSPACE_TOP_2_6_11 0x0000800000000000 +#define PAGE_OFFSET_2_6_11 0xffff810000000000 +#define VMALLOC_START_ADDR_2_6_11 0xffffc20000000000 +#define VMALLOC_END_2_6_11 0xffffe1ffffffffff +#define MODULES_VADDR_2_6_11 0xffffffff88000000 +#define MODULES_END_2_6_11 0xfffffffffff00000 + +#define VMEMMAP_VADDR_2_6_24 0xffffe20000000000 +#define VMEMMAP_END_2_6_24 0xffffe2ffffffffff + +#define MODULES_VADDR_2_6_26 0xffffffffa0000000 + +#define PAGE_OFFSET_2_6_27 0xffff880000000000 +#define MODULES_END_2_6_27 0xffffffffff000000 + +#define USERSPACE_TOP_XEN 0x0000800000000000 +#define PAGE_OFFSET_XEN 0xffff880000000000 +#define VMALLOC_START_ADDR_XEN 0xffffc20000000000 +#define VMALLOC_END_XEN 0xffffe1ffffffffff +#define MODULES_VADDR_XEN 0xffffffff88000000 +#define MODULES_END_XEN 0xfffffffffff00000 + +#define USERSPACE_TOP_XEN_RHEL4 0x0000008000000000 +#define PAGE_OFFSET_XEN_RHEL4 0xffffff8000000000 +#define VMALLOC_START_ADDR_XEN_RHEL4 0xffffff0000000000 +#define VMALLOC_END_XEN_RHEL4 0xffffff7fffffffff +#define MODULES_VADDR_XEN_RHEL4 0xffffffffa0000000 +#define MODULES_END_XEN_RHEL4 0xffffffffafffffff + +#define VMALLOC_START_ADDR_2_6_31 0xffffc90000000000 +#define VMALLOC_END_2_6_31 0xffffe8ffffffffff +#define VMEMMAP_VADDR_2_6_31 0xffffea0000000000 +#define VMEMMAP_END_2_6_31 0xffffeaffffffffff +#define MODULES_VADDR_2_6_31 0xffffffffa0000000 +#define MODULES_END_2_6_31 0xffffffffff000000 + +#define USERSPACE_TOP_5LEVEL 0x0100000000000000 +#define PAGE_OFFSET_5LEVEL 0xff10000000000000 +#define VMALLOC_START_ADDR_5LEVEL 0xffa0000000000000 +#define VMALLOC_END_5LEVEL 0xffd1ffffffffffff +#define MODULES_VADDR_5LEVEL 0xffffffffa0000000 +#define MODULES_END_5LEVEL 0xffffffffff5fffff +#define VMEMMAP_VADDR_5LEVEL 0xffd4000000000000 +#define VMEMMAP_END_5LEVEL 0xffd5ffffffffffff + +#define PAGE_OFFSET_4LEVEL_4_20 0xffff888000000000 +#define PAGE_OFFSET_5LEVEL_4_20 0xff11000000000000 + +#define VSYSCALL_START 0xffffffffff600000 +#define VSYSCALL_END 0xffffffffff601000 + +#define CPU_ENTRY_AREA_START 0xfffffe0000000000 +#define CPU_ENTRY_AREA_END 0xfffffe7fffffffff + +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) x86_64_VTOP((ulong)(X)) +#define IS_VMALLOC_ADDR(X) x86_64_IS_VMALLOC_ADDR((ulong)(X)) + +/* + * the default page table level for x86_64: + * 4 level page tables + */ +#define PGDIR_SHIFT 39 +#define PTRS_PER_PGD 512 +#define PUD_SHIFT 30 +#define PTRS_PER_PUD 512 +#define PMD_SHIFT 21 +#define PTRS_PER_PMD 512 +#define PTRS_PER_PTE 512 + +/* 5 level page */ +#define PGDIR_SHIFT_5LEVEL 48 +#define PTRS_PER_PGD_5LEVEL 512 +#define P4D_SHIFT 39 +#define PTRS_PER_P4D 512 + +#define __PGDIR_SHIFT (machdep->machspec->pgdir_shift) +#define __PTRS_PER_PGD (machdep->machspec->ptrs_per_pgd) + +#define pgd_index(address) (((address) >> __PGDIR_SHIFT) & (__PTRS_PER_PGD-1)) +#define p4d_index(address) (((address) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) +#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) +#define pmd_index(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) +#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +#define FILL_TOP_PGD() \ + if (!(pc->flags & RUNTIME) || ACTIVE()) { \ + FILL_PGD(vt->kernel_pgd[0], KVADDR, PAGESIZE()); \ + } + +#define FILL_TOP_PGD_HYPER() \ + unsigned long idle_pg_table = symbol_exists("idle_pg_table_4") ? \ + symbol_value("idle_pg_table_4") : \ + symbol_value("idle_pg_table"); \ + FILL_PGD(idle_pg_table, KVADDR, PAGESIZE()); + +#define IS_LAST_P4D_READ(p4d) ((ulong)(p4d) == machdep->machspec->last_p4d_read) + +#define FILL_P4D(P4D, TYPE, SIZE) \ + if (!IS_LAST_P4D_READ(P4D)) { \ + readmem((ulonglong)((ulong)(P4D)), TYPE, machdep->machspec->p4d, \ + SIZE, "p4d page", FAULT_ON_ERROR); \ + machdep->machspec->last_p4d_read = (ulong)(P4D); \ + } + +/* + * PHYSICAL_PAGE_MASK changed (enlarged) between 2.4 and 2.6, so + * for safety, use the 2.6 values to generate it. + */ +#define __PHYSICAL_MASK_SHIFT_XEN 40 +#define __PHYSICAL_MASK_SHIFT_2_6 46 +#define __PHYSICAL_MASK_SHIFT_5LEVEL 52 +#define __PHYSICAL_MASK_SHIFT (machdep->machspec->physical_mask_shift) +#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1) +#define __VIRTUAL_MASK_SHIFT 48 +#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1) +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK ) + +#define _PAGE_BIT_NX 63 +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PWT 0x008 +#define _PAGE_PCD 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_PSE 0x080 /* 2MB page */ +#define _PAGE_FILE 0x040 /* set:pagecache, unset:swap */ +#define _PAGE_GLOBAL 0x100 /* Global TLB entry */ +#define _PAGE_PROTNONE (machdep->machspec->page_protnone) +#define _PAGE_NX (1UL<<_PAGE_BIT_NX) + +#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f) +#define SWP_OFFSET(entry) ((entry) >> 8) +#define __swp_type(entry) x86_64_swp_type(entry) +#define __swp_offset(entry) x86_64_swp_offset(entry) + +#define TIF_SIGPENDING (2) + +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) + +#define _CPU_PDA_READ2(CPU, BUFFER) \ + ((readmem(symbol_value("_cpu_pda"), \ + KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ + (readmem(cpu_pda_addr + ((CPU) * sizeof(void *)), \ + KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ + (cpu_pda_addr) && \ + (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ + "cpu_pda entry", RETURN_ON_ERROR))) + +#define _CPU_PDA_READ(CPU, BUFFER) \ + ((STRNEQ("_cpu_pda", closest_symbol((symbol_value("_cpu_pda") + \ + ((CPU) * sizeof(unsigned long)))))) && \ + (readmem(symbol_value("_cpu_pda") + ((CPU) * sizeof(void *)), \ + KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ + (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ + "cpu_pda entry", RETURN_ON_ERROR))) + +#define CPU_PDA_READ(CPU, BUFFER) \ + (STRNEQ("cpu_pda", closest_symbol((symbol_value("cpu_pda") + \ + ((CPU) * SIZE(x8664_pda))))) && \ + readmem(symbol_value("cpu_pda") + ((CPU) * SIZE(x8664_pda)), \ + KVADDR, (BUFFER), SIZE(x8664_pda), "cpu_pda entry", \ + RETURN_ON_ERROR)) + +#define VALID_LEVEL4_PGT_ADDR(X) \ + (((X) == VIRTPAGEBASE(X)) && IS_KVADDR(X) && !IS_VMALLOC_ADDR(X)) + +#define _SECTION_SIZE_BITS 27 +#define _MAX_PHYSMEM_BITS 40 +#define _MAX_PHYSMEM_BITS_2_6_26 44 +#define _MAX_PHYSMEM_BITS_2_6_31 46 +#define _MAX_PHYSMEM_BITS_5LEVEL 52 + +#endif /* X86_64 */ + +#ifdef ALPHA +#define _64BIT_ +#define MACHINE_TYPE "ALPHA" + +#define PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) + +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) +#define KSEG_BASE_48_BIT (0xffff800000000000) +#define KSEG_BASE (0xfffffc0000000000) +#define _PFN_MASK (0xFFFFFFFF00000000) +#define VMALLOC_START (0xFFFFFE0000000000) +#define MIN_SYMBOL_VALUE (KSEG_BASE_48_BIT) + +#define PGDIR_SHIFT (PAGESHIFT() + 2*(PAGESHIFT()-3)) +#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT()-3)) +#define PTRS_PER_PAGE (1024) + +#define PTRS_PER_PGD (1UL << (PAGESHIFT()-3)) + +/* + * OSF/1 PAL-code-imposed page table bits + */ +#define _PAGE_VALID 0x0001 +#define _PAGE_FOR 0x0002 /* used for page protection (fault on read) */ +#define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */ +#define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */ +#define _PAGE_ASM 0x0010 +#define _PAGE_KRE 0x0100 /* xxx - see below on the "accessed" bit */ +#define _PAGE_URE 0x0200 /* xxx */ +#define _PAGE_KWE 0x1000 /* used to do the dirty bit in software */ +#define _PAGE_UWE 0x2000 /* used to do the dirty bit in software */ + +/* .. and these are ours ... */ +#define _PAGE_DIRTY 0x20000 +#define _PAGE_ACCESSED 0x40000 + +#define SWP_TYPE(entry) (((entry) >> 32) & 0xff) +#define SWP_OFFSET(entry) ((entry) >> 40) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#endif /* ALPHA */ + +#ifdef PPC +#define _32BIT_ +#define MACHINE_TYPE "PPC" + +#define PAGEBASE(X) ((X) & machdep->pagemask) + +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) + +/* Holds the platform specific info for page translation */ +struct machine_specific { + char *platform; + + /* page address translation bits */ + int pte_size; + int pte_rpn_shift; + + /* page flags */ + ulong _page_present; + ulong _page_user; + ulong _page_rw; + ulong _page_guarded; + ulong _page_coherent; + ulong _page_no_cache; + ulong _page_writethru; + ulong _page_dirty; + ulong _page_accessed; + ulong _page_hwwrite; + ulong _page_shared; + ulong _page_k_rw; + + /* platform special vtop */ + int (*vtop_special)(ulong vaddr, physaddr_t *paddr, int verbose); + void *mmu_special; +}; + +/* machdep flags for ppc32 specific */ +#define IS_PAE() (machdep->flags & PAE) +#define IS_BOOKE() (machdep->flags & CPU_BOOKE) +/* Page translation bits */ +#define PPC_PLATFORM (machdep->machspec->platform) +#define PTE_SIZE (machdep->machspec->pte_size) +#define PTE_RPN_SHIFT (machdep->machspec->pte_rpn_shift) +#define PAGE_SHIFT (12) +#define PTE_T_LOG2 (ffs(PTE_SIZE) - 1) +#define PTE_SHIFT (PAGE_SHIFT - PTE_T_LOG2) +#define PGDIR_SHIFT (PAGE_SHIFT + PTE_SHIFT) +#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT)) +#define PTRS_PER_PTE (1 << PTE_SHIFT) +/* special vtop */ +#define VTOP_SPECIAL (machdep->machspec->vtop_special) +#define MMU_SPECIAL (machdep->machspec->mmu_special) + +/* PFN shifts */ +#define BOOKE3E_PTE_RPN_SHIFT (24) + +/* PAGE flags */ +#define _PAGE_PRESENT (machdep->machspec->_page_present) /* software: pte contains a translation */ +#define _PAGE_USER (machdep->machspec->_page_user) /* matches one of the PP bits */ +#define _PAGE_RW (machdep->machspec->_page_rw) /* software: user write access allowed */ +#define _PAGE_GUARDED (machdep->machspec->_page_guarded) +#define _PAGE_COHERENT (machdep->machspec->_page_coherent /* M: enforce memory coherence (SMP systems) */) +#define _PAGE_NO_CACHE (machdep->machspec->_page_no_cache) /* I: cache inhibit */ +#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru) /* W: cache write-through */ +#define _PAGE_DIRTY (machdep->machspec->_page_dirty) /* C: page changed */ +#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) /* R: page referenced */ +#define _PAGE_HWWRITE (machdep->machspec->_page_hwwrite) /* software: _PAGE_RW & _PAGE_DIRTY */ +#define _PAGE_SHARED (machdep->machspec->_page_shared) +#define _PAGE_K_RW (machdep->machspec->_page_k_rw) /* privilege only write access allowed */ + +/* Default values for PAGE flags */ +#define DEFAULT_PAGE_PRESENT 0x001 +#define DEFAULT_PAGE_USER 0x002 +#define DEFAULT_PAGE_RW 0x004 +#define DEFAULT_PAGE_GUARDED 0x008 +#define DEFAULT_PAGE_COHERENT 0x010 +#define DEFAULT_PAGE_NO_CACHE 0x020 +#define DEFAULT_PAGE_WRITETHRU 0x040 +#define DEFAULT_PAGE_DIRTY 0x080 +#define DEFAULT_PAGE_ACCESSED 0x100 +#define DEFAULT_PAGE_HWWRITE 0x200 +#define DEFAULT_PAGE_SHARED 0 + +/* PPC44x PAGE flags: Values from kernel asm/pte-44x.h */ +#define PPC44x_PAGE_PRESENT 0x001 +#define PPC44x_PAGE_RW 0x002 +#define PPC44x_PAGE_ACCESSED 0x008 +#define PPC44x_PAGE_DIRTY 0x010 +#define PPC44x_PAGE_USER 0x040 +#define PPC44x_PAGE_GUARDED 0x100 +#define PPC44x_PAGE_COHERENT 0x200 +#define PPC44x_PAGE_NO_CACHE 0x400 +#define PPC44x_PAGE_WRITETHRU 0x800 +#define PPC44x_PAGE_HWWRITE 0 +#define PPC44x_PAGE_SHARED 0 + +/* BOOK3E */ +#define BOOK3E_PAGE_PRESENT 0x000001 +#define BOOK3E_PAGE_BAP_SR 0x000004 +#define BOOK3E_PAGE_BAP_UR 0x000008 /* User Readable */ +#define BOOK3E_PAGE_BAP_SW 0x000010 +#define BOOK3E_PAGE_BAP_UW 0x000020 /* User Writable */ +#define BOOK3E_PAGE_DIRTY 0x001000 +#define BOOK3E_PAGE_ACCESSED 0x040000 +#define BOOK3E_PAGE_GUARDED 0x100000 +#define BOOK3E_PAGE_COHERENT 0x200000 +#define BOOK3E_PAGE_NO_CACHE 0x400000 +#define BOOK3E_PAGE_WRITETHRU 0x800000 +#define BOOK3E_PAGE_HWWRITE 0 +#define BOOK3E_PAGE_SHARED 0 +#define BOOK3E_PAGE_USER (BOOK3E_PAGE_BAP_SR | BOOK3E_PAGE_BAP_UR) +#define BOOK3E_PAGE_RW (BOOK3E_PAGE_BAP_SW | BOOK3E_PAGE_BAP_UW) +#define BOOK3E_PAGE_KERNEL_RW (BOOK3E_PAGE_BAP_SW | BOOK3E_PAGE_BAP_SR | BOOK3E_PAGE_DIRTY) + +/* FSL BOOKE */ +#define FSL_BOOKE_PAGE_PRESENT 0x00001 +#define FSL_BOOKE_PAGE_USER 0x00002 +#define FSL_BOOKE_PAGE_RW 0x00004 +#define FSL_BOOKE_PAGE_DIRTY 0x00008 +#define FSL_BOOKE_PAGE_ACCESSED 0x00020 +#define FSL_BOOKE_PAGE_GUARDED 0x00080 +#define FSL_BOOKE_PAGE_COHERENT 0x00100 +#define FSL_BOOKE_PAGE_NO_CACHE 0x00200 +#define FSL_BOOKE_PAGE_WRITETHRU 0x00400 +#define FSL_BOOKE_PAGE_HWWRITE 0 +#define FSL_BOOKE_PAGE_SHARED 0 + +#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) +#define SWP_OFFSET(entry) ((entry) >> 8) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#define _SECTION_SIZE_BITS 24 +#define _MAX_PHYSMEM_BITS 44 + +#define STACK_FRAME_OVERHEAD 16 +#define STACK_FRAME_LR_SAVE (sizeof(ulong)) +#define STACK_FRAME_MARKER (2 * sizeof(ulong)) +#define STACK_FRAME_REGS_MARKER 0x72656773 +#define PPC_STACK_SIZE 8192 + +#endif /* PPC */ + +#ifdef IA64 +#define _64BIT_ +#define MACHINE_TYPE "IA64" + +#define PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask) + +#define REGION_SHIFT (61) +#define VADDR_REGION(X) ((ulong)(X) >> REGION_SHIFT) + +#define KERNEL_CACHED_REGION (7) +#define KERNEL_UNCACHED_REGION (6) +#define KERNEL_VMALLOC_REGION (5) +#define USER_STACK_REGION (4) +#define USER_DATA_REGION (3) +#define USER_TEXT_REGION (2) +#define USER_SHMEM_REGION (1) +#define USER_IA32_EMUL_REGION (0) + +#define KERNEL_VMALLOC_BASE ((ulong)KERNEL_VMALLOC_REGION << REGION_SHIFT) +#define KERNEL_UNCACHED_BASE ((ulong)KERNEL_UNCACHED_REGION << REGION_SHIFT) +#define KERNEL_CACHED_BASE ((ulong)KERNEL_CACHED_REGION << REGION_SHIFT) + +#define _SECTION_SIZE_BITS 30 +#define _MAX_PHYSMEM_BITS 50 + +/* + * As of 2.6, these are no longer straight forward. + */ +#define PTOV(X) ia64_PTOV((ulong)(X)) +#define VTOP(X) ia64_VTOP((ulong)(X)) +#define IS_VMALLOC_ADDR(X) ia64_IS_VMALLOC_ADDR((ulong)(X)) + +#define SWITCH_STACK_ADDR(X) (ia64_get_switch_stack((ulong)(X))) + +#define __IA64_UL(x) ((unsigned long)(x)) +#define IA64_MAX_PHYS_BITS (50) /* max # of phys address bits (architected) */ + +/* + * How many pointers will a page table level hold expressed in shift + */ +#define PTRS_PER_PTD_SHIFT (PAGESHIFT()-3) + +/* + * Definitions for fourth level: + */ +#define PTRS_PER_PTE (__IA64_UL(1) << (PTRS_PER_PTD_SHIFT)) + +/* + * Definitions for third level: + * + * PMD_SHIFT determines the size of the area a third-level page table + * can map. + */ +#define PMD_SHIFT (PAGESHIFT() + (PTRS_PER_PTD_SHIFT)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) +#define PTRS_PER_PMD (1UL << (PTRS_PER_PTD_SHIFT)) + +/* + * PUD_SHIFT determines the size of the area a second-level page table + * can map + */ +#define PUD_SHIFT (PMD_SHIFT + (PTRS_PER_PTD_SHIFT)) +#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE-1)) +#define PTRS_PER_PUD (1UL << (PTRS_PER_PTD_SHIFT)) + +/* + * Definitions for first level: + * + * PGDIR_SHIFT determines what a first-level page table entry can map. + */ + +#define PGDIR_SHIFT_4L (PUD_SHIFT + (PTRS_PER_PTD_SHIFT)) +#define PGDIR_SHIFT_3L (PMD_SHIFT + (PTRS_PER_PTD_SHIFT)) +/* Turns out 4L & 3L PGDIR_SHIFT are the same (for now) */ +#define PGDIR_SHIFT PGDIR_SHIFT_4L +#define PGDIR_SIZE (__IA64_UL(1) << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE-1)) +#define PTRS_PER_PGD_SHIFT PTRS_PER_PTD_SHIFT +#define PTRS_PER_PGD (1UL << PTRS_PER_PGD_SHIFT) +#define USER_PTRS_PER_PGD (5*PTRS_PER_PGD/8) /* regions 0-4 are user regions */ +#define FIRST_USER_ADDRESS 0 + +/* + * First, define the various bits in a PTE. Note that the PTE format + * matches the VHPT short format, the firt doubleword of the VHPD long + * format, and the first doubleword of the TLB insertion format. + */ +#define _PAGE_P (1 << 0) /* page present bit */ +#define _PAGE_MA_WB (0x0 << 2) /* write back memory attribute */ +#define _PAGE_MA_UC (0x4 << 2) /* uncacheable memory attribute */ +#define _PAGE_MA_UCE (0x5 << 2) /* UC exported attribute */ +#define _PAGE_MA_WC (0x6 << 2) /* write coalescing memory attribute */ +#define _PAGE_MA_NAT (0x7 << 2) /* not-a-thing attribute */ +#define _PAGE_MA_MASK (0x7 << 2) +#define _PAGE_PL_0 (0 << 7) /* privilege level 0 (kernel) */ +#define _PAGE_PL_1 (1 << 7) /* privilege level 1 (unused) */ +#define _PAGE_PL_2 (2 << 7) /* privilege level 2 (unused) */ +#define _PAGE_PL_3 (3 << 7) /* privilege level 3 (user) */ +#define _PAGE_PL_MASK (3 << 7) +#define _PAGE_AR_R (0 << 9) /* read only */ +#define _PAGE_AR_RX (1 << 9) /* read & execute */ +#define _PAGE_AR_RW (2 << 9) /* read & write */ +#define _PAGE_AR_RWX (3 << 9) /* read, write & execute */ +#define _PAGE_AR_R_RW (4 << 9) /* read / read & write */ +#define _PAGE_AR_RX_RWX (5 << 9) /* read & exec / read, write & exec */ +#define _PAGE_AR_RWX_RW (6 << 9) /* read, write & exec / read & write */ +#define _PAGE_AR_X_RX (7 << 9) /* exec & promote / read & exec */ +#define _PAGE_AR_MASK (7 << 9) +#define _PAGE_AR_SHIFT 9 +#define _PAGE_A (1 << 5) /* page accessed bit */ +#define _PAGE_D (1 << 6) /* page dirty bit */ +#define _PAGE_PPN_MASK (((__IA64_UL(1) << IA64_MAX_PHYS_BITS) - 1) & ~0xfffUL) +#define _PAGE_ED (__IA64_UL(1) << 52) /* exception deferral */ +#define _PAGE_PROTNONE (__IA64_UL(1) << 63) + +#define _PFN_MASK _PAGE_PPN_MASK +#define _PAGE_CHG_MASK (_PFN_MASK | _PAGE_A | _PAGE_D) + +#define _PAGE_SIZE_4K 12 +#define _PAGE_SIZE_8K 13 +#define _PAGE_SIZE_16K 14 +#define _PAGE_SIZE_64K 16 +#define _PAGE_SIZE_256K 18 +#define _PAGE_SIZE_1M 20 +#define _PAGE_SIZE_4M 22 +#define _PAGE_SIZE_16M 24 +#define _PAGE_SIZE_64M 26 +#define _PAGE_SIZE_256M 28 + +#define __ACCESS_BITS _PAGE_ED | _PAGE_A | _PAGE_P | _PAGE_MA_WB +#define __DIRTY_BITS_NO_ED _PAGE_A | _PAGE_P | _PAGE_D | _PAGE_MA_WB +#define __DIRTY_BITS _PAGE_ED | __DIRTY_BITS_NO_ED + +#define EFI_PAGE_SHIFT (12) + +/* + * NOTE: #include'ing creates too many compiler problems, so + * this stuff is hardwired here; it's probably etched in stone somewhere. + */ +struct efi_memory_desc_t { + uint32_t type; + uint32_t pad; + uint64_t phys_addr; + uint64_t virt_addr; + uint64_t num_pages; + uint64_t attribute; +} desc; + +/* Memory types: */ +#define EFI_RESERVED_TYPE 0 +#define EFI_LOADER_CODE 1 +#define EFI_LOADER_DATA 2 +#define EFI_BOOT_SERVICES_CODE 3 +#define EFI_BOOT_SERVICES_DATA 4 +#define EFI_RUNTIME_SERVICES_CODE 5 +#define EFI_RUNTIME_SERVICES_DATA 6 +#define EFI_CONVENTIONAL_MEMORY 7 +#define EFI_UNUSABLE_MEMORY 8 +#define EFI_ACPI_RECLAIM_MEMORY 9 +#define EFI_ACPI_MEMORY_NVS 10 +#define EFI_MEMORY_MAPPED_IO 11 +#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 +#define EFI_PAL_CODE 13 +#define EFI_MAX_MEMORY_TYPE 14 + +/* Attribute values: */ +#define EFI_MEMORY_UC 0x0000000000000001 /* uncached */ +#define EFI_MEMORY_WC 0x0000000000000002 /* write-coalescing */ +#define EFI_MEMORY_WT 0x0000000000000004 /* write-through */ +#define EFI_MEMORY_WB 0x0000000000000008 /* write-back */ +#define EFI_MEMORY_WP 0x0000000000001000 /* write-protect */ +#define EFI_MEMORY_RP 0x0000000000002000 /* read-protect */ +#define EFI_MEMORY_XP 0x0000000000004000 /* execute-protect */ +#define EFI_MEMORY_RUNTIME 0x8000000000000000 /* range requires runtime mapping */ + +#define SWP_TYPE(entry) (((entry) >> 1) & 0xff) +#define SWP_OFFSET(entry) ((entry) >> 9) +#define __swp_type(entry) ((entry >> 2) & 0x7f) +#define __swp_offset(entry) ((entry << 1) >> 10) + +#define TIF_SIGPENDING (1) + +#define KERNEL_TR_PAGE_SIZE (1 << _PAGE_SIZE_64M) +#define KERNEL_TR_PAGE_MASK (~(KERNEL_TR_PAGE_SIZE - 1)) + +#define UNKNOWN_PHYS_START ((ulong)(-1)) +#define DEFAULT_PHYS_START (KERNEL_TR_PAGE_SIZE * 1) + +#define IA64_GET_STACK_ULONG(OFF) \ + ((INSTACK(OFF,bt)) ? (GET_STACK_ULONG(OFF)) : get_init_stack_ulong((unsigned long)OFF)) + +#endif /* IA64 */ + +#ifdef PPC64 +#define _64BIT_ +#define MACHINE_TYPE "PPC64" + +#define PPC64_64K_PAGE_SIZE 65536 +#define PPC64_STACK_SIZE 16384 + +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) + +#define PTOV(X) ((unsigned long)(X)+(machdep->identity_map_base)) +#define VTOP(X) ((unsigned long)(X)-(machdep->identity_map_base)) +#define BOOK3E_VMBASE 0x8000000000000000 +#define IS_VMALLOC_ADDR(X) machdep->machspec->is_vmaddr(X) +#define KERNELBASE machdep->pageoffset + +#define PGDIR_SHIFT (machdep->pageshift + (machdep->pageshift -3) + (machdep->pageshift - 2)) +#define PMD_SHIFT (machdep->pageshift + (machdep->pageshift - 3)) + +#define PGD_MASK (~((1UL << PGDIR_SHIFT) - 1)) +#define PMD_MASK (~((1UL << PMD_SHIFT) - 1)) + +/* shift to put page number into pte */ +#define PTE_RPN_SHIFT_DEFAULT 16 +#define PMD_TO_PTEPAGE_SHIFT 2 /* Used for 2.6 or later */ + +#define PTE_INDEX_SIZE 9 +#define PMD_INDEX_SIZE 10 +#define PGD_INDEX_SIZE 10 + +#define PTRS_PER_PTE (1 << PTE_INDEX_SIZE) +#define PTRS_PER_PMD (1 << PMD_INDEX_SIZE) +#define PTRS_PER_PGD (1 << PGD_INDEX_SIZE) + +#define PGD_OFFSET_24(vaddr) ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) +#define PGD_OFFSET(vaddr) ((vaddr >> PGDIR_SHIFT) & 0x7ff) +#define PMD_OFFSET(vaddr) ((vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) + +/* 4-level page table support */ + +/* 4K pagesize */ +#define PTE_INDEX_SIZE_L4_4K 9 +#define PMD_INDEX_SIZE_L4_4K 7 +#define PUD_INDEX_SIZE_L4_4K 7 +#define PGD_INDEX_SIZE_L4_4K 9 +#define PUD_INDEX_SIZE_L4_4K_3_7 9 +#define PTE_INDEX_SIZE_RADIX_4K 9 +#define PMD_INDEX_SIZE_RADIX_4K 9 +#define PUD_INDEX_SIZE_RADIX_4K 9 +#define PGD_INDEX_SIZE_RADIX_4K 13 +#define PTE_RPN_SHIFT_L4_4K 17 +#define PTE_RPN_SHIFT_L4_4K_4_5 18 +#define PGD_MASKED_BITS_4K 0 +#define PUD_MASKED_BITS_4K 0 +#define PMD_MASKED_BITS_4K 0 + +/* 64K pagesize */ +#define PTE_INDEX_SIZE_L4_64K 12 +#define PMD_INDEX_SIZE_L4_64K 12 +#define PUD_INDEX_SIZE_L4_64K 0 +#define PGD_INDEX_SIZE_L4_64K 4 +#define PTE_INDEX_SIZE_L4_64K_3_10 8 +#define PMD_INDEX_SIZE_L4_64K_3_10 10 +#define PGD_INDEX_SIZE_L4_64K_3_10 12 +#define PMD_INDEX_SIZE_L4_64K_4_6 5 +#define PUD_INDEX_SIZE_L4_64K_4_6 5 +#define PMD_INDEX_SIZE_L4_64K_4_12 10 +#define PUD_INDEX_SIZE_L4_64K_4_12 7 +#define PGD_INDEX_SIZE_L4_64K_4_12 8 +#define PUD_INDEX_SIZE_L4_64K_4_17 10 +#define PTE_INDEX_SIZE_RADIX_64K 5 +#define PMD_INDEX_SIZE_RADIX_64K 9 +#define PUD_INDEX_SIZE_RADIX_64K 9 +#define PGD_INDEX_SIZE_RADIX_64K 13 +#define PTE_RPN_SHIFT_L4_64K_V1 32 +#define PTE_RPN_SHIFT_L4_64K_V2 30 +#define PTE_RPN_SHIFT_L4_BOOK3E_64K 28 +#define PTE_RPN_SHIFT_L4_BOOK3E_4K 24 +#define PGD_MASKED_BITS_64K 0 +#define PUD_MASKED_BITS_64K 0x1ff +#define PMD_MASKED_BITS_64K 0x1ff +#define PMD_MASKED_BITS_64K_3_11 0xfff +#define PMD_MASKED_BITS_BOOK3E_64K_4_5 0x7ff +#define PGD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL +#define PUD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL +#define PMD_MASKED_BITS_64K_4_6 0xc0000000000000ffUL + +#define PTE_RPN_MASK_DEFAULT 0xffffffffffffffffUL +#define PAGE_PA_MAX_L4_4_6 (THIS_KERNEL_VERSION >= LINUX(4,11,0) ? 53 : 57) +#define PTE_RPN_MASK_L4_4_6 \ + (((1UL << PAGE_PA_MAX_L4_4_6) - 1) & ~((1UL << PAGESHIFT()) - 1)) +#define PTE_RPN_SHIFT_L4_4_6 PAGESHIFT() + +#define PGD_MASKED_BITS_4_7 0xc0000000000000ffUL +#define PUD_MASKED_BITS_4_7 0xc0000000000000ffUL +#define PMD_MASKED_BITS_4_7 0xc0000000000000ffUL + +#define PD_HUGE 0x8000000000000000 +#define HUGE_PTE_MASK 0x03 +#define HUGEPD_SHIFT_MASK 0x3f +#define HUGEPD_ADDR_MASK (0x0fffffffffffffffUL & ~HUGEPD_SHIFT_MASK) + +#define PGD_MASK_L4 \ + (THIS_KERNEL_VERSION >= LINUX(3,10,0) ? (machdep->ptrs_per_pgd - 1) : 0x1ff) + +#define PGD_OFFSET_L4(vaddr) \ + ((vaddr >> (machdep->machspec->l4_shift)) & PGD_MASK_L4) + +#define PUD_OFFSET_L4(vaddr) \ + ((vaddr >> (machdep->machspec->l3_shift)) & (machdep->machspec->ptrs_per_l3 - 1)) + +#define PMD_OFFSET_L4(vaddr) \ + ((vaddr >> (machdep->machspec->l2_shift)) & (machdep->machspec->ptrs_per_l2 - 1)) + +#define _PAGE_PTE (machdep->machspec->_page_pte) /* distinguishes PTEs from pointers */ +#define _PAGE_PRESENT (machdep->machspec->_page_present) /* software: pte contains a translation */ +#define _PAGE_USER (machdep->machspec->_page_user) /* matches one of the PP bits */ +#define _PAGE_RW (machdep->machspec->_page_rw) /* software: user write access allowed */ +#define _PAGE_GUARDED (machdep->machspec->_page_guarded) +#define _PAGE_COHERENT (machdep->machspec->_page_coherent /* M: enforce memory coherence (SMP systems) */) +#define _PAGE_NO_CACHE (machdep->machspec->_page_no_cache) /* I: cache inhibit */ +#define _PAGE_WRITETHRU (machdep->machspec->_page_writethru) /* W: cache write-through */ +#define _PAGE_DIRTY (machdep->machspec->_page_dirty) /* C: page changed */ +#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) /* R: page referenced */ + +#define PTE_RPN_MASK (machdep->machspec->pte_rpn_mask) +#define PTE_RPN_SHIFT (machdep->machspec->pte_rpn_shift) + +#define TIF_SIGPENDING (2) + +#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f) +#define SWP_OFFSET(entry) ((entry) >> 8) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define MSR_PR_LG 14 /* Problem State / Privilege Level */ + /* Used to find the user or kernel-mode frame*/ + +#define STACK_FRAME_OVERHEAD 112 +#define EXCP_FRAME_MARKER 0x7265677368657265 + +#define _SECTION_SIZE_BITS 24 +#define _MAX_PHYSMEM_BITS 44 +#define _MAX_PHYSMEM_BITS_3_7 46 +#define _MAX_PHYSMEM_BITS_4_19 47 +#define _MAX_PHYSMEM_BITS_4_20 51 + +#endif /* PPC64 */ + +#ifdef S390 +#define _32BIT_ +#define MACHINE_TYPE "S390" + +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) + +#define PTRS_PER_PTE 1024 +#define PTRS_PER_PMD 1 +#define PTRS_PER_PGD 512 +#define SEGMENT_TABLE_SIZE ((sizeof(ulong)*4) * PTRS_PER_PGD) + +#define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) +#define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffe) | \ + (((entry) >> 7) & 0x1)) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#define _SECTION_SIZE_BITS 25 +#define _MAX_PHYSMEM_BITS 31 + +#endif /* S390 */ + +#ifdef S390X +#define _64BIT_ +#define MACHINE_TYPE "S390X" + +#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) +#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase)) +#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start) +#define PTRS_PER_PTE 512 +#define PTRS_PER_PMD 1024 +#define PTRS_PER_PGD 2048 +#define SEGMENT_TABLE_SIZE ((sizeof(ulong)*2) * PTRS_PER_PMD) + +#define SWP_TYPE(entry) (((entry) >> 2) & 0x1f) +#define SWP_OFFSET(entry) ((((entry) >> 11) & 0xfffffffffffffffe) | \ + (((entry) >> 7) & 0x1)) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#define TIF_SIGPENDING (2) + +#define _SECTION_SIZE_BITS 28 +#define _MAX_PHYSMEM_BITS_OLD 42 +#define _MAX_PHYSMEM_BITS_NEW 46 + +#endif /* S390X */ + +#ifdef SPARC64 +#define _64BIT_ +#define MACHINE_TYPE "SPARC64" + +#define PTOV(X) \ + ((unsigned long)(X) + machdep->machspec->page_offset) +#define VTOP(X) \ + ((unsigned long)(X) - machdep->machspec->page_offset) + +#define PAGE_OFFSET (machdep->machspec->page_offset) + +extern int sparc64_IS_VMALLOC_ADDR(ulong vaddr); +#define IS_VMALLOC_ADDR(X) sparc64_IS_VMALLOC_ADDR((ulong)(X)) +#define PAGE_SHIFT (13) +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask) +#define THREAD_SIZE (2 * PAGE_SIZE) + +/* S3 Core + * Core 48-bit physical address supported. + * Bit 47 distinguishes memory or I/O. When set to "1" it is I/O. + */ +#define PHYS_MASK_SHIFT (47) +#define PHYS_MASK (((1UL) << PHYS_MASK_SHIFT) - 1) + +typedef signed int s32; + +/* + * This next two defines are convenience defines for normal page table. + */ +#define PTES_PER_PAGE (1UL << (PAGE_SHIFT - 3)) +#define PTES_PER_PAGE_MASK (PTES_PER_PAGE - 1) + +/* 4-level page table */ +#define PMD_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE - 1)) +#define PMD_BITS (PAGE_SHIFT - 3) + +#define PUD_SHIFT (PMD_SHIFT + PMD_BITS) +#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE - 1)) +#define PUD_BITS (PAGE_SHIFT - 3) + +#define PGDIR_SHIFT (PUD_SHIFT + PUD_BITS) +#define PGDIR_SIZE (1UL << PGDIR_SHIFT) +#define PGDIR_MASK (~(PGDIR_SIZE - 1)) +#define PGDIR_BITS (PAGE_SHIFT - 3) + +#define PTRS_PER_PTE (1UL << (PAGE_SHIFT - 3)) +#define PTRS_PER_PMD (1UL << PMD_BITS) +#define PTRS_PER_PUD (1UL << PUD_BITS) +#define PTRS_PER_PGD (1UL << PGDIR_BITS) + +#define HPAGE_SHIFT (23) +/* Down one huge page */ +#define SPARC64_USERSPACE_TOP (-(1UL << HPAGE_SHIFT)) +#define PAGE_PMD_HUGE (0x0100000000000000UL) + +/* These are for SUN4V. */ +#define _PAGE_VALID (0x8000000000000000UL) +#define _PAGE_NFO_4V (0x4000000000000000UL) +#define _PAGE_MODIFIED_4V (0x2000000000000000UL) +#define _PAGE_ACCESSED_4V (0x1000000000000000UL) +#define _PAGE_READ_4V (0x0800000000000000UL) +#define _PAGE_WRITE_4V (0x0400000000000000UL) +#define _PAGE_PADDR_4V (0x00FFFFFFFFFFE000UL) +#define _PAGE_PFN_MASK (_PAGE_PADDR_4V) +#define _PAGE_P_4V (0x0000000000000100UL) +#define _PAGE_EXEC_4V (0x0000000000000080UL) +#define _PAGE_W_4V (0x0000000000000040UL) +#define _PAGE_PRESENT_4V (0x0000000000000010UL) +#define _PAGE_SZALL_4V (0x0000000000000007UL) +/* There are other page sizes. Some supported. */ +#define _PAGE_SZ4MB_4V (0x0000000000000003UL) +#define _PAGE_SZ512K_4V (0x0000000000000002UL) +#define _PAGE_SZ64K_4V (0x0000000000000001UL) +#define _PAGE_SZ8K_4V (0x0000000000000000UL) + +#define SPARC64_MODULES_VADDR (0x0000000010000000UL) +#define SPARC64_MODULES_END (0x00000000f0000000UL) +#define SPARC64_VMALLOC_START (0x0000000100000000UL) + +#define SPARC64_STACK_SIZE 0x4000 + +/* sparsemem */ +#define _SECTION_SIZE_BITS 30 +#define _MAX_PHYSMEM_BITS 53 + +#define STACK_BIAS 2047 + +struct machine_specific { + ulong page_offset; + ulong vmalloc_end; +}; + +#define TIF_SIGPENDING (2) +#define SWP_OFFSET(E) ((E) >> (PAGE_SHIFT + 8UL)) +#define SWP_TYPE(E) (((E) >> PAGE_SHIFT) & 0xffUL) +#define __swp_type(E) SWP_TYPE(E) +#define __swp_offset(E) SWP_OFFSET(E) +#endif /* SPARC64 */ + +#ifdef PLATFORM + +#define SWP_TYPE(entry) (error("PLATFORM_SWP_TYPE: TBD\n")) +#define SWP_OFFSET(entry) (error("PLATFORM_SWP_OFFSET: TBD\n")) +#define __swp_type(entry) SWP_TYPE(entry) +#define __swp_offset(entry) SWP_OFFSET(entry) + +#endif /* PLATFORM */ + +#define KILOBYTES(x) ((x) * (1024)) +#define MEGABYTES(x) ((x) * (1048576)) +#define GIGABYTES(x) ((x) * (1073741824)) +#define TB_SHIFT (40) +#define TERABYTES(x) ((x) * (1UL << TB_SHIFT)) + +#define MEGABYTE_MASK (MEGABYTES(1)-1) + +#define SIZEOF_64BIT (8) +#define SIZEOF_32BIT (4) +#define SIZEOF_16BIT (2) +#define SIZEOF_8BIT (1) + +#ifdef ARM +#define MAX_HEXADDR_STRLEN (8) +#define UVADDR_PRLEN (8) +#endif +#ifdef X86 +#define MAX_HEXADDR_STRLEN (8) +#define UVADDR_PRLEN (8) +#endif +#ifdef ALPHA +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (11) +#endif +#ifdef PPC +#define MAX_HEXADDR_STRLEN (8) +#define UVADDR_PRLEN (8) +#endif +#ifdef IA64 +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (16) +#endif +#ifdef S390 +#define MAX_HEXADDR_STRLEN (8) +#define UVADDR_PRLEN (8) +#endif +#ifdef S390X +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (16) +#endif +#ifdef X86_64 +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (10) +#endif +#ifdef PPC64 +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (16) +#endif +#ifdef ARM64 +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (10) +#endif +#ifdef MIPS +#define MAX_HEXADDR_STRLEN (8) +#define UVADDR_PRLEN (8) +#endif +#ifdef SPARC64 +#define MAX_HEXADDR_STRLEN (16) +#define UVADDR_PRLEN (16) +#endif + +#define BADADDR ((ulong)(-1)) +#define BADVAL ((ulong)(-1)) +#define UNUSED (-1) + +#define UNINITIALIZED (BADVAL) + +#define BITS_PER_BYTE (8) +#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#define NUM_TO_BIT(x) (1UL<<((x)%BITS_PER_LONG)) +#define NUM_IN_BITMAP(bitmap, x) (bitmap[(x)/BITS_PER_LONG] & NUM_TO_BIT(x)) +#define SET_BIT(bitmap, x) (bitmap[(x)/BITS_PER_LONG] |= NUM_TO_BIT(x)) + +/* + * precision lengths for fprintf + */ +#define VADDR_PRLEN (sizeof(char *) == 8 ? 16 : 8) +#define LONG_LONG_PRLEN (16) +#define LONG_PRLEN (sizeof(long) == 8 ? 16 : 8) +#define INT_PRLEN (sizeof(int) == 8 ? 16 : 8) +#define CHAR_PRLEN (2) +#define SHORT_PRLEN (4) + +#define MINSPACE (-100) + +#define SYNOPSIS (0x1) +#define COMPLETE_HELP (0x2) +#define PIPE_TO_SCROLL (0x4) +#define MUST_HELP (0x8) + +#define LEFT_JUSTIFY (1) +#define RIGHT_JUSTIFY (2) + +#define CENTER (0x1) +#define LJUST (0x2) +#define RJUST (0x4) +#define LONG_DEC (0x8) +#define LONG_HEX (0x10) +#define INT_DEC (0x20) +#define INT_HEX (0x40) +#define LONGLONG_HEX (0x80) +#define ZERO_FILL (0x100) +#define SLONG_DEC (0x200) + +#define INIT_TIME (1) +#define RUN_TIME (2) + +/* + * IRQ line status. + * For kernels up to and including 2.6.17 + */ +#define IRQ_INPROGRESS_2_6_17 1 /* IRQ handler active - do not enter! */ +#define IRQ_DISABLED_2_6_17 2 /* IRQ disabled - do not enter! */ +#define IRQ_PENDING_2_6_17 4 /* IRQ pending - replay on enable */ +#define IRQ_REPLAY_2_6_17 8 /* IRQ has been replayed but not acked yet */ +#define IRQ_AUTODETECT_2_6_17 16 /* IRQ is being autodetected */ +#define IRQ_WAITING_2_6_17 32 /* IRQ not yet seen - for autodetection */ +#define IRQ_LEVEL_2_6_17 64 /* IRQ level triggered */ +#define IRQ_MASKED_2_6_17 128 /* IRQ masked - shouldn't be seen again */ + +/* + * For kernel 2.6.21 and later + */ +#define IRQ_TYPE_NONE_2_6_21 0x00000000 /* Default, unspecified type */ +#define IRQ_TYPE_EDGE_RISING_2_6_21 0x00000001 /* Edge rising type */ +#define IRQ_TYPE_EDGE_FALLING_2_6_21 0x00000002 /* Edge falling type */ +#define IRQ_TYPE_EDGE_BOTH_2_6_21 (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) +#define IRQ_TYPE_LEVEL_HIGH_2_6_21 0x00000004 /* Level high type */ +#define IRQ_TYPE_LEVEL_LOW_2_6_21 0x00000008 /* Level low type */ +#define IRQ_TYPE_SENSE_MASK_2_6_21 0x0000000f /* Mask of the above */ +#define IRQ_TYPE_PROBE_2_6_21 0x00000010 /* Probing in progress */ + +#define IRQ_INPROGRESS_2_6_21 0x00000100 /* IRQ handler active - do not enter! */ +#define IRQ_DISABLED_2_6_21 0x00000200 /* IRQ disabled - do not enter! */ +#define IRQ_PENDING_2_6_21 0x00000400 /* IRQ pending - replay on enable */ +#define IRQ_REPLAY_2_6_21 0x00000800 /* IRQ has been replayed but not acked yet */ +#define IRQ_AUTODETECT_2_6_21 0x00001000 /* IRQ is being autodetected */ +#define IRQ_WAITING_2_6_21 0x00002000 /* IRQ not yet seen - for autodetection */ +#define IRQ_LEVEL_2_6_21 0x00004000 /* IRQ level triggered */ +#define IRQ_MASKED_2_6_21 0x00008000 /* IRQ masked - shouldn't be seen again */ +#define IRQ_PER_CPU_2_6_21 0x00010000 /* IRQ is per CPU */ +#define IRQ_NOPROBE_2_6_21 0x00020000 /* IRQ is not valid for probing */ +#define IRQ_NOREQUEST_2_6_21 0x00040000 /* IRQ cannot be requested */ +#define IRQ_NOAUTOEN_2_6_21 0x00080000 /* IRQ will not be enabled on request irq */ +#define IRQ_WAKEUP_2_6_21 0x00100000 /* IRQ triggers system wakeup */ +#define IRQ_MOVE_PENDING_2_6_21 0x00200000 /* need to re-target IRQ destination */ +#define IRQ_NO_BALANCING_2_6_21 0x00400000 /* IRQ is excluded from balancing */ +#define IRQ_SPURIOUS_DISABLED_2_6_21 0x00800000 /* IRQ was disabled by the spurious trap */ +#define IRQ_MOVE_PCNTXT_2_6_21 0x01000000 /* IRQ migration from process context */ +#define IRQ_AFFINITY_SET_2_6_21 0x02000000 /* IRQ affinity was set from userspace*/ + +/* + * Select proper IRQ value depending on kernel version + */ +#define IRQ_TYPE_NONE \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_NONE_2_6_21 : 0) +#define IRQ_TYPE_EDGE_RISING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_RISING_2_6_21 : 0) +#define IRQ_TYPE_EDGE_FALLING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_FALLING_2_6_21 : 0) +#define IRQ_TYPE_EDGE_BOTH \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_EDGE_BOTH_2_6_21 : 0) +#define IRQ_TYPE_LEVEL_HIGH \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_LEVEL_HIGH_2_6_21 : 0) +#define IRQ_TYPE_LEVEL_LOW \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_LEVEL_LOW_2_6_21 : 0) +#define IRQ_TYPE_SENSE_MASK \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_SENSE_MASK_2_6_21 : 0) +#define IRQ_TYPE_PROBE \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_TYPE_PROBE_2_6_21 : 0) + +#define IRQ_INPROGRESS \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_INPROGRESS_2_6_21 : IRQ_INPROGRESS_2_6_17) +#define IRQ_DISABLED \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_DISABLED_2_6_21 : IRQ_DISABLED_2_6_17) +#define IRQ_PENDING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_PENDING_2_6_21 : IRQ_PENDING_2_6_17) +#define IRQ_REPLAY \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_REPLAY_2_6_21 : IRQ_REPLAY_2_6_17) +#define IRQ_AUTODETECT \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_AUTODETECT_2_6_21 : IRQ_AUTODETECT_2_6_17) +#define IRQ_WAITING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_WAITING_2_6_21 : IRQ_WAITING_2_6_17) +#define IRQ_LEVEL \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_LEVEL_2_6_21 : IRQ_LEVEL_2_6_17) +#define IRQ_MASKED \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MASKED_2_6_21 : IRQ_MASKED_2_6_17) +#define IRQ_PER_CPU \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_PER_CPU_2_6_21 : 0) +#define IRQ_NOPROBE \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOPROBE_2_6_21 : 0) +#define IRQ_NOREQUEST \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOREQUEST_2_6_21 : 0) +#define IRQ_NOAUTOEN \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NOAUTOEN_2_6_21 : 0) +#define IRQ_WAKEUP \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_WAKEUP_2_6_21 : 0) +#define IRQ_MOVE_PENDING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MOVE_PENDING_2_6_21 : 0) +#define IRQ_NO_BALANCING \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_NO_BALANCING_2_6_21 : 0) +#define IRQ_SPURIOUS_DISABLED \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_SPURIOUS_DISABLED_2_6_21 : 0) +#define IRQ_MOVE_PCNTXT \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_MOVE_PCNTXT_2_6_21 : 0) +#define IRQ_AFFINITY_SET \ + (THIS_KERNEL_VERSION >= LINUX(2,6,21) ? IRQ_AFFINITY_SET_2_6_21 : 0) + +#ifdef ARM +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef X86 +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef X86_64 +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef ALPHA +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x40000000 +#endif + +#ifdef PPC +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef PPC64 +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000u +#endif + +#ifdef IA64 +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef S390 +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + +#ifdef S390X +#define SA_PROBE SA_ONESHOT +#define SA_SAMPLE_RANDOM SA_RESTART +#define SA_SHIRQ 0x04000000 +#define SA_RESTORER 0x04000000 +#endif + + +#define ACTION_FLAGS (SA_INTERRUPT|SA_PROBE|SA_SAMPLE_RANDOM|SA_SHIRQ) + + +#endif /* !GDB_COMMON */ + +/* + * Common request structure for BFD or GDB data or commands. + */ +struct gnu_request { + int command; + char *buf; + FILE *fp; + ulong addr; + ulong addr2; + ulong count; + ulong flags; + char *name; + ulong length; + int typecode; +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) + char *typename; +#else + char *type_name; +#endif + char *target_typename; + ulong target_length; + int target_typecode; + int is_typedef; + char *member; + long member_offset; + long member_length; + int member_typecode; + long value; + char *tagname; + ulong pc; + ulong sp; + ulong ra; + int curframe; + ulong frame; + ulong prevsp; + ulong prevpc; + ulong lastsp; + ulong task; + ulong debug; + struct stack_hook *hookp; + struct global_iterator { + int finished; + int block_index; + struct symtab *symtab; + struct symbol *sym; + struct objfile *obj; + } global_iterator; + struct load_module *lm; + char *member_main_type_name; + char *member_main_type_tag_name; + char *member_target_type_name; + char *member_target_type_tag_name; + char *type_tag_name; +}; + +/* + * GNU commands + */ +#define GNU_DATATYPE_INIT (1) +#define GNU_DISASSEMBLE (2) +#define GNU_GET_LINE_NUMBER (3) +#define GNU_PASS_THROUGH (4) +#define GNU_GET_DATATYPE (5) +#define GNU_COMMAND_EXISTS (6) +#define GNU_STACK_TRACE (7) +#define GNU_ALPHA_FRAME_OFFSET (8) +#define GNU_FUNCTION_NUMARGS (9) +#define GNU_RESOLVE_TEXT_ADDR (10) +#define GNU_ADD_SYMBOL_FILE (11) +#define GNU_DELETE_SYMBOL_FILE (12) +#define GNU_VERSION (13) +#define GNU_PATCH_SYMBOL_VALUES (14) +#define GNU_GET_SYMBOL_TYPE (15) +#define GNU_USER_PRINT_OPTION (16) +#define GNU_SET_CRASH_BLOCK (17) +#define GNU_GET_FUNCTION_RANGE (18) +#define GNU_GET_NEXT_DATATYPE (19) +#define GNU_LOOKUP_STRUCT_CONTENTS (20) +#define GNU_DEBUG_COMMAND (100) +/* + * GNU flags + */ +#define GNU_PRINT_LINE_NUMBERS (0x1) +#define GNU_FUNCTION_ONLY (0x2) +#define GNU_PRINT_ENUMERATORS (0x4) +#define GNU_RETURN_ON_ERROR (0x8) +#define GNU_COMMAND_FAILED (0x10) +#define GNU_FROM_TTY_OFF (0x20) +#define GNU_NO_READMEM (0x40) +#define GNU_VAR_LENGTH_TYPECODE (0x80) + +#undef TRUE +#undef FALSE + +#define TRUE (1) +#define FALSE (0) + +#ifdef GDB_COMMON +/* + * function prototypes required by modified gdb source files. + */ +int console(char *, ...); +int gdb_CRASHDEBUG(ulong); +int gdb_readmem_callback(ulong, void *, int, int); +void patch_load_module(struct objfile *objfile, struct minimal_symbol *msymbol); +int patch_kernel_symbol(struct gnu_request *); +struct syment *symbol_search(char *); +int gdb_line_number_callback(ulong, ulong, ulong); +int gdb_print_callback(ulong); +#endif + +#ifndef GDB_COMMON +/* + * WARNING: the following type codes are type_code enums from gdb/gdbtypes.h + */ +enum type_code { + TYPE_CODE_UNDEF, /* Not used; catches errors */ + TYPE_CODE_PTR, /* Pointer type */ + TYPE_CODE_ARRAY, /* Array type with lower & upper bounds. */ + TYPE_CODE_STRUCT, /* C struct or Pascal record */ + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) +#if defined(GDB_7_0) || defined(GDB_7_3_1) || defined(GDB_7_6) + TYPE_CODE_FLAGS, /* Bit flags type */ +#endif + TYPE_CODE_FUNC, /* Function type */ + TYPE_CODE_INT, /* Integer type */ + + /* Floating type. This is *NOT* a complex type. Beware, there are parts + of GDB which bogusly assume that TYPE_CODE_FLT can mean complex. */ + TYPE_CODE_FLT, + + /* Void type. The length field specifies the length (probably always + one) which is used in pointer arithmetic involving pointers to + this type, but actually dereferencing such a pointer is invalid; + a void type has no length and no actual representation in memory + or registers. A pointer to a void type is a generic pointer. */ + TYPE_CODE_VOID, + + TYPE_CODE_SET, /* Pascal sets */ + TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ + + /* + * NOTE: the remainder of the type codes are not list or used here... + */ + TYPE_CODE_BOOL = 20, +#endif +}; + +/* + * include/linux/sched.h + */ +#define PF_EXITING 0x00000004 /* getting shut down */ +#define PF_KTHREAD 0x00200000 /* I am a kernel thread */ +#define SCHED_NORMAL 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 +#define SCHED_BATCH 3 +#define SCHED_ISO 4 +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 + +extern long _ZOMBIE_; +#define IS_ZOMBIE(task) (task_state(task) & _ZOMBIE_) +#define IS_EXITING(task) (task_flags(task) & PF_EXITING) + +/* + * ps command options. + */ +#define PS_BY_PID (0x1) +#define PS_BY_TASK (0x2) +#define PS_BY_CMD (0x4) +#define PS_SHOW_ALL (0x8) +#define PS_PPID_LIST (0x10) +#define PS_CHILD_LIST (0x20) +#define PS_KERNEL (0x40) +#define PS_USER (0x80) +#define PS_TIMES (0x100) +#define PS_KSTACKP (0x200) +#define PS_LAST_RUN (0x400) +#define PS_ARGV_ENVP (0x800) +#define PS_TGID_LIST (0x1000) +#define PS_RLIMIT (0x2000) +#define PS_GROUP (0x4000) +#define PS_BY_REGEX (0x8000) +#define PS_NO_HEADER (0x10000) +#define PS_MSECS (0x20000) +#define PS_SUMMARY (0x40000) +#define PS_POLICY (0x80000) +#define PS_ACTIVE (0x100000) + +#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY|PS_ACTIVE) + +#define MAX_PS_ARGS (100) /* maximum command-line specific requests */ + +struct psinfo { + int argc; + ulong pid[MAX_PS_ARGS]; + int type[MAX_PS_ARGS]; + ulong task[MAX_PS_ARGS]; + char comm[MAX_PS_ARGS][TASK_COMM_LEN+1]; + struct regex_data { + char *pattern; + regex_t regex; + } regex_data[MAX_PS_ARGS]; + int regexs; + ulong *cpus; + int policy; +}; + +#define IS_A_NUMBER(X) (decimal(X, 0) || hexadecimal(X, 0)) +#define AMBIGUOUS_NUMBER(X) (decimal(X, 0) && hexadecimal(X, 0)) + +#define is_mclx_compressed_dump(X) (va_server_init((X), 0, 0, 0) == 0) + +struct task_mem_usage { + ulong rss; + ulong total_vm; + double pct_physmem; + ulong mm_struct_addr; + ulong pgd_addr; +}; + +/* + * Global data (global_data.c) + */ +extern FILE *fp; +extern struct program_context program_context, *pc; +extern struct task_table task_table, *tt; +extern struct kernel_table kernel_table, *kt; +extern struct command_table_entry linux_command_table[]; +extern char *args[MAXARGS]; +extern int argcnt; +extern int argerrs; +extern struct offset_table offset_table; +extern struct size_table size_table; +extern struct array_table array_table; +extern struct vm_table vm_table, *vt; +extern struct machdep_table *machdep; +extern struct symbol_table_data symbol_table_data, *st; +extern struct extension_table *extension_table; + +/* + * Generated in build_data.c + */ +extern char *build_command; +extern char *build_data; +extern char *build_target; +extern char *build_version; +extern char *compiler_version; + + +/* + * command prototypes + */ +void cmd_quit(void); /* main.c */ +void cmd_mach(void); /* main.c */ +void cmd_help(void); /* help.c */ +void cmd_test(void); /* test.c */ +void cmd_ascii(void); /* tools.c */ +void cmd_bpf(void); /* bfp.c */ +void cmd_set(void); /* tools.c */ +void cmd_eval(void); /* tools.c */ +void cmd_list(void); /* tools.c */ +void cmd_tree(void); /* tools.c */ +void cmd_template(void); /* tools.c */ +void cmd_alias(void); /* cmdline.c */ +void cmd_repeat(void); /* cmdline.c */ +void cmd_rd(void); /* memory.c */ +void cmd_wr(void); /* memory.c */ +void cmd_ptov(void); /* memory.c */ +void cmd_vtop(void); /* memory.c */ +void cmd_vm(void); /* memory.c */ +void cmd_ptob(void); /* memory.c */ +void cmd_btop(void); /* memory.c */ +void cmd_kmem(void); /* memory.c */ +void cmd_search(void); /* memory.c */ +void cmd_swap(void); /* memory.c */ +void cmd_pte(void); /* memory.c */ +void cmd_ps(void); /* task.c */ +void cmd_task(void); /* task.c */ +void cmd_foreach(void); /* task.c */ +void cmd_runq(void); /* task.c */ +void cmd_sig(void); /* task.c */ +void cmd_bt(void); /* kernel.c */ +void cmd_dis(void); /* kernel.c */ +void cmd_mod(void); /* kernel.c */ +void cmd_log(void); /* kernel.c */ +void cmd_sys(void); /* kernel.c */ +void cmd_irq(void); /* kernel.c */ +void cmd_timer(void); /* kernel.c */ +void cmd_waitq(void); /* kernel.c */ +void cmd_sym(void); /* symbols.c */ +void cmd_struct(void); /* symbols.c */ +void cmd_union(void); /* symbols.c */ +void cmd_pointer(void); /* symbols.c */ +void cmd_whatis(void); /* symbols.c */ +void cmd_p(void); /* symbols.c */ +void cmd_mount(void); /* filesys.c */ +void cmd_files(void); /* filesys.c */ +void cmd_fuser(void); /* filesys.c */ +void cmd_dev(void); /* dev.c */ +void cmd_gdb(void); /* gdb_interface.c */ +void cmd_net(void); /* net.c */ +void cmd_extend(void); /* extensions.c */ +#if defined(S390) || defined(S390X) +void cmd_s390dbf(void); +#endif +void cmd_map(void); /* kvmdump.c */ +void cmd_ipcs(void); /* ipcs.c */ + +/* + * main.c + */ +void main_loop(void); +void exec_command(void); +struct command_table_entry *get_command_table_entry(char *); +void program_usage(int); +#define LONG_FORM (1) +#define SHORT_FORM (0) +void dump_program_context(void); +void dump_build_data(void); +#ifdef ARM +#define machdep_init(X) arm_init(X) +#endif +#ifdef ARM64 +#define machdep_init(X) arm64_init(X) +#endif +#ifdef X86 +#define machdep_init(X) x86_init(X) +#endif +#ifdef ALPHA +#define machdep_init(X) alpha_init(X) +#endif +#ifdef PPC +#define machdep_init(X) ppc_init(X) +#endif +#ifdef IA64 +#define machdep_init(X) ia64_init(X) +#endif +#ifdef S390 +#define machdep_init(X) s390_init(X) +#endif +#ifdef S390X +#define machdep_init(X) s390x_init(X) +#endif +#ifdef X86_64 +#define machdep_init(X) x86_64_init(X) +#endif +#ifdef PPC64 +#define machdep_init(X) ppc64_init(X) +#endif +#ifdef MIPS +#define machdep_init(X) mips_init(X) +#endif +#ifdef SPARC64 +#define machdep_init(X) sparc64_init(X) +#endif +int clean_exit(int); +int untrusted_file(FILE *, char *); +char *readmem_function_name(void); +char *writemem_function_name(void); +char *no_vmcoreinfo(const char *); + +/* + * cmdline.c + */ +void restart(int); +void alias_init(char *); +struct alias_data *is_alias(char *); +void deallocate_alias(char *); +void cmdline_init(void); +void set_command_prompt(char *); +void exec_input_file(void); +void process_command_line(void); +void dump_history(void); +void resolve_rc_cmd(char *, int); +void dump_alias_data(void); +int output_open(void); +#define output_closed() (!output_open()) +void close_output(void); +int interruptible(void); +int received_SIGINT(void); +void debug_redirect(char *); +int CRASHPAGER_valid(void); +char *setup_scroll_command(void); +int minimal_functions(char *); +int is_args_input_file(struct command_table_entry *, struct args_input_file *); +void exec_args_input_file(struct command_table_entry *, struct args_input_file *); + +/* + * tools.c + */ +FILE *set_error(char *); +int __error(int, char *, ...); +#define error __error /* avoid conflict with gdb error() */ +int console(char *, ...); +void create_console_device(char *); +int console_off(void); +int console_on(int); +int console_verbatim(char *); +int whitespace(int); +int ascii(int); +int ascii_string(char *); +int printable_string(char *); +char *clean_line(char *); +char *strip_line_end(char *); +char *strip_linefeeds(char *); +char *strip_beginning_whitespace(char *); +char *strip_ending_whitespace(char *); +char *strip_ending_char(char *, char); +char *strip_beginning_char(char *, char); +char *strip_comma(char *); +char *strip_hex(char *); +char *upper_case(const char *, char *); +char *first_nonspace(char *); +char *first_space(char *); +char *replace_string(char *, char *, char); +void string_insert(char *, char *); +char *strstr_rightmost(char *, char *); +char *null_first_space(char *); +int parse_line(char *, char **); +void print_verbatim(FILE *, char *); +char *fixup_percent(char *); +int can_eval(char *); +ulong eval(char *, int, int *); +ulonglong evall(char *, int, int *); +int eval_common(char *, int, int *, struct number_option *); +ulong htol(char *, int, int *); +ulong dtol(char *, int, int *); +unsigned int dtoi(char *, int, int *); +ulong stol(char *, int, int *); +ulonglong stoll(char *, int, int *); +ulonglong htoll(char *, int, int *); +ulonglong dtoll(char *, int, int *); +int decimal(char *, int); +int hexadecimal(char *, int); +int hexadecimal_only(char *, int); +ulong convert(char *, int, int *, ulong); +void pad_line(FILE *, int, char); +#define INDENT(x) pad_line(fp, x, ' ') +char *mkstring(char *, int, ulong, const char *); +#define MKSTR(X) ((const char *)(X)) +int count_leading_spaces(char *); +int count_chars(char *, char); +long count_buffer_chars(char *, char, long); +char *space(int); +char *concat_args(char *, int, int); +char *shift_string_left(char *, int); +char *shift_string_right(char *, int); +int bracketed(char *, char *, int); +void backspace(int); +int do_list(struct list_data *); +int do_list_no_hash(struct list_data *); +struct radix_tree_ops { + void (*entry)(ulong node, ulong slot, const char *path, + ulong index, void *private); + uint radix; + void *private; +}; +int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops); +struct xarray_ops { + void (*entry)(ulong node, ulong slot, const char *path, + ulong index, void *private); + uint radix; + void *private; +}; +int do_xarray_traverse(ulong ptr, int is_root, struct xarray_ops *ops); +int do_rdtree(struct tree_data *); +int do_rbtree(struct tree_data *); +int do_xatree(struct tree_data *); +int retrieve_list(ulong *, int); +long power(long, int); +long long ll_power(long long, long long); +void hq_init(void); +int hq_open(void); +int hq_close(void); +int hq_enter(ulong); +int hq_entry_exists(ulong); +int hq_is_open(void); +int hq_is_inuse(void); +long get_embedded(void); +void dump_embedded(char *); +char *ordinal(ulong, char *); +char *first_nonspace(char *); +void dump_hash_table(int); +void dump_shared_bufs(void); +void drop_core(char *); +int extract_hex(char *, ulong *, char, ulong); +int count_bits_int(int); +int count_bits_long(ulong); +int highest_bit_long(ulong); +int lowest_bit_long(ulong); +void buf_init(void); +void sym_buf_init(void); +void free_all_bufs(void); +char *getbuf(long); +void freebuf(char *); +char *resizebuf(char *, long, long); +char *strdupbuf(char *); +#define GETBUF(X) getbuf((long)(X)) +#define FREEBUF(X) freebuf((char *)(X)) +#define RESIZEBUF(X,Y,Z) (X) = (typeof(X))resizebuf((char *)(X), (long)(Y), (long)(Z)); +#define STRDUPBUF(X) strdupbuf((char *)(X)) +void sigsetup(int, void *, struct sigaction *, struct sigaction *); +#define SIGACTION(s, h, a, o) sigsetup(s, h, a, o) +char *convert_time(ulonglong, char *); +void stall(ulong); +char *pages_to_size(ulong, char *); +int clean_arg(void); +int empty_list(ulong); +int machine_type(char *); +int machine_type_mismatch(char *, char *, char *, ulong); +void command_not_supported(void); +void option_not_supported(int); +void please_wait(char *); +void please_wait_done(void); +int pathcmp(char *, char *); +int calculate(char *, ulong *, ulonglong *, ulong); +int endian_mismatch(char *, char, ulong); +uint16_t swap16(uint16_t, int); +uint32_t swap32(uint32_t, int); +uint64_t swap64(uint64_t, int); +ulong *get_cpumask_buf(void); +int make_cpumask(char *, ulong *, int, int *); +size_t strlcpy(char *, char *, size_t); +struct rb_node *rb_first(struct rb_root *); +struct rb_node *rb_parent(struct rb_node *, struct rb_node *); +struct rb_node *rb_right(struct rb_node *, struct rb_node *); +struct rb_node *rb_left(struct rb_node *, struct rb_node *); +struct rb_node *rb_next(struct rb_node *); +struct rb_node *rb_last(struct rb_root *); + +/* + * symbols.c + */ +void symtab_init(void); +char *check_specified_kernel_debug_file(void); +void no_debugging_data(int); +void get_text_init_space(void); +int is_kernel_text(ulong); +int is_kernel_data(ulong); +int is_init_data(ulong value); +int is_kernel_text_offset(ulong); +int is_symbol_text(struct syment *); +int is_rodata(ulong, struct syment **); +int get_text_function_range(ulong, ulong *, ulong *); +void datatype_init(void); +struct syment *symbol_search(char *); +struct syment *value_search(ulong, ulong *); +struct syment *value_search_base_kernel(ulong, ulong *); +struct syment *value_search_module(ulong, ulong *); +struct syment *symbol_search_next(char *, struct syment *); +ulong highest_bss_symbol(void); +int in_ksymbol_range(ulong); +int module_symbol(ulong, struct syment **, + struct load_module **, char *, ulong); +#define IS_MODULE_VADDR(X) \ + (module_symbol((ulong)(X), NULL, NULL, NULL, *gdb_output_radix)) +char *closest_symbol(ulong); +ulong closest_symbol_value(ulong); +#define SAME_FUNCTION(X,Y) (closest_symbol_value(X) == closest_symbol_value(Y)) +void show_symbol(struct syment *, ulong, ulong); +#define SHOW_LINENUM (0x1) +#define SHOW_SECTION (0x2) +#define SHOW_HEX_OFFS (0x4) +#define SHOW_DEC_OFFS (0x8) +#define SHOW_RADIX() (*gdb_output_radix == 16 ? SHOW_HEX_OFFS : SHOW_DEC_OFFS) +#define SHOW_MODULE (0x10) +int symbol_name_count(char *); +int symbol_query(char *, char *, struct syment **); +struct syment *next_symbol(char *, struct syment *); +struct syment *prev_symbol(char *, struct syment *); +void get_symbol_data(char *, long, void *); +int try_get_symbol_data(char *, long, void *); +char *value_to_symstr(ulong, char *, ulong); +char *value_symbol(ulong); +ulong symbol_value(char *); +ulong symbol_value_module(char *, char *); +struct syment *per_cpu_symbol_search(char *); +int symbol_exists(char *s); +int kernel_symbol_exists(char *s); +struct syment *kernel_symbol_search(char *); +ulong symbol_value_from_proc_kallsyms(char *); +int get_syment_array(char *, struct syment **, int); +void set_temporary_radix(unsigned int, unsigned int *); +void restore_current_radix(unsigned int); +void dump_struct(char *, ulong, unsigned); +void dump_struct_member(char *, ulong, unsigned); +void dump_union(char *, ulong, unsigned); +void store_module_symbols_v1(ulong, int); +void store_module_symbols_v2(ulong, int); +int is_datatype_command(void); +int is_typedef(char *); +int arg_to_datatype(char *, struct datatype_member *, ulong); +void dump_symbol_table(void); +void dump_struct_table(ulong); +void dump_offset_table(char *, ulong); +int is_elf_file(char *); +int is_kernel(char *); +int is_shared_object(char *); +int file_elf_version(char *); +int is_system_map(char *); +int is_compressed_kernel(char *, char **); +int select_namelist(char *); +int get_array_length(char *, int *, long); +int get_array_length_alt(char *, char *, int *, long); +int builtin_array_length(char *, int, int *); +char *get_line_number(ulong, char *, int); +char *get_build_directory(char *); +int datatype_exists(char *); +int get_function_numargs(ulong); +int is_module_name(char *, ulong *, struct load_module **); +int is_module_address(ulong, char *); +ulong lowest_module_address(void); +ulong highest_module_address(void); +int load_module_symbols(char *, char *, ulong); +void delete_load_module(ulong); +ulong gdb_load_module_callback(ulong, char *); +char *load_module_filter(char *, int); +#define LM_P_FILTER (1) +#define LM_DIS_FILTER (2) +long datatype_info(char *, char *, struct datatype_member *); +int get_symbol_type(char *, char *, struct gnu_request *); +int get_symbol_length(char *); +int text_value_cache(ulong, uint32_t, uint32_t *); +int text_value_cache_byte(ulong, unsigned char *); +void dump_text_value_cache(int); +void clear_text_value_cache(void); +void dump_numargs_cache(void); +int patch_kernel_symbol(struct gnu_request *); +struct syment *generic_machdep_value_to_symbol(ulong, ulong *); +long OFFSET_verify(long, char *, char *, int, char *); +long SIZE_verify(long, char *, char *, int, char *); +long OFFSET_option(long, long, char *, char *, int, char *, char *); +long SIZE_option(long, long, char *, char *, int, char *, char *); +void dump_trace(void **); +int enumerator_value(char *, long *); +int dump_enumerator_list(char *); +struct load_module *init_module_function(ulong); +struct struct_member_data { + char *structure; + char *member; + long type; + long unsigned_type; + long length; + long offset; + long bitpos; + long bitsize; +}; +int fill_struct_member_data(struct struct_member_data *); +void parse_for_member_extended(struct datatype_member *, ulong); +void add_to_downsized(char *); +int is_downsized(char *); +int is_string(char *, char *); +struct syment *symbol_complete_match(const char *, struct syment *); + +/* + * memory.c + */ +void mem_init(void); +void vm_init(void); +int readmem(ulonglong, int, void *, long, char *, ulong); +int writemem(ulonglong, int, void *, long, char *, ulong); +int generic_verify_paddr(uint64_t); +int read_dev_mem(int, void *, int, ulong, physaddr_t); +int read_memory_device(int, void *, int, ulong, physaddr_t); +int read_mclx_dumpfile(int, void *, int, ulong, physaddr_t); +int read_lkcd_dumpfile(int, void *, int, ulong, physaddr_t); +int read_daemon(int, void *, int, ulong, physaddr_t); +int write_dev_mem(int, void *, int, ulong, physaddr_t); +int write_memory_device(int, void *, int, ulong, physaddr_t); +int write_mclx_dumpfile(int, void *, int, ulong, physaddr_t); +int write_lkcd_dumpfile(int, void *, int, ulong, physaddr_t); +int write_daemon(int, void *, int, ulong, physaddr_t); +int kvtop(struct task_context *, ulong, physaddr_t *, int); +int uvtop(struct task_context *, ulong, physaddr_t *, int); +void do_vtop(ulong, struct task_context *, ulong); +void raw_stack_dump(ulong, ulong); +void raw_data_dump(ulong, long, int); +int accessible(ulong); +ulong vm_area_dump(ulong, ulong, ulong, struct reference *); +#define IN_TASK_VMA(TASK,VA) (vm_area_dump((TASK), UVADDR|VERIFY_ADDR, (VA), 0)) +char *fill_vma_cache(ulong); +void clear_vma_cache(void); +void dump_vma_cache(ulong); +int generic_is_page_ptr(ulong, physaddr_t *); +int is_page_ptr(ulong, physaddr_t *); +void dump_vm_table(int); +int read_string(ulong, char *, int); +void get_task_mem_usage(ulong, struct task_mem_usage *); +char *get_memory_size(char *); +uint64_t generic_memory_size(void); +char *swap_location(ulonglong, char *); +void clear_swap_info_cache(void); +uint memory_page_size(void); +void force_page_size(char *); +ulong first_vmalloc_address(void); +ulong last_vmalloc_address(void); +int in_vmlist_segment(ulong); +int phys_to_page(physaddr_t, ulong *); +int generic_get_kvaddr_ranges(struct vaddr_range *); +int l1_cache_size(void); +int dumpfile_memory(int); +#define DUMPFILE_MEM_USED (1) +#define DUMPFILE_FREE_MEM (2) +#define DUMPFILE_MEM_DUMP (3) +#define DUMPFILE_ENVIRONMENT (4) +uint64_t total_node_memory(void); +int generic_is_kvaddr(ulong); +int generic_is_uvaddr(ulong, struct task_context *); +void fill_stackbuf(struct bt_info *); +void alter_stackbuf(struct bt_info *); +int vaddr_type(ulong, struct task_context *); +char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong); +int in_user_stack(ulong, ulong); +int dump_inode_page(ulong); +ulong valid_section_nr(ulong); +void display_memory_from_file_offset(ulonglong, long, void *); + + +/* + * filesys.c + */ +void fd_init(void); +void vfs_init(void); +int is_a_tty(char *); +int file_exists(char *, struct stat *); +int file_readable(char *); +int is_directory(char *); +char *search_directory_tree(char *, char *, int); +void open_tmpfile(void); +void close_tmpfile(void); +void open_tmpfile2(void); +void set_tmpfile2(FILE *); +void close_tmpfile2(void); +void open_files_dump(ulong, int, struct reference *); +void get_pathname(ulong, char *, int, int, ulong); +ulong *get_mount_list(int *, struct task_context *); +char *vfsmount_devname(ulong, char *, int); +ulong file_to_dentry(ulong); +ulong file_to_vfsmnt(ulong); +int get_proc_version(void); +int file_checksum(char *, long *); +void dump_filesys_table(int); +char *fill_file_cache(ulong); +void clear_file_cache(void); +char *fill_dentry_cache(ulong); +void clear_dentry_cache(void); +char *fill_inode_cache(ulong); +void clear_inode_cache(void); +int monitor_memory(long *, long *, long *, long *); +int is_readable(char *); +struct list_pair { + ulong index; + void *value; +}; +#define radix_tree_pair list_pair +ulong do_radix_tree(ulong, int, struct list_pair *); +#define RADIX_TREE_COUNT (1) +#define RADIX_TREE_SEARCH (2) +#define RADIX_TREE_DUMP (3) +#define RADIX_TREE_GATHER (4) +#define RADIX_TREE_DUMP_CB (5) +/* + * from: "include/linux/radix-tree.h" + */ +#define RADIX_TREE_ENTRY_MASK 3UL +#define RADIX_TREE_EXCEPTIONAL_ENTRY 2 + +ulong do_xarray(ulong, int, struct list_pair *); +#define XARRAY_COUNT (1) +#define XARRAY_SEARCH (2) +#define XARRAY_DUMP (3) +#define XARRAY_GATHER (4) +#define XARRAY_DUMP_CB (5) +#define XARRAY_TAG_MASK (3UL) +#define XARRAY_TAG_INTERNAL (2UL) + +int file_dump(ulong, ulong, ulong, int, int); +#define DUMP_FULL_NAME 0x1 +#define DUMP_INODE_ONLY 0x2 +#define DUMP_DENTRY_ONLY 0x4 +#define DUMP_EMPTY_FILE 0x8 +#define DUMP_FILE_NRPAGES 0x10 +#endif /* !GDB_COMMON */ +int same_file(char *, char *); +#ifndef GDB_COMMON +int cleanup_memory_driver(void); + + +/* + * help.c + */ +#define HELP_COLUMNS 5 +#define START_OF_HELP_DATA(X) "START_OF_HELP_DATA" X +#define END_OF_HELP_DATA "END_OF_HELP_DATA" +void help_init(void); +void cmd_usage(char *, int); +void display_version(void); +void display_help_screen(char *); +#ifdef ARM +#define dump_machdep_table(X) arm_dump_machdep_table(X) +#endif +#ifdef ARM64 +#define dump_machdep_table(X) arm64_dump_machdep_table(X) +#endif +#ifdef X86 +#define dump_machdep_table(X) x86_dump_machdep_table(X) +#endif +#ifdef ALPHA +#define dump_machdep_table(X) alpha_dump_machdep_table(X) +#endif +#ifdef PPC +#define dump_machdep_table(X) ppc_dump_machdep_table(X) +#endif +#ifdef IA64 +#define dump_machdep_table(X) ia64_dump_machdep_table(X) +#endif +#ifdef S390 +#define dump_machdep_table(X) s390_dump_machdep_table(X) +#endif +#ifdef S390X +#define dump_machdep_table(X) s390x_dump_machdep_table(X) +#endif +#ifdef X86_64 +#define dump_machdep_table(X) x86_64_dump_machdep_table(X) +#endif +#ifdef PPC64 +#define dump_machdep_table(X) ppc64_dump_machdep_table(X) +#endif +#ifdef MIPS +#define dump_machdep_table(X) mips_dump_machdep_table(X) +#endif +#ifdef SPARC64 +#define dump_machdep_table(X) sparc64_dump_machdep_table(X) +#endif +extern char *help_pointer[]; +extern char *help_alias[]; +extern char *help_ascii[]; +extern char *help_bpf[]; +extern char *help_bt[]; +extern char *help_btop[]; +extern char *help_dev[]; +extern char *help_dis[]; +extern char *help_eval[]; +extern char *help_exit[]; +extern char *help_extend[]; +extern char *help_files[]; +extern char *help_foreach[]; +extern char *help_fuser[]; +extern char *help_gdb[]; +extern char *help_help[]; +extern char *help_irq[]; +extern char *help_kmem[]; +extern char *help__list[]; +extern char *help_tree[]; +extern char *help_log[]; +extern char *help_mach[]; +extern char *help_mod[]; +extern char *help_mount[]; +extern char *help_net[]; +extern char *help_p[]; +extern char *help_ps[]; +extern char *help_pte[]; +extern char *help_ptob[]; +extern char *help_ptov[]; +extern char *help_quit[]; +extern char *help_rd[]; +extern char *help_repeat[]; +extern char *help_runq[]; +extern char *help_ipcs[]; +extern char *help_search[]; +extern char *help_set[]; +extern char *help_sig[]; +extern char *help_struct[]; +extern char *help_swap[]; +extern char *help_sym[]; +extern char *help_sys[]; +extern char *help_task[]; +extern char *help_timer[]; +extern char *help_union[]; +extern char *help_vm[]; +extern char *help_vtop[]; +extern char *help_waitq[]; +extern char *help_whatis[]; +extern char *help_wr[]; +#if defined(S390) || defined(S390X) +extern char *help_s390dbf[]; +#endif +extern char *help_map[]; + +/* + * task.c + */ +void task_init(void); +int set_context(ulong, ulong); +void show_context(struct task_context *); +ulong pid_to_task(ulong); +ulong task_to_pid(ulong); +int task_exists(ulong); +int is_kernel_thread(ulong); +int is_idle_thread(ulong); +void get_idle_threads(ulong *, int); +char *task_state_string(ulong, char *, int); +ulong task_flags(ulong); +ulong task_state(ulong); +ulong task_mm(ulong, int); +ulong task_tgid(ulong); +ulonglong task_last_run(ulong); +ulong vaddr_in_task_struct(ulong); +int comm_exists(char *); +struct task_context *task_to_context(ulong); +struct task_context *pid_to_context(ulong); +struct task_context *tgid_to_context(ulong); +ulong stkptr_to_task(ulong); +ulong task_to_thread_info(ulong); +ulong task_to_stackbase(ulong); +int str_to_context(char *, ulong *, struct task_context **); +#define STR_PID (0x1) +#define STR_TASK (0x2) +#define STR_INVALID (0x4) +char *get_panicmsg(char *); +char *task_cpu(int, char *, int); +void print_task_header(FILE *, struct task_context *, int); +ulong get_active_task(int); +int is_task_active(ulong); +int is_panic_thread(ulong); +int get_panic_ksp(struct bt_info *, ulong *); +void foreach(struct foreach_data *); +int pid_exists(ulong); +#define TASKS_PER_PID(x) pid_exists(x) +char *fill_task_struct(ulong); +#define IS_LAST_TASK_READ(task) ((ulong)(task) == tt->last_task_read) +char *fill_thread_info(ulong); +#define IS_LAST_THREAD_INFO_READ(ti) ((ulong)(ti) == tt->last_thread_info_read) +char *fill_mm_struct(ulong); +#define IS_LAST_MM_READ(mm) ((ulong)(mm) == tt->last_mm_read) +void do_task(ulong, ulong, struct reference *, unsigned int); +void clear_task_cache(void); +int get_active_set(void); +void clear_active_set(void); +void do_sig(ulong, ulong, struct reference *); +void modify_signame(int, char *, char *); +ulong generic_get_stackbase(ulong); +ulong generic_get_stacktop(ulong); +void dump_task_table(int); +void sort_context_array(void); +void sort_tgid_array(void); +int sort_by_tgid(const void *, const void *); +int in_irq_ctx(ulonglong, int, ulong); +void check_stack_overflow(void); + +/* + * extensions.c + */ +void register_extension(struct command_table_entry *); +void dump_extension_table(int); +void load_extension(char *); +void unload_extension(char *); +void preload_extensions(void); +/* Hooks for sial */ +unsigned long get_curtask(void); +char *crash_global_cmd(void); +struct command_table_entry *crash_cmd_table(void); + +/* + * kernel.c + */ +void kernel_init(void); +void module_init(void); +void verify_version(void); +void verify_spinlock(void); +void non_matching_kernel(void); +struct load_module *modref_to_load_module(char *); +int load_module_symbols_helper(char *); +void unlink_module(struct load_module *); +int check_specified_module_tree(char *, char *); +int is_system_call(char *, ulong); +void generic_dump_irq(int); +void generic_get_irq_affinity(int); +void generic_show_interrupts(int, ulong *); +int generic_dis_filter(ulong, char *, unsigned int); +int kernel_BUG_encoding_bytes(void); +void display_sys_stats(void); +char *get_uptime(char *, ulonglong *); +void clone_bt_info(struct bt_info *, struct bt_info *, struct task_context *); +void dump_kernel_table(int); +void dump_bt_info(struct bt_info *, char *where); +void dump_log(int); +#define SHOW_LOG_LEVEL (0x1) +#define SHOW_LOG_DICT (0x2) +#define SHOW_LOG_TEXT (0x4) +#define SHOW_LOG_AUDIT (0x8) +void set_cpu(int); +void clear_machdep_cache(void); +struct stack_hook *gather_text_list(struct bt_info *); +int get_cpus_online(void); +int get_cpus_active(void); +int get_cpus_present(void); +int get_cpus_possible(void); +int check_offline_cpu(int); +int hide_offline_cpu(int); +int get_highest_cpu_online(void); +int get_highest_cpu_present(void); +int get_cpus_to_display(void); +void get_log_from_vmcoreinfo(char *file); +int in_cpu_map(int, int); +void paravirt_init(void); +void print_stack_text_syms(struct bt_info *, ulong, ulong); +void back_trace(struct bt_info *); +int in_alternate_stack(int, ulong); +ulong cpu_map_addr(const char *type); +#define BT_RAW (0x1ULL) +#define BT_SYMBOLIC_ARGS (0x2ULL) +#define BT_FULL (0x4ULL) +#define BT_TEXT_SYMBOLS (0x8ULL) +#define BT_TEXT_SYMBOLS_PRINT (0x10ULL) +#define BT_TEXT_SYMBOLS_NOPRINT (0x20ULL) +#define BT_USE_GDB (0x40ULL) +#define BT_EXCEPTION_FRAME (0x80ULL) +#define BT_LINE_NUMBERS (0x100ULL) +#define BT_USER_EFRAME (0x200ULL) +#define BT_INCOMPLETE_USER_EFRAME (BT_USER_EFRAME) +#define BT_SAVE_LASTSP (0x400ULL) +#define BT_FROM_EXCEPTION (0x800ULL) +#define BT_FROM_CALLFRAME (0x1000ULL) +#define BT_EFRAME_SEARCH (0x2000ULL) +#define BT_SPECULATE (0x4000ULL) +#define BT_FRAMESIZE_DISABLE (BT_SPECULATE) +#define BT_RESCHEDULE (0x8000ULL) +#define BT_SCHEDULE (BT_RESCHEDULE) +#define BT_RET_FROM_SMP_FORK (0x10000ULL) +#define BT_STRACE (0x20000ULL) +#define BT_KDUMP_ADJUST (BT_STRACE) +#define BT_KSTACKP (0x40000ULL) +#define BT_LOOP_TRAP (0x80000ULL) +#define BT_BUMP_FRAME_LEVEL (0x100000ULL) +#define BT_EFRAME_COUNT (0x200000ULL) +#define BT_CPU_IDLE (0x400000ULL) +#define BT_WRAP_TRAP (0x800000ULL) +#define BT_KERNEL_THREAD (0x1000000ULL) +#define BT_ERROR_MASK (BT_LOOP_TRAP|BT_WRAP_TRAP|BT_KERNEL_THREAD|BT_CPU_IDLE) +#define BT_UNWIND_ERROR (0x2000000ULL) +#define BT_OLD_BACK_TRACE (0x4000000ULL) +#define BT_OPT_BACK_TRACE (0x4000000ULL) +#define BT_FRAMESIZE_DEBUG (0x8000000ULL) +#define BT_CONTEXT_SWITCH (0x10000000ULL) +#define BT_HARDIRQ (0x20000000ULL) +#define BT_SOFTIRQ (0x40000000ULL) +#define BT_CHECK_CALLER (0x80000000ULL) +#define BT_NO_CHECK_CALLER (0x100000000ULL) +#define BT_EXCEPTION_STACK (0x200000000ULL) +#define BT_IRQSTACK (0x400000000ULL) +#define BT_DUMPFILE_SEARCH (0x800000000ULL) +#define BT_EFRAME_SEARCH2 (0x1000000000ULL) +#define BT_START (0x2000000000ULL) +#define BT_TEXT_SYMBOLS_ALL (0x4000000000ULL) +#define BT_XEN_STOP_THIS_CPU (0x8000000000ULL) +#define BT_THREAD_GROUP (0x10000000000ULL) +#define BT_SAVE_EFRAME_IP (0x20000000000ULL) +#define BT_FULL_SYM_SLAB (0x40000000000ULL) +#define BT_KDUMP_ELF_REGS (0x80000000000ULL) +#define BT_USER_SPACE (0x100000000000ULL) +#define BT_KERNEL_SPACE (0x200000000000ULL) +#define BT_FULL_SYM_SLAB2 (0x400000000000ULL) +#define BT_EFRAME_TARGET (0x800000000000ULL) +#define BT_CPUMASK (0x1000000000000ULL) +#define BT_SHOW_ALL_REGS (0x2000000000000ULL) +#define BT_REGS_NOT_FOUND (0x4000000000000ULL) +#define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) + +#define BT_REF_HEXVAL (0x1) +#define BT_REF_SYMBOL (0x2) +#define BT_REF_FOUND (0x4) +#define BT_REFERENCE_CHECK(X) ((X)->ref) +#define BT_REFERENCE_FOUND(X) ((X)->ref && ((X)->ref->cmdflags & BT_REF_FOUND)) + +#define NO_MODULES() \ + (!kt->module_list || (kt->module_list == kt->kernel_module)) + +#define USER_EFRAME_ADDR(task) \ + ((ulong)task + UNION_SIZE("task_union") - SIZE(pt_regs)) + +struct remote_file { + char *filename; + char *local; + int fd; + int flags; + int type; + long csum; + off_t size; +}; + +#define REMOTE_VERBOSE (O_RDWR << 1) +#define REMOTE_COPY_DONE (REMOTE_VERBOSE << 1) +#define TYPE_ELF (REMOTE_VERBOSE << 2) +#define TYPE_DEVMEM (REMOTE_VERBOSE << 3) +#define TYPE_MCLXCD (REMOTE_VERBOSE << 4) +#define TYPE_LKCD (REMOTE_VERBOSE << 5) +#define TYPE_S390D (REMOTE_VERBOSE << 6) +#define TYPE_NETDUMP (REMOTE_VERBOSE << 7) + +ulonglong xen_m2p(ulonglong); + +void read_in_kernel_config(int); + +#define IKCFG_INIT (0) +#define IKCFG_READ (1) +#define IKCFG_SETUP (2) +#define IKCFG_FREE (3) + +int get_kernel_config(char *, char **); +enum { + IKCONFIG_N, + IKCONFIG_Y, + IKCONFIG_M, + IKCONFIG_STR, +}; + +#define MAGIC_START "IKCFG_ST" +#define MAGIC_END "IKCFG_ED" +#define MAGIC_SIZE (sizeof(MAGIC_START) - 1) + +/* + * dev.c + */ +void dev_init(void); +void dump_dev_table(void); +void devdump_extract(void *, ulonglong, char *, FILE *); +void devdump_info(void *, ulonglong, FILE *); + +/* + * ipcs.c + */ +void ipcs_init(void); +ulong idr_find(ulong, int); + +#ifdef ARM +void arm_init(int); +void arm_dump_machdep_table(ulong); +int arm_is_vmalloc_addr(ulong); +void arm_dump_backtrace_entry(struct bt_info *, int, ulong, ulong); + +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to ARM architecture\n") + +struct arm_pt_regs { + ulong uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +#define KSYMS_START (0x1) +#define PHYS_BASE (0x2) +#define PGTABLE_V2 (0x4) +#define IDMAP_PGD (0x8) + +#define KVBASE_MASK (0x1ffffff) + +struct machine_specific { + ulong phys_base; + ulong vmalloc_start_addr; + ulong modules_vaddr; + ulong modules_end; + ulong kernel_text_start; + ulong kernel_text_end; + ulong exception_text_start; + ulong exception_text_end; + ulonglong last_pgd_read_lpae; + ulonglong last_pmd_read_lpae; + ulonglong last_ptbl_read_lpae; + struct arm_pt_regs *crash_task_regs; + int unwind_index_prel31; +}; + +int init_unwind_tables(void); +void unwind_backtrace(struct bt_info *); +#endif /* ARM */ + +/* + * arm64.c + */ +#ifdef ARM64 +void arm64_init(int); +void arm64_dump_machdep_table(ulong); +ulong arm64_VTOP(ulong); +int arm64_IS_VMALLOC_ADDR(ulong); +ulong arm64_swp_type(ulong); +ulong arm64_swp_offset(ulong); +#endif + +/* + * alpha.c + */ +#ifdef ALPHA +void alpha_init(int); +void alpha_dump_machdep_table(ulong); +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to alpha architecture\n") + +#define HWRESET_TASK(X) ((machdep->flags & HWRESET) && is_task_active(X) && \ + (task_to_context(X)->processor == 0)) +#endif + +/* + * x86.c + */ +#ifdef X86 +void x86_init(int); +void x86_dump_machdep_table(ulong); +void x86_display_idt_table(void); +#define display_idt_table() x86_display_idt_table() +#define KSYMS_START (0x1) +void x86_dump_eframe_common(struct bt_info *bt, ulong *, int); +char *x86_function_called_by(ulong); +struct syment *x86_jmp_error_code(ulong); +struct syment *x86_text_lock_jmp(ulong, ulong *); + +struct machine_specific { + ulong *idt_table; + ulong entry_tramp_start; + ulong entry_tramp_end; + physaddr_t entry_tramp_start_phys; + ulonglong last_pmd_read_PAE; + ulonglong last_ptbl_read_PAE; + ulong page_protnone; + int max_numnodes; + ulong *remap_start_vaddr; + ulong *remap_end_vaddr; + ulong *remap_start_pfn; +}; + +struct syment *x86_is_entry_tramp_address(ulong, ulong *); +#endif + +/* + * x86_64.c + */ +#ifdef X86_64 +void x86_64_init(int); +void x86_64_dump_machdep_table(ulong); +ulong x86_64_PTOV(ulong); +ulong x86_64_VTOP(ulong); +int x86_64_IS_VMALLOC_ADDR(ulong); +ulong x86_64_swp_type(ulong); +ulong x86_64_swp_offset(ulong); +void x86_64_display_idt_table(void); +#define display_idt_table() x86_64_display_idt_table() +long x86_64_exception_frame(ulong, ulong, char *, struct bt_info *, FILE *); +#define EFRAME_INIT (0) + +struct x86_64_pt_regs_offsets { + long r15; + long r14; + long r13; + long r12; + long rbp; + long rbx; +/* arguments: non interrupts/non tracing syscalls only save upto here*/ + long r11; + long r10; + long r9; + long r8; + long rax; + long rcx; + long rdx; + long rsi; + long rdi; + long orig_rax; +/* end of arguments */ +/* cpu exception frame or undefined */ + long rip; + long cs; + long eflags; + long rsp; + long ss; +}; + +#define MAX_EXCEPTION_STACKS 7 +#define NMI_STACK (machdep->machspec->stkinfo.NMI_stack_index) + +struct x86_64_stkinfo { + ulong ebase[NR_CPUS][MAX_EXCEPTION_STACKS]; + int esize[MAX_EXCEPTION_STACKS]; + ulong ibase[NR_CPUS]; + int isize; + int NMI_stack_index; + char *exception_stacks[MAX_EXCEPTION_STACKS]; +}; + +typedef struct __attribute__((__packed__)) { + signed short sp_offset; + signed short bp_offset; + unsigned int sp_reg:4; + unsigned int bp_reg:4; + unsigned int type:2; + unsigned int end:1; +} kernel_orc_entry; + +struct ORC_data { + int module_ORC; + uint lookup_num_blocks; + ulong __start_orc_unwind_ip; + ulong __stop_orc_unwind_ip; + ulong __start_orc_unwind; + ulong __stop_orc_unwind; + ulong orc_lookup; + ulong ip_entry; + ulong orc_entry; + kernel_orc_entry kernel_orc_entry; +}; + +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_IRET 2 +#define UNWIND_HINT_TYPE_SAVE 3 +#define UNWIND_HINT_TYPE_RESTORE 4 + +#define ORC_REG_UNDEFINED 0 +#define ORC_REG_PREV_SP 1 +#define ORC_REG_DX 2 +#define ORC_REG_DI 3 +#define ORC_REG_BP 4 +#define ORC_REG_SP 5 +#define ORC_REG_R10 6 +#define ORC_REG_R13 7 +#define ORC_REG_BP_INDIRECT 8 +#define ORC_REG_SP_INDIRECT 9 +#define ORC_REG_MAX 15 + +struct machine_specific { + ulong userspace_top; + ulong page_offset; + ulong vmalloc_start_addr; + ulong vmalloc_end; + ulong vmemmap_vaddr; + ulong vmemmap_end; + ulong modules_vaddr; + ulong modules_end; + ulong phys_base; + char *pml4; + char *upml; + ulong last_upml_read; + ulong last_pml4_read; + char *irqstack; + ulong irq_eframe_link; + struct x86_64_pt_regs_offsets pto; + struct x86_64_stkinfo stkinfo; + ulong *current; + ulong *crash_nmi_rsp; + ulong vsyscall_page; + ulong thread_return; + ulong page_protnone; + ulong GART_start; + ulong GART_end; + ulong kernel_image_size; + ulong physical_mask_shift; + ulong pgdir_shift; + char *p4d; + ulong last_p4d_read; + struct ORC_data orc; + ulong irq_stack_gap; + ulong kpti_entry_stack; + ulong kpti_entry_stack_size; + ulong ptrs_per_pgd; + ulong cpu_entry_area_start; + ulong cpu_entry_area_end; + ulong page_offset_force; +}; + +#define KSYMS_START (0x1) +#define PT_REGS_INIT (0x2) +#define VM_ORIG (0x4) +#define VM_2_6_11 (0x8) +#define VM_XEN (0x10) +#define NO_TSS (0x20) +#define SCHED_TEXT (0x40) +#define PHYS_BASE (0x80) +#define VM_XEN_RHEL4 (0x100) +#define FRAMEPOINTER (0x200) +#define GART_REGION (0x400) +#define NESTED_NMI (0x800) +#define RANDOMIZED (0x1000) +#define VM_5LEVEL (0x2000) +#define ORC (0x4000) +#define KPTI (0x8000) +#define L1TF (0x10000) + +#define VM_FLAGS (VM_ORIG|VM_2_6_11|VM_XEN|VM_XEN_RHEL4|VM_5LEVEL) + +#define _2MB_PAGE_MASK (~((MEGABYTES(2))-1)) + +#endif + +#if defined(X86) || defined(X86_64) + +/* + * unwind_x86_32_64.c + */ +void init_unwind_table(void); +int dwarf_backtrace(struct bt_info *, int, ulong); +void dwarf_debug(struct bt_info *); +int dwarf_print_stack_entry(struct bt_info *, int); + +#endif + + +/* + * ppc64.c + */ + +/* + * This structure was copied from kernel source + * in include/asm-ppc/ptrace.h + */ +struct ppc64_pt_regs { + long gpr[32]; + long nip; + long msr; + long orig_gpr3; /* Used for restarting system calls */ + long ctr; + long link; + long xer; + long ccr; + long mq; /* 601 only (not used at present) */ + /* Used on APUS to hold IPL value. */ + long trap; /* Reason for being here */ + long dar; /* Fault registers */ + long dsisr; + long result; /* Result of a system call */ +}; + +struct ppc64_elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct ppc64_elf_prstatus { + struct ppc64_elf_siginfo pr_info; + short pr_cursig; + unsigned long pr_sigpend; + unsigned long pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + struct ppc64_pt_regs pr_reg; + int pr_fpvalid; +}; + +#ifdef PPC64 + +struct ppc64_opal { + uint64_t base; + uint64_t entry; + uint64_t size; +}; + +struct ppc64_vmemmap { + unsigned long phys; + unsigned long virt; +}; + +/* + * Used to store the HW interrupt stack. It is only for 2.4. + */ +struct machine_specific { + ulong hwintrstack[NR_CPUS]; + char *hwstackbuf; + uint hwstacksize; + + uint l4_index_size; + uint l3_index_size; + uint l2_index_size; + uint l1_index_size; + + uint ptrs_per_l4; + uint ptrs_per_l3; + uint ptrs_per_l2; + uint ptrs_per_l1; + + uint l4_shift; + uint l3_shift; + uint l2_shift; + uint l1_shift; + + uint pte_rpn_shift; + ulong pte_rpn_mask; + ulong pgd_masked_bits; + ulong pud_masked_bits; + ulong pmd_masked_bits; + + int vmemmap_cnt; + int vmemmap_psize; + ulong vmemmap_base; + struct ppc64_vmemmap *vmemmap_list; + ulong _page_pte; + ulong _page_present; + ulong _page_user; + ulong _page_rw; + ulong _page_guarded; + ulong _page_coherent; + ulong _page_no_cache; + ulong _page_writethru; + ulong _page_dirty; + ulong _page_accessed; + int (*is_kvaddr)(ulong); + int (*is_vmaddr)(ulong); + struct ppc64_opal opal; +}; + +void ppc64_init(int); +void ppc64_dump_machdep_table(ulong); +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to PowerPC architecture\n") +#define KSYMS_START (0x1) +#define VM_ORIG (0x2) +#define VMEMMAP_AWARE (0x4) +#define BOOK3E (0x8) +#define PHYS_ENTRY_L4 (0x10) +#define SWAP_ENTRY_L4 (0x20) +/* + * The flag bit for radix MMU in cpu_spec.mmu_features + * in the kernel is also 0x40. + */ +#define RADIX_MMU (0x40) +#define OPAL_FW (0x80) + +#define REGION_SHIFT (60UL) +#define REGION_ID(addr) (((unsigned long)(addr)) >> REGION_SHIFT) +#define VMEMMAP_REGION_ID (0xfUL) +#endif + +/* + * ppc.c + */ +#ifdef PPC +void ppc_init(int); +void ppc_dump_machdep_table(ulong); +void ppc_relocate_nt_prstatus_percpu(void **, uint *); +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to PowerPC architecture\n") +#define KSYMS_START (0x1) +/* This should match PPC_FEATURE_BOOKE from include/asm-powerpc/cputable.h */ +#define CPU_BOOKE (0x00008000) +#else +#define ppc_relocate_nt_prstatus_percpu(X,Y) do {} while (0) +#endif + +/* + * lkcd_fix_mem.c + */ + +struct _dump_header_asm_s; +struct _dump_header_s; +ulong get_lkcd_switch_stack(ulong); +int fix_addr_v8(struct _dump_header_asm_s *); +int lkcd_dump_init_v8_arch(struct _dump_header_s *dh); +int fix_addr_v7(int); +int get_lkcd_regs_for_cpu_arch(int cpu, ulong *eip, ulong *esp); +int lkcd_get_kernel_start_v8(ulong *addr); + +/* + * lkcd_v8.c + */ +int get_lkcd_regs_for_cpu_v8(struct bt_info *bt, ulong *eip, ulong *esp); + +/* + * ia64.c + */ +#ifdef IA64 +void ia64_init(int); +void ia64_dump_machdep_table(ulong); +void ia64_dump_line_number(ulong); +ulong ia64_get_switch_stack(ulong); +void ia64_exception_frame(ulong, struct bt_info *bt); +ulong ia64_PTOV(ulong); +ulong ia64_VTOP(ulong); +int ia64_IS_VMALLOC_ADDR(ulong); +#define display_idt_table() \ + error(FATAL, "-d option TBD on ia64 architecture\n"); +int ia64_in_init_stack(ulong addr); +int ia64_in_mca_stack_hyper(ulong addr, struct bt_info *bt); +physaddr_t ia64_xen_kdump_p2m(struct xen_kdump_data *xkd, physaddr_t pseudo); + +#define OLD_UNWIND (0x1) /* CONFIG_IA64_NEW_UNWIND not turned on */ +#define NEW_UNWIND (0x2) /* CONFIG_IA64_NEW_UNWIND turned on */ +#define NEW_UNW_V1 (0x4) +#define NEW_UNW_V2 (0x8) +#define NEW_UNW_V3 (0x10) +#define UNW_OUT_OF_SYNC (0x20) /* shared data structures out of sync */ +#define UNW_READ (0x40) /* kernel unw has been read successfully */ +#define MEM_LIMIT (0x80) +#define UNW_PTREGS (0x100) +#define UNW_R0 (0x200) + +#undef IA64_RBS_OFFSET +#undef IA64_STK_OFFSET +#define IA64_RBS_OFFSET ((SIZE(task_struct) + 15) & ~15) +#define IA64_STK_OFFSET (STACKSIZE()) + +struct machine_specific { + ulong cpu_data_address; + ulong unimpl_va_mask; + ulong unimpl_pa_mask; + long unw_tables_offset; + long unw_kernel_table_offset; + long unw_pt_regs_offsets; + int script_index; + struct unw_script *script_cache; + ulong script_cache_fills; + ulong script_cache_hits; + void *unw; + ulong mem_limit; + ulong kernel_region; + ulong kernel_start; + ulong phys_start; + ulong vmalloc_start; + char *ia64_memmap; + uint64_t efi_memmap_size; + uint64_t efi_memdesc_size; + void (*unwind_init)(void); + void (*unwind)(struct bt_info *); + void (*dump_unwind_stats)(void); + int (*unwind_debug)(ulong); + int ia64_init_stack_size; +}; + + +/* + * unwind.c + */ +void unwind_init_v1(void); +void unwind_v1(struct bt_info *); +void dump_unwind_stats_v1(void); +int unwind_debug_v1(ulong); + +void unwind_init_v2(void); +void unwind_v2(struct bt_info *); +void dump_unwind_stats_v2(void); +int unwind_debug_v2(ulong); + +void unwind_init_v3(void); +void unwind_v3(struct bt_info *); +void dump_unwind_stats_v3(void); +int unwind_debug_v3(ulong); + +#endif /* IA64 */ + +/* + * s390.c + */ +#ifdef S390 +void s390_init(int); +void s390_dump_machdep_table(ulong); +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to S390 architecture\n") +#define KSYMS_START (0x1) +#endif + +/* + * s390_dump.c + */ +int is_s390_dump(char *); +FILE* s390_dump_init(char *); +int read_s390_dumpfile(int, void *, int, ulong, physaddr_t); +int write_s390_dumpfile(int, void *, int, ulong, physaddr_t); +uint s390_page_size(void); +int s390_memory_used(void); +int s390_free_memory(void); +int s390_memory_dump(FILE *); +ulong get_s390_panic_task(void); +void get_s390_panicmsg(char *); + +/* + * s390x.c + */ +#ifdef S390X +void s390x_init(int); +void s390x_dump_machdep_table(ulong); +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to S390X architecture\n") +#define KSYMS_START (0x1) +#endif + +/* + * mips.c + */ +void mips_display_regs_from_elf_notes(int, FILE *); + +#ifdef MIPS +void mips_init(int); +void mips_dump_machdep_table(ulong); + +#define display_idt_table() \ + error(FATAL, "-d option is not applicable to MIPS architecture\n") + +struct mips_regset { + ulong regs[45]; +}; + +struct mips_pt_regs_main { + ulong regs[32]; + ulong cp0_status; + ulong hi; + ulong lo; +}; + +struct mips_pt_regs_cp0 { + ulong cp0_badvaddr; + ulong cp0_cause; + ulong cp0_epc; +}; + +#define KSYMS_START (0x1) +#define PHYS_BASE (0x2) + +#define KVBASE_MASK (0x1ffffff) + +struct machine_specific { + ulong phys_base; + ulong vmalloc_start_addr; + ulong modules_vaddr; + ulong modules_end; + + ulong _page_present; + ulong _page_read; + ulong _page_write; + ulong _page_accessed; + ulong _page_modified; + ulong _page_global; + ulong _page_valid; + ulong _page_no_read; + ulong _page_no_exec; + ulong _page_dirty; + + ulong _pfn_shift; + +#define _PAGE_PRESENT (machdep->machspec->_page_present) +#define _PAGE_READ (machdep->machspec->_page_read) +#define _PAGE_WRITE (machdep->machspec->_page_write) +#define _PAGE_ACCESSED (machdep->machspec->_page_accessed) +#define _PAGE_MODIFIED (machdep->machspec->_page_modified) +#define _PAGE_GLOBAL (machdep->machspec->_page_global) +#define _PAGE_VALID (machdep->machspec->_page_valid) +#define _PAGE_NO_READ (machdep->machspec->_page_no_read) +#define _PAGE_NO_EXEC (machdep->machspec->_page_no_exec) +#define _PAGE_DIRTY (machdep->machspec->_page_dirty) +#define _PFN_SHIFT (machdep->machspec->_pfn_shift) + + struct mips_regset *crash_task_regs; +}; +#endif /* MIPS */ + +/* + * sparc64.c + */ +#ifdef SPARC64 +void sparc64_init(int); +void sparc64_dump_machdep_table(ulong); +int sparc64_vmalloc_addr(ulong); +#define display_idt_table() \ + error(FATAL, "The -d option is not applicable to sparc64.\n") +#endif + +/* + * netdump.c + */ +int is_netdump(char *, ulong); +uint netdump_page_size(void); +int read_netdump(int, void *, int, ulong, physaddr_t); +int write_netdump(int, void *, int, ulong, physaddr_t); +int netdump_free_memory(void); +int netdump_memory_used(void); +int netdump_init(char *, FILE *); +ulong get_netdump_panic_task(void); +ulong get_netdump_switch_stack(ulong); +FILE *set_netdump_fp(FILE *); +int netdump_memory_dump(FILE *); +void get_netdump_regs(struct bt_info *, ulong *, ulong *); +int is_partial_netdump(void); +void get_netdump_regs_x86(struct bt_info *, ulong *, ulong *); +void get_netdump_regs_x86_64(struct bt_info *, ulong *, ulong *); +void dump_registers_for_elf_dumpfiles(void); +struct vmcore_data; +struct vmcore_data *get_kdump_vmcore_data(void); +int read_kdump(int, void *, int, ulong, physaddr_t); +int write_kdump(int, void *, int, ulong, physaddr_t); +int is_kdump(char *, ulong); +int kdump_init(char *, FILE *); +ulong get_kdump_panic_task(void); +uint kdump_page_size(void); +int kdump_free_memory(void); +int kdump_memory_used(void); +int kdump_memory_dump(FILE *); +void get_kdump_regs(struct bt_info *, ulong *, ulong *); +void xen_kdump_p2m_mfn(char *); +int is_sadump_xen(void); +void set_xen_phys_start(char *); +ulong xen_phys_start(void); +int xen_major_version(void); +int xen_minor_version(void); +int get_netdump_arch(void); +int exist_regs_in_elf_notes(struct task_context *); +void *get_regs_from_elf_notes(struct task_context *); +void map_cpus_to_prstatus(void); +int kdump_phys_base(ulong *); +int kdump_set_phys_base(ulong); +int arm_kdump_phys_base(ulong *); +int arm_kdump_phys_end(ulong *); +int is_proc_kcore(char *, ulong); +int proc_kcore_init(FILE *, int); +int read_proc_kcore(int, void *, int, ulong, physaddr_t); +int write_proc_kcore(int, void *, int, ulong, physaddr_t); +int kcore_memory_dump(FILE *); +void dump_registers_for_qemu_mem_dump(void); +void kdump_backup_region_init(void); +void display_regs_from_elf_notes(int, FILE *); +void display_ELF_note(int, int, void *, FILE *); +void *netdump_get_prstatus_percpu(int); +int kdump_kaslr_check(void); +void display_vmcoredd_note(void *ptr, FILE *ofp); +QEMUCPUState *kdump_get_qemucpustate(int); +void kdump_device_dump_info(FILE *); +void kdump_device_dump_extract(int, char *, FILE *); +#define PRSTATUS_NOTE (1) +#define QEMU_NOTE (2) + +/* + * ramdump.c + */ +int is_ramdump(char *pattern); +char *ramdump_to_elf(void); +void ramdump_elf_output_file(char *opt); +void ramdump_cleanup(void); +int read_ramdump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr); +void show_ramdump_files(void); +void dump_ramdump_data(void); +int is_ramdump_image(void); + +/* + * diskdump.c + */ +int is_diskdump(char *); +uint diskdump_page_size(void); +int read_diskdump(int, void *, int, ulong, physaddr_t); +int write_diskdump(int, void *, int, ulong, physaddr_t); +int diskdump_free_memory(void); +int diskdump_memory_used(void); +int diskdump_init(char *, FILE *); +ulong get_diskdump_panic_task(void); +ulong get_diskdump_switch_stack(ulong); +int diskdump_memory_dump(FILE *); +FILE *set_diskdump_fp(FILE *); +void get_diskdump_regs(struct bt_info *, ulong *, ulong *); +int diskdump_phys_base(unsigned long *); +int diskdump_set_phys_base(unsigned long); +extern ulong *diskdump_flags; +int is_partial_diskdump(void); +int get_dump_level(void); +int dumpfile_is_split(void); +void show_split_dumpfiles(void); +void x86_process_elf_notes(void *, unsigned long); +void *diskdump_get_prstatus_percpu(int); +void map_cpus_to_prstatus_kdump_cmprs(void); +void diskdump_display_regs(int, FILE *); +void process_elf32_notes(void *, ulong); +void process_elf64_notes(void *, ulong); +void dump_registers_for_compressed_kdump(void); +int diskdump_kaslr_check(void); +QEMUCPUState *diskdump_get_qemucpustate(int); +void diskdump_device_dump_info(FILE *); +void diskdump_device_dump_extract(int, char *, FILE *); + +/* + * makedumpfile.c + */ +void check_flattened_format(char *file); +int is_flattened_format(char *file); +int read_flattened_format(int fd, off_t offset, void *buf, size_t size); +void dump_flat_header(FILE *); + +/* + * xendump.c + */ +int is_xendump(char *); +int read_xendump(int, void *, int, ulong, physaddr_t); +int write_xendump(int, void *, int, ulong, physaddr_t); +uint xendump_page_size(void); +int xendump_free_memory(void); +int xendump_memory_used(void); +int xendump_init(char *, FILE *); +int xendump_memory_dump(FILE *); +ulong get_xendump_panic_task(void); +void get_xendump_regs(struct bt_info *, ulong *, ulong *); +char *xc_core_mfn_to_page(ulong, char *); +int xc_core_mfn_to_page_index(ulong); +void xendump_panic_hook(char *); +int read_xendump_hyper(int, void *, int, ulong, physaddr_t); +struct xendump_data *get_xendump_data(void); + +/* + * kvmdump.c + */ +int is_kvmdump(char *); +int is_kvmdump_mapfile(char *); +int kvmdump_init(char *, FILE *); +int read_kvmdump(int, void *, int, ulong, physaddr_t); +int write_kvmdump(int, void *, int, ulong, physaddr_t); +int kvmdump_free_memory(void); +int kvmdump_memory_used(void); +int kvmdump_memory_dump(FILE *); +void get_kvmdump_regs(struct bt_info *, ulong *, ulong *); +ulong get_kvmdump_panic_task(void); +int kvmdump_phys_base(unsigned long *); +void kvmdump_display_regs(int, FILE *); +void set_kvmhost_type(char *); +void set_kvm_iohole(char *); +struct kvm_register_set { + union { + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; + uint64_t ip; + uint64_t flags; + uint64_t regs[16]; + } x86; +}; +int get_kvm_register_set(int, struct kvm_register_set *); + +/* + * sadump.c + */ +int is_sadump(char *); +uint sadump_page_size(void); +int read_sadump(int, void *, int, ulong, physaddr_t); +int write_sadump(int, void *, int, ulong, physaddr_t); +int sadump_init(char *, FILE *); +int sadump_is_diskset(void); +ulong get_sadump_panic_task(void); +ulong get_sadump_switch_stack(ulong); +int sadump_memory_used(void); +int sadump_free_memory(void); +int sadump_memory_dump(FILE *); +FILE *set_sadump_fp(FILE *); +void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); +void sadump_display_regs(int, FILE *); +int sadump_phys_base(ulong *); +int sadump_set_phys_base(ulong); +void sadump_show_diskset(void); +int sadump_is_zero_excluded(void); +void sadump_set_zero_excluded(void); +void sadump_unset_zero_excluded(void); +struct sadump_data; +struct sadump_data *get_sadump_data(void); +int sadump_calc_kaslr_offset(ulong *); +int sadump_get_cr3_idtr(ulong *, ulong *); + +/* + * qemu.c + */ +int qemu_init(char *); + +/* + * qemu-load.c + */ +int is_qemu_vm_file(char *); +void dump_qemu_header(FILE *); + +/* + * net.c + */ +void net_init(void); +void dump_net_table(void); +void dump_sockets_workhorse(ulong, ulong, struct reference *); + +/* + * remote.c + */ +int is_remote_daemon(char *); +physaddr_t get_remote_phys_base(physaddr_t, physaddr_t); +physaddr_t remote_vtop(int, physaddr_t); +int get_remote_regs(struct bt_info *, ulong *, ulong *); +physaddr_t get_remote_cr3(int); +void remote_fd_init(void); +int get_remote_file(struct remote_file *); +uint remote_page_size(void); +int find_remote_module_objfile(struct load_module *lm, char *, char *); +int remote_free_memory(void); +int remote_memory_dump(int); +int remote_memory_used(void); +void remote_exit(void); +int remote_execute(void); +void remote_clear_pipeline(void); +int remote_memory_read(int, char *, int, physaddr_t, int); + +/* + * vmware_vmss.c + */ +int is_vmware_vmss(char *filename); +int vmware_vmss_init(char *filename, FILE *ofp); +uint vmware_vmss_page_size(void); +int read_vmware_vmss(int, void *, int, ulong, physaddr_t); +int write_vmware_vmss(int, void *, int, ulong, physaddr_t); +void vmware_vmss_display_regs(int, FILE *); +void get_vmware_vmss_regs(struct bt_info *, ulong *, ulong *); +int vmware_vmss_memory_dump(FILE *); +void dump_registers_for_vmss_dump(void); +int vmware_vmss_valid_regs(struct bt_info *); +int vmware_vmss_get_cr3_idtr(ulong *, ulong *); +int vmware_vmss_phys_base(ulong *phys_base); +int vmware_vmss_set_phys_base(ulong); + +/* + * kaslr_helper.c + */ +int calc_kaslr_offset(ulong *, ulong *); + +/* + * gnu_binutils.c + */ + +/* NO LONGER IN USE */ + +/* + * test.c + */ +void cmd_template(void); +void foreach_test(ulong, ulong); + +/* + * va_server.c + */ +int mclx_page_size(void); +int vas_memory_used(void); +int vas_memory_dump(FILE *); +int vas_free_memory(char *); +void set_vas_debug(ulong); +size_t vas_write(void *, size_t); +int va_server_init(char *, ulong *, ulong *, ulong *); +size_t vas_read(void *, size_t); +int vas_lseek(ulong, int); + +/* + * lkcd_x86_trace.c + */ +int lkcd_x86_back_trace(struct bt_info *, int, FILE *); + +/* + * lkcd_common.c + */ +int lkcd_dump_init(FILE *, int, char *); +ulong get_lkcd_panic_task(void); +void get_lkcd_panicmsg(char *); +int is_lkcd_compressed_dump(char *); +void dump_lkcd_environment(ulong); +int lkcd_lseek(physaddr_t); +long lkcd_read(void *, long); +void set_lkcd_debug(ulong); +FILE *set_lkcd_fp(FILE *); +uint lkcd_page_size(void); +int lkcd_memory_used(void); +int lkcd_memory_dump(FILE *); +int lkcd_free_memory(void); +void lkcd_print(char *, ...); +void set_remote_lkcd_panic_data(ulong, char *); +void set_lkcd_nohash(void); +int lkcd_load_dump_page_header(void *, ulong); +void lkcd_dumpfile_complaint(uint32_t, uint32_t, int); +int set_mb_benchmark(ulong); +ulonglong fix_lkcd_address(ulonglong); +int lkcd_get_kernel_start(ulong *addr); +int get_lkcd_regs_for_cpu(struct bt_info *bt, ulong *eip, ulong *esp); + +/* + * lkcd_v1.c + */ +int lkcd_dump_init_v1(FILE *, int); +void dump_dump_page_v1(char *, void *); +void dump_lkcd_environment_v1(ulong); +uint32_t get_dp_size_v1(void); +uint32_t get_dp_flags_v1(void); +uint64_t get_dp_address_v1(void); + +/* + * lkcd_v2_v3.c + */ +int lkcd_dump_init_v2_v3(FILE *, int); +void dump_dump_page_v2_v3(char *, void *); +void dump_lkcd_environment_v2_v3(ulong); +uint32_t get_dp_size_v2_v3(void); +uint32_t get_dp_flags_v2_v3(void); +uint64_t get_dp_address_v2_v3(void); + +/* + * lkcd_v5.c + */ +int lkcd_dump_init_v5(FILE *, int); +void dump_dump_page_v5(char *, void *); +void dump_lkcd_environment_v5(ulong); +uint32_t get_dp_size_v5(void); +uint32_t get_dp_flags_v5(void); +uint64_t get_dp_address_v5(void); + +/* + * lkcd_v7.c + */ +int lkcd_dump_init_v7(FILE *, int, char *); +void dump_dump_page_v7(char *, void *); +void dump_lkcd_environment_v7(ulong); +uint32_t get_dp_size_v7(void); +uint32_t get_dp_flags_v7(void); +uint64_t get_dp_address_v7(void); + +/* + * lkcd_v8.c + */ +int lkcd_dump_init_v8(FILE *, int, char *); +void dump_dump_page_v8(char *, void *); +void dump_lkcd_environment_v8(ulong); +uint32_t get_dp_size_v8(void); +uint32_t get_dp_flags_v8(void); +uint64_t get_dp_address_v8(void); + +#ifdef LKCD_COMMON +/* + * Until they differ across versions, these remain usable in the common + * routines in lkcd_common.c + */ +#define LKCD_DUMP_MAGIC_NUMBER (0xa8190173618f23edULL) +#define LKCD_DUMP_MAGIC_LIVE (0xa8190173618f23cdULL) + +#define LKCD_DUMP_V1 (0x1) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V2 (0x2) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V3 (0x3) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V5 (0x5) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V6 (0x6) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V7 (0x7) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V8 (0x8) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V9 (0x9) /* DUMP_VERSION_NUMBER */ +#define LKCD_DUMP_V10 (0xa) /* DUMP_VERSION_NUMBER */ + +#define LKCD_DUMP_VERSION_NUMBER_MASK (0xf) +#define LKCD_DUMP_RAW (0x1) /* DUMP_[DH_]RAW */ +#define LKCD_DUMP_COMPRESSED (0x2) /* DUMP_[DH_]COMPRESSED */ +#define LKCD_DUMP_END (0x4) /* DUMP_[DH_]END */ + +#define LKCD_DUMP_COMPRESS_NONE (0x0) /* DUMP_COMPRESS_NONE */ +#define LKCD_DUMP_COMPRESS_RLE (0x1) /* DUMP_COMPRESS_RLE */ +#define LKCD_DUMP_COMPRESS_GZIP (0x2) /* DUMP_COMPRESS_GZIP */ + +#define LKCD_DUMP_MCLX_V0 (0x80000000) /* MCLX mod of LKCD */ +#define LKCD_DUMP_MCLX_V1 (0x40000000) /* Extra page header data */ +#define LKCD_OFFSET_TO_FIRST_PAGE (65536) + +#define MCLX_PAGE_HEADERS (4096) +#define MCLX_V1_PAGE_HEADER_CACHE ((sizeof(uint64_t)) * MCLX_PAGE_HEADERS) + +/* + * lkcd_load_dump_page_header() return values + */ +#define LKCD_DUMPFILE_OK (0) +#define LKCD_DUMPFILE_EOF (1) +#define LKCD_DUMPFILE_END (2) + +/* + * Common handling of LKCD dump environment + */ +#define LKCD_CACHED_PAGES (16) +#define LKCD_PAGE_HASH (32) +#define LKCD_DUMP_HEADER_ONLY (1) /* arguments to lkcd_dump_environment */ +#define LKCD_DUMP_PAGE_ONLY (2) + +#define LKCD_VALID (0x1) /* flags */ +#define LKCD_REMOTE (0x2) +#define LKCD_NOHASH (0x4) +#define LKCD_MCLX (0x8) +#define LKCD_BAD_DUMP (0x10) + +struct page_hash_entry { + uint32_t pg_flags; + uint64_t pg_addr; + off_t pg_hdr_offset; + struct page_hash_entry *next; +}; + +struct page_desc { + off_t offset; /* lseek offset in dump file */ +}; + +struct physmem_zone { + uint64_t start; + struct page_desc *pages; +}; + +struct fix_addrs { + ulong task; + ulong saddr; + ulong sw; +}; + + +struct lkcd_environment { + int fd; /* dumpfile file descriptor */ + ulong flags; /* flags from above */ + ulong debug; /* shadow of pc->debug */ + FILE *fp; /* abstracted fp for fprintf */ + void *dump_header; /* header stash, v1 or v2 */ + void *dump_header_asm; /* architecture specific header for v2 */ + void *dump_header_asm_smp; /* architecture specific header for v7 & v8 */ + void *dump_page; /* current page header holder */ + uint32_t version; /* version number of this dump */ + uint32_t page_size; /* size of a Linux memory page */ + int page_shift; /* byte address to page */ + int bits; /* processor bitsize */ + ulong panic_task; /* panic task address */ + char *panic_string; /* pointer to stashed panic string */ + uint32_t compression; /* compression type */ + uint32_t (*get_dp_size)(void); /* returns current page's dp_size */ + uint32_t (*get_dp_flags)(void); /* returns current page's dp_size */ + uint64_t (*get_dp_address)(void); /* returns current page's dp_address*/ + size_t page_header_size; /* size of version's page header */ + unsigned long curpos; /* offset into current page */ + uint64_t curpaddr; /* current page's physical address */ + off_t curhdroffs; /* current page's header offset */ + char *curbufptr; /* pointer to uncompressed page buffer */ + uint64_t kvbase; /* physical-to-LKCD page address format*/ + char *page_cache_buf; /* base of cached buffer pages */ + char *compressed_page; /* copy of compressed page data */ + int evict_index; /* next page to evict */ + ulong evictions; /* total evictions done */ + struct page_cache_hdr { /* header for each cached page */ + uint32_t pg_flags; + uint64_t pg_addr; + char *pg_bufptr; + ulong pg_hit_count; + } page_cache_hdr[LKCD_CACHED_PAGES]; + struct page_hash_entry *page_hash; + ulong total_pages; + ulong benchmark_pages; + ulong benchmarks_done; + off_t *mb_hdr_offsets; + ulong total_reads; + ulong cached_reads; + ulong hashed_reads; + ulong hashed; + ulong compressed; + ulong raw; + + /* lkcd_v7 additions */ + char *dumpfile_index; /* array of offsets for each page */ + int ifd; /* index file for dump (LKCD V7+) */ + long memory_pages; /* Mamimum index of dump pages */ + off_t page_offset_max; /* Offset of page with greatest offset seen so far */ + long page_index_max; /* Index of page with greatest offset seen so far */ + off_t *page_offsets; /* Pointer to huge array with seek offsets */ + /* NB: There are no holes in the array */ + + struct physmem_zone *zones; /* Array of physical memory zones */ + int num_zones; /* Number of zones initialized */ + int max_zones; /* Size of the zones array */ + long zoned_offsets; /* Number of stored page offsets */ + uint64_t zone_mask; + int zone_shift; + + int fix_addr_num; /* Number of active stacks to switch to saved values */ + struct fix_addrs *fix_addr; /* Array of active stacks to switch to saved values */ + + +}; + +#define ZONE_ALLOC 128 +#define ZONE_SIZE (MEGABYTES(512)) + +#define MEGABYTE_ALIGNED(vaddr) (!((uint64_t)(vaddr) & MEGABYTE_MASK)) + +#define LKCD_PAGE_HASH_INDEX(paddr) \ + (((paddr) >> lkcd->page_shift) % LKCD_PAGE_HASH) +#define LKCD_PAGES_PER_MEGABYTE() (MEGABYTES(1) / lkcd->page_size) +#define LKCD_PAGE_MEGABYTE(page) ((page) / LKCD_PAGES_PER_MEGABYTE()) +#define LKCD_BENCHMARKS_DONE() (lkcd->benchmarks_done >= lkcd->benchmark_pages) +#define LKCD_VALID_PAGE(flags) ((flags) & LKCD_VALID) + +extern struct lkcd_environment *lkcd; + +#define LKCD_DEBUG(x) (lkcd->debug >= (x)) +#undef BITS +#undef BITS32 +#undef BITS64 +#define BITS() (lkcd->bits) +#define BITS32() (lkcd->bits == 32) +#define BITS64() (lkcd->bits == 64) + +#endif /* LKCD_COMMON */ + +/* + * gdb_interface.c + */ +void gdb_main_loop(int, char **); +void display_gdb_banner(void); +void get_gdb_version(void); +void gdb_session_init(void); +void gdb_interface(struct gnu_request *); +int gdb_pass_through(char *, FILE *, ulong); +int gdb_readmem_callback(ulong, void *, int, int); +int gdb_line_number_callback(ulong, ulong, ulong); +int gdb_print_callback(ulong); +void gdb_error_hook(void); +void restore_gdb_sanity(void); +int is_gdb_command(int, ulong); +char *gdb_command_string(int, char *, int); +void dump_gnu_request(struct gnu_request *, int); +int gdb_CRASHDEBUG(ulong); +void dump_gdb_data(void); +void update_gdb_hooks(void); +void gdb_readnow_warning(void); +int gdb_set_crash_scope(ulong, char *); +extern int *gdb_output_format; +extern unsigned int *gdb_print_max; +extern int *gdb_prettyprint_structs; +extern int *gdb_prettyprint_arrays; +extern int *gdb_repeat_count_threshold; +extern int *gdb_stop_print_at_null; +extern unsigned int *gdb_output_radix; + +/* + * gdb/top.c + */ +extern void execute_command (char *, int); +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) +extern void (*command_loop_hook)(void); +extern void (*error_hook)(void); +#else +extern void (*deprecated_command_loop_hook)(void); + +/* + * gdb/exceptions.c + */ +extern void (*error_hook)(void); +#endif + +/* + * gdb/symtab.c + */ +extern void gdb_command_funnel(struct gnu_request *); + +/* + * gdb/symfile.c + */ +#if defined(GDB_6_0) || defined(GDB_6_1) +struct objfile; +extern void (*target_new_objfile_hook)(struct objfile *); +#endif + +/* + * gdb/valprint.c + */ +extern unsigned output_radix; +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) +extern int output_format; +extern int prettyprint_structs; +extern int prettyprint_arrays; +extern int repeat_count_threshold; +extern unsigned int print_max; +extern int stop_print_at_null; +#endif + +#ifdef GDB_7_6 +/* + * gdb/cleanups.c + */ +struct cleanup; +extern struct cleanup *all_cleanups(void); +extern void do_cleanups(struct cleanup *); +#else +/* + * gdb/utils.c + */ +extern void do_cleanups(void *); +#endif + +/* + * gdb/version.c + */ +extern char *version; + +/* + * gdb/disasm.c + */ +#ifdef GDB_5_3 +extern int gdb_disassemble_from_exec; +#endif + +/* + * readline/readline.c + */ +#ifdef GDB_5_3 +extern char *readline(char *); +#else +extern char *readline(const char *); +#endif +extern int rl_editing_mode; + +/* + * readline/history.c + */ +extern int history_offset; + +/* + * external gdb routines + */ +extern int gdb_main_entry(int, char **); +#ifdef GDB_5_3 +extern unsigned long calc_crc32(unsigned long, unsigned char *, size_t); +#else +extern unsigned long gnu_debuglink_crc32 (unsigned long, unsigned char *, size_t); +#endif +extern int have_partial_symbols(void); +extern int have_full_symbols(void); + +#if defined(X86) || defined(X86_64) || defined(IA64) +#define XEN_HYPERVISOR_ARCH +#endif + +#endif /* !GDB_COMMON */ diff --git a/kaslr_helper.c b/kaslr_helper.c index fe5909c..bb19e54 100644 --- a/kaslr_helper.c +++ b/kaslr_helper.c @@ -394,10 +394,11 @@ quit: #define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) #define CR3_PCID_MASK 0xFFFull int -calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) +calc_kaslr_offset(ulong *ko, ulong *pb) { uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr; ulong divide_error_vmcore; + ulong kaslr_offset, phys_base; ulong kaslr_offset_kdump, phys_base_kdump; int ret = FALSE; int verbose = CRASHDEBUG(1)? 1: 0; @@ -405,6 +406,7 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (!machine_type("X86_64")) return FALSE; +retry: if (SADUMP_DUMPFILE()) { if (!sadump_get_cr3_idtr(&cr3, &idtr)) return FALSE; @@ -436,18 +438,48 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) machdep->machspec->pgdir_shift = PGDIR_SHIFT; machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD; if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(), - "pgd", RETURN_ON_ERROR)) - goto quit; + "pgd", RETURN_ON_ERROR)) { + if (SADUMP_DUMPFILE()) + goto retry; + else + goto quit; + } /* Convert virtual address of IDT table to physical address */ - if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) - goto quit; + if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) { + if (SADUMP_DUMPFILE()) + goto retry; + else + goto quit; + } /* Now we can calculate kaslr_offset and phys_base */ divide_error_vmcore = get_vec0_addr(idtr_paddr); - *kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux; - *phys_base = idtr_paddr - - (st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map); + kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux; + phys_base = idtr_paddr - + (st->idt_table_vmlinux + kaslr_offset - __START_KERNEL_map); + + if (SADUMP_DUMPFILE()) { + char buf[sizeof("Linux version")]; + ulong linux_banner_paddr; + + if (!kvtop(NULL, + st->linux_banner_vmlinux + kaslr_offset, + &linux_banner_paddr, + verbose)) + goto retry; + + if (!readmem(linux_banner_paddr, + PHYSADDR, + buf, + sizeof(buf), + "linux_banner", + RETURN_ON_ERROR)) + goto retry; + + if (!STRNEQ(buf, "Linux version")) + goto retry; + } if (CRASHDEBUG(1)) { fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr); @@ -465,9 +497,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) * from vmcoreinfo */ if (get_kaslr_offset_from_vmcoreinfo( - *kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) { - *kaslr_offset = kaslr_offset_kdump; - *phys_base = phys_base_kdump; + kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) { + kaslr_offset = kaslr_offset_kdump; + phys_base = phys_base_kdump; } else if (CRASHDEBUG(1)) { fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n"); fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n"); @@ -475,10 +507,13 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (CRASHDEBUG(1)) { fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n", - *kaslr_offset); - fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", *phys_base); + kaslr_offset); + fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", phys_base); } + *ko = kaslr_offset; + *pb = phys_base; + ret = TRUE; quit: vt->kernel_pgd[0] = 0; diff --git a/kaslr_helper.cgithub_b97e7fd4e826_to_8b50d94ada21.patch b/kaslr_helper.cgithub_b97e7fd4e826_to_8b50d94ada21.patch new file mode 100644 index 0000000..fe5909c --- /dev/null +++ b/kaslr_helper.cgithub_b97e7fd4e826_to_8b50d94ada21.patch @@ -0,0 +1,494 @@ +/* + * kaslr_helper - helper for kaslr offset calculation + * + * Copyright (c) 2011 FUJITSU LIMITED + * Copyright (c) 2018 Red Hat Inc. + * + * 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. + * + * Authors: HATAYAMA Daisuke + * INDOH Takao + * Sergio Lopez + */ + +#include "defs.h" +#include +#include + +#ifdef X86_64 +/* + * Get address of vector0 interrupt handler (Devide Error) from Interrupt + * Descriptor Table. + */ +static ulong +get_vec0_addr(ulong idtr) +{ + struct gate_struct64 { + uint16_t offset_low; + uint16_t segment; + uint32_t ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1; + uint16_t offset_middle; + uint32_t offset_high; + uint32_t zero1; + } __attribute__((packed)) gate; + + readmem(idtr, PHYSADDR, &gate, sizeof(gate), "idt_table", FAULT_ON_ERROR); + + return ((ulong)gate.offset_high << 32) + + ((ulong)gate.offset_middle << 16) + + gate.offset_low; +} + +/* + * Parse a string of [size[KMG] ]offset[KMG] + * Import from Linux kernel(lib/cmdline.c) + */ +static ulong +memparse(char *ptr, char **retptr) +{ + char *endptr; + + unsigned long long ret = strtoull(ptr, &endptr, 0); + + switch (*endptr) { + case 'E': + case 'e': + ret <<= 10; + case 'P': + case 'p': + ret <<= 10; + case 'T': + case 't': + ret <<= 10; + case 'G': + case 'g': + ret <<= 10; + case 'M': + case 'm': + ret <<= 10; + case 'K': + case 'k': + ret <<= 10; + endptr++; + default: + break; + } + + if (retptr) + *retptr = endptr; + + return ret; +} + +/* + * Find "elfcorehdr=" in the boot parameter of kernel and return the address + * of elfcorehdr. + */ +static ulong +get_elfcorehdr(ulong kaslr_offset) +{ + char cmdline[BUFSIZE], *ptr; + ulong cmdline_vaddr; + ulong cmdline_paddr; + ulong buf_vaddr, buf_paddr; + char *end; + ulong elfcorehdr_addr = 0, elfcorehdr_size = 0; + int verbose = CRASHDEBUG(1)? 1: 0; + + cmdline_vaddr = st->saved_command_line_vmlinux + kaslr_offset; + if (!kvtop(NULL, cmdline_vaddr, &cmdline_paddr, verbose)) + return 0; + + if (CRASHDEBUG(1)) { + fprintf(fp, "cmdline vaddr=%lx\n", cmdline_vaddr); + fprintf(fp, "cmdline paddr=%lx\n", cmdline_paddr); + } + + if (!readmem(cmdline_paddr, PHYSADDR, &buf_vaddr, sizeof(ulong), + "saved_command_line", RETURN_ON_ERROR)) + return 0; + + if (!kvtop(NULL, buf_vaddr, &buf_paddr, verbose)) + return 0; + + if (CRASHDEBUG(1)) { + fprintf(fp, "cmdline buffer vaddr=%lx\n", buf_vaddr); + fprintf(fp, "cmdline buffer paddr=%lx\n", buf_paddr); + } + + memset(cmdline, 0, BUFSIZE); + if (!readmem(buf_paddr, PHYSADDR, cmdline, BUFSIZE, + "saved_command_line", RETURN_ON_ERROR)) + return 0; + + ptr = strstr(cmdline, "elfcorehdr="); + if (!ptr) + return 0; + + if (CRASHDEBUG(1)) + fprintf(fp, "2nd kernel detected\n"); + + ptr += strlen("elfcorehdr="); + elfcorehdr_addr = memparse(ptr, &end); + if (*end == '@') { + elfcorehdr_size = elfcorehdr_addr; + elfcorehdr_addr = memparse(end + 1, &end); + } + + if (CRASHDEBUG(1)) { + fprintf(fp, "elfcorehdr_addr=%lx\n", elfcorehdr_addr); + fprintf(fp, "elfcorehdr_size=%lx\n", elfcorehdr_size); + } + + return elfcorehdr_addr; +} + + /* + * Get vmcoreinfo from elfcorehdr. + * Some codes are imported from Linux kernel(fs/proc/vmcore.c) + */ +static int +get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len) +{ + unsigned char e_ident[EI_NIDENT]; + Elf64_Ehdr ehdr; + Elf64_Phdr phdr; + Elf64_Nhdr nhdr; + ulong ptr; + ulong nhdr_offset = 0; + int i; + + if (!readmem(elfcorehdr, PHYSADDR, e_ident, EI_NIDENT, + "EI_NIDENT", RETURN_ON_ERROR)) + return FALSE; + + if (e_ident[EI_CLASS] != ELFCLASS64) { + error(INFO, "Only ELFCLASS64 is supportd\n"); + return FALSE; + } + + if (!readmem(elfcorehdr, PHYSADDR, &ehdr, sizeof(ehdr), + "Elf64_Ehdr", RETURN_ON_ERROR)) + return FALSE; + + /* Sanity Check */ + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || + (ehdr.e_type != ET_CORE) || + ehdr.e_ident[EI_CLASS] != ELFCLASS64 || + ehdr.e_ident[EI_VERSION] != EV_CURRENT || + ehdr.e_version != EV_CURRENT || + ehdr.e_ehsize != sizeof(Elf64_Ehdr) || + ehdr.e_phentsize != sizeof(Elf64_Phdr) || + ehdr.e_phnum == 0) { + error(INFO, "Invalid elf header\n"); + return FALSE; + } + + ptr = elfcorehdr + ehdr.e_phoff; + for (i = 0; i < ehdr.e_phnum; i++) { + ulong offset; + char name[16]; + + if (!readmem(ptr, PHYSADDR, &phdr, sizeof(phdr), + "Elf64_Phdr", RETURN_ON_ERROR)) + return FALSE; + + ptr += sizeof(phdr); + if (phdr.p_type != PT_NOTE) + continue; + + offset = phdr.p_offset; + if (!readmem(offset, PHYSADDR, &nhdr, sizeof(nhdr), + "Elf64_Nhdr", RETURN_ON_ERROR)) + return FALSE; + + offset += DIV_ROUND_UP(sizeof(Elf64_Nhdr), sizeof(Elf64_Word))* + sizeof(Elf64_Word); + memset(name, 0, sizeof(name)); + if (!readmem(offset, PHYSADDR, name, sizeof(name), + "Elf64_Nhdr name", RETURN_ON_ERROR)) + return FALSE; + + if(!strcmp(name, "VMCOREINFO")) { + nhdr_offset = offset; + break; + } + } + + if (!nhdr_offset) + return FALSE; + + *addr = nhdr_offset + + DIV_ROUND_UP(nhdr.n_namesz, sizeof(Elf64_Word))* + sizeof(Elf64_Word); + *len = nhdr.n_descsz; + + if (CRASHDEBUG(1)) { + fprintf(fp, "vmcoreinfo addr=%lx\n", *addr); + fprintf(fp, "vmcoreinfo len=%d\n", *len); + } + + return TRUE; +} + +static int +qemu_get_cr3_idtr(ulong *cr3, ulong *idtr) +{ + QEMUCPUState *cpustat; + + if (DISKDUMP_DUMPFILE()) { + cpustat = diskdump_get_qemucpustate(0); + } else if (KDUMP_DUMPFILE()) { + cpustat = kdump_get_qemucpustate(0); + } else { + return FALSE; + } + + if (!cpustat) { + return FALSE; + } + + *cr3 = cpustat->cr[3]; + *idtr = cpustat->idt.base; + + return TRUE; +} + +/* + * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd kernel. + * If we are in 2nd kernel, get kaslr_offset/phys_base from vmcoreinfo. + * + * 1. Get command line and try to retrieve "elfcorehdr=" boot parameter + * 2. If "elfcorehdr=" is not found in command line, we are in 1st kernel. + * There is nothing to do. + * 3. If "elfcorehdr=" is found, we are in 2nd kernel. Find vmcoreinfo + * using "elfcorehdr=" and retrieve kaslr_offset/phys_base from vmcoreinfo. + */ +static int +get_kaslr_offset_from_vmcoreinfo(ulong orig_kaslr_offset, + ulong *kaslr_offset, ulong *phys_base) +{ + ulong elfcorehdr_addr = 0; + ulong vmcoreinfo_addr; + int vmcoreinfo_len; + char *buf, *pos; + int ret = FALSE; + + /* Find "elfcorehdr=" in the kernel boot parameter */ + elfcorehdr_addr = get_elfcorehdr(orig_kaslr_offset); + if (!elfcorehdr_addr) + return FALSE; + + /* Get vmcoreinfo from the address of "elfcorehdr=" */ + if (!get_vmcoreinfo(elfcorehdr_addr, &vmcoreinfo_addr, &vmcoreinfo_len)) + return FALSE; + + if (!vmcoreinfo_len) + return FALSE; + + if (CRASHDEBUG(1)) + fprintf(fp, "Find vmcoreinfo in kdump memory\n"); + + buf = GETBUF(vmcoreinfo_len); + if (!readmem(vmcoreinfo_addr, PHYSADDR, buf, vmcoreinfo_len, + "vmcoreinfo", RETURN_ON_ERROR)) + goto quit; + + /* Get phys_base form vmcoreinfo */ + pos = strstr(buf, "NUMBER(phys_base)="); + if (!pos) + goto quit; + *phys_base = strtoull(pos + strlen("NUMBER(phys_base)="), NULL, 0); + + /* Get kaslr_offset form vmcoreinfo */ + pos = strstr(buf, "KERNELOFFSET="); + if (!pos) + goto quit; + *kaslr_offset = strtoull(pos + strlen("KERNELOFFSET="), NULL, 16); + + ret = TRUE; + +quit: + FREEBUF(buf); + return ret; +} + +/* + * Calculate kaslr_offset and phys_base + * + * kaslr_offset: + * The difference between original address in System.map or vmlinux and + * actual address placed randomly by kaslr feature. To be more accurate, + * kaslr_offset = actual address - original address + * + * phys_base: + * Physical address where the kerenel is placed. In other words, it's a + * physical address of __START_KERNEL_map. This is also decided randomly by + * kaslr. + * + * kaslr offset and phys_base are calculated as follows: + * + * kaslr_offset: + * 1) Get IDTR and CR3 value from the dump header. + * 2) Get a virtual address of IDT from IDTR value + * --- (A) + * 3) Translate (A) to physical address using CR3, the upper 52 bits + * of which points a top of page table. + * --- (B) + * 4) Get an address of vector0 (Devide Error) interrupt handler from + * IDT, which are pointed by (B). + * --- (C) + * 5) Get an address of symbol "divide_error" form vmlinux + * --- (D) + * + * Now we have two addresses: + * (C)-> Actual address of "divide_error" + * (D)-> Original address of "divide_error" in the vmlinux + * + * kaslr_offset can be calculated by the difference between these two + * value. + * + * phys_base; + * 1) Get IDT virtual address from vmlinux + * --- (E) + * + * So phys_base can be calculated using relationship of directly mapped + * address. + * + * phys_base = + * Physical address(B) - + * (Virtual address(E) + kaslr_offset - __START_KERNEL_map) + * + * Note that the address (A) cannot be used instead of (E) because (A) is + * not direct map address, it's a fixed map address. + * + * This solution works in most every case, but does not work in the + * following case. + * + * 1) If the dump is captured on early stage of kernel boot, IDTR points + * early IDT table(early_idts) instead of normal IDT(idt_table). + * 2) If the dump is captured whle kdump is working, IDTR points + * IDT table of 2nd kernel, not 1st kernel. + * + * Current implementation does not support the case 1), need + * enhancement in the future. For the case 2), get kaslr_offset and + * phys_base as follows. + * + * 1) Get kaslr_offset and phys_base using the above solution. + * 2) Get kernel boot parameter from "saved_command_line" + * 3) If "elfcorehdr=" is not included in boot parameter, we are in the + * first kernel, nothing to do any more. + * 4) If "elfcorehdr=" is included in boot parameter, we are in the 2nd + * kernel. Retrieve vmcoreinfo from address of "elfcorehdr=" and + * get kaslr_offset and phys_base from vmcoreinfo. + */ +#define PTI_USER_PGTABLE_BIT PAGE_SHIFT +#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT) +#define CR3_PCID_MASK 0xFFFull +int +calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) +{ + uint64_t cr3 = 0, idtr = 0, pgd = 0, idtr_paddr; + ulong divide_error_vmcore; + ulong kaslr_offset_kdump, phys_base_kdump; + int ret = FALSE; + int verbose = CRASHDEBUG(1)? 1: 0; + + if (!machine_type("X86_64")) + return FALSE; + + if (SADUMP_DUMPFILE()) { + if (!sadump_get_cr3_idtr(&cr3, &idtr)) + return FALSE; + } else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { + if (!qemu_get_cr3_idtr(&cr3, &idtr)) + return FALSE; + } else if (VMSS_DUMPFILE()) { + if (!vmware_vmss_get_cr3_idtr(&cr3, &idtr)) + return FALSE; + } else + return FALSE; + + if (st->pti_init_vmlinux || st->kaiser_init_vmlinux) + pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK); + else + pgd = cr3 & ~CR3_PCID_MASK; + + /* + * Set up for kvtop. + * + * calc_kaslr_offset() is called before machdep_init(PRE_GDB), so some + * variables are not initialized yet. Set up them here to call kvtop(). + * + * TODO: XEN and 5-level is not supported + */ + vt->kernel_pgd[0] = pgd; + machdep->last_pgd_read = vt->kernel_pgd[0]; + machdep->machspec->physical_mask_shift = __PHYSICAL_MASK_SHIFT_2_6; + machdep->machspec->pgdir_shift = PGDIR_SHIFT; + machdep->machspec->ptrs_per_pgd = PTRS_PER_PGD; + if (!readmem(pgd, PHYSADDR, machdep->pgd, PAGESIZE(), + "pgd", RETURN_ON_ERROR)) + goto quit; + + /* Convert virtual address of IDT table to physical address */ + if (!kvtop(NULL, idtr, &idtr_paddr, verbose)) + goto quit; + + /* Now we can calculate kaslr_offset and phys_base */ + divide_error_vmcore = get_vec0_addr(idtr_paddr); + *kaslr_offset = divide_error_vmcore - st->divide_error_vmlinux; + *phys_base = idtr_paddr - + (st->idt_table_vmlinux + *kaslr_offset - __START_KERNEL_map); + + if (CRASHDEBUG(1)) { + fprintf(fp, "calc_kaslr_offset: idtr=%lx\n", idtr); + fprintf(fp, "calc_kaslr_offset: pgd=%lx\n", pgd); + fprintf(fp, "calc_kaslr_offset: idtr(phys)=%lx\n", idtr_paddr); + fprintf(fp, "calc_kaslr_offset: divide_error(vmlinux): %lx\n", + st->divide_error_vmlinux); + fprintf(fp, "calc_kaslr_offset: divide_error(vmcore): %lx\n", + divide_error_vmcore); + } + + /* + * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd + * kernel. If we are in 2nd kernel, get kaslr_offset/phys_base + * from vmcoreinfo + */ + if (get_kaslr_offset_from_vmcoreinfo( + *kaslr_offset, &kaslr_offset_kdump, &phys_base_kdump)) { + *kaslr_offset = kaslr_offset_kdump; + *phys_base = phys_base_kdump; + } else if (CRASHDEBUG(1)) { + fprintf(fp, "kaslr_helper: failed to determine which kernel was running at crash,\n"); + fprintf(fp, "kaslr_helper: asssuming the kdump 1st kernel.\n"); + } + + if (CRASHDEBUG(1)) { + fprintf(fp, "calc_kaslr_offset: kaslr_offset=%lx\n", + *kaslr_offset); + fprintf(fp, "calc_kaslr_offset: phys_base=%lx\n", *phys_base); + } + + ret = TRUE; +quit: + vt->kernel_pgd[0] = 0; + machdep->last_pgd_read = 0; + return ret; +} +#else +int +calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_page) +{ + return FALSE; +} +#endif /* X86_64 */ diff --git a/sadump.c b/sadump.c index 35f7cf0..009e17a 100644 --- a/sadump.c +++ b/sadump.c @@ -1664,29 +1664,32 @@ get_sadump_data(void) static int get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram) { - ulong offset; - struct sadump_header *sh = sd->dump_header; - int apicid; - struct sadump_smram_cpu_state scs, zero; - - offset = sd->sub_hdr_offset + sizeof(uint32_t) + - sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); - - memset(&zero, 0, sizeof(zero)); - - for (apicid = 0; apicid < sh->nr_cpus; ++apicid) { - if (!read_device(&scs, sizeof(scs), &offset)) { - error(INFO, "sadump: cannot read sub header " - "cpu_state\n"); - return FALSE; - } - if (memcmp(&scs, &zero, sizeof(scs)) != 0) { - *smram = scs; - return TRUE; - } - } - - return FALSE; + ulong offset; + struct sadump_header *sh = sd->dump_header; + static int apicid; + struct sadump_smram_cpu_state scs; + + if (apicid >= sh->nr_cpus) + return FALSE; + + offset = sd->sub_hdr_offset + sizeof(uint32_t) + + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state) + + apicid * sizeof(scs); + + while (apicid < sh->nr_cpus) { + apicid++; + if (!read_device(&scs, sizeof(scs), &offset)) { + error(INFO, "sadump: cannot read sub header " + "cpu_state\n"); + return FALSE; + } + if (scs.Cr3 && (scs.IdtUpper || scs.IdtLower)) { + *smram = scs; + return TRUE; + } + } + + return FALSE; } int @@ -1695,7 +1698,8 @@ sadump_get_cr3_idtr(ulong *cr3, ulong *idtr) struct sadump_smram_cpu_state scs; memset(&scs, 0, sizeof(scs)); - get_sadump_smram_cpu_state_any(&scs); + if (!get_sadump_smram_cpu_state_any(&scs)) + return FALSE; *cr3 = scs.Cr3; *idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower; diff --git a/sadump.cgithub_b97e7fd4e826_to_8b50d94ada21.patch b/sadump.cgithub_b97e7fd4e826_to_8b50d94ada21.patch new file mode 100644 index 0000000..35f7cf0 --- /dev/null +++ b/sadump.cgithub_b97e7fd4e826_to_8b50d94ada21.patch @@ -0,0 +1,1705 @@ +/* + * sadump.h - core analysis suite + * + * Copyright (c) 2011 FUJITSU LIMITED + * + * 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. + * + * Author: HATAYAMA Daisuke + */ + +#include "defs.h" +#include "sadump.h" +#include /* htonl, htons */ +#include +#include + +enum { + failed = -1 +}; + +static struct sadump_data sadump_data = { 0 }; +static struct sadump_data *sd = &sadump_data; + +static int read_device(void *buf, size_t bytes, ulong *offset); +static int read_dump_header(char *file); +static int add_disk(char *file); +static int open_dump_file(char *file); +static int open_disk(char *file); +static uint64_t paddr_to_pfn(physaddr_t paddr); +static inline int is_set_bit(char *bitmap, uint64_t pfn); +static inline int page_is_ram(uint64_t nr); +static inline int page_is_dumpable(uint64_t nr); +static int lookup_diskset(uint64_t whole_offset, int *diskid, uint64_t *disk_offset); +static struct tm *efi_time_t_to_tm(const efi_time_t *e); +static char * guid_to_str(efi_guid_t *guid, char *buf, size_t buflen); +static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]); +static ulong per_cpu_ptr(ulong ptr, int cpu); +static ulong early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu); +static ulong legacy_per_cpu_ptr(ulong ptr, int cpu); +static int get_prstatus_from_crash_notes(int cpu, char *prstatus); +static void display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s); +static int cpu_to_apicid(int cpu, int *apicid); +static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram); +static int block_table_init(void); +static uint64_t pfn_to_block(uint64_t pfn); + +struct sadump_data * +sadump_get_sadump_data(void) +{ + if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) + return NULL; + + return &sadump_data; +} + +int +sadump_cleanup_sadump_data(void) +{ + int i; + + if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) + return FALSE; + + if (sd->flags & SADUMP_DISKSET) { + for (i = 1; i < sd->sd_list_len; ++i) { + if (sd->sd_list[i]->dfd) + close(sd->sd_list[i]->dfd); + free(sd->sd_list[i]->header); + free(sd->sd_list[i]); + } + } + + close(sd->dfd); + free(sd->header); + free(sd->dump_header); + free(sd->diskset_header); + free(sd->bitmap); + free(sd->dumpable_bitmap); + free(sd->page_buf); + free(sd->block_table); + if (sd->sd_list[0]) + free(sd->sd_list[0]); + free(sd->sd_list); + + memset(&sadump_data, 0, sizeof(sadump_data)); + + pc->flags &= ~SADUMP; + pc->dumpfile = NULL; + pc->readmem = NULL; + pc->writemem = NULL; + + return TRUE; +} + +static int +read_device(void *buf, size_t bytes, ulong *offset) +{ + if (lseek(sd->dfd, *offset, SEEK_SET) == failed) { + error(INFO, "sadump: cannot lseek dump device\n"); + return FALSE; + } + if (read(sd->dfd, buf, bytes) < bytes) { + error(INFO, "sadump: cannot read dump device\n"); + return FALSE; + } + *offset += bytes; + return TRUE; +} + +static int +read_dump_header(char *file) +{ + struct sadump_part_header *sph = NULL; + struct sadump_header *sh = NULL; + struct sadump_disk_set_header *new, *sdh = NULL; + struct sadump_media_header *smh = NULL; + struct sadump_diskset_data *sd_list_len_0 = NULL; + size_t block_size = SADUMP_DEFAULT_BLOCK_SIZE; + ulong flags = 0; + ulong offset = 0, sub_hdr_offset, data_offset; + uint32_t smram_cpu_state_size = 0; + ulong bitmap_len, dumpable_bitmap_len; + char *bitmap = NULL, *dumpable_bitmap = NULL, *page_buf = NULL; + char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; + char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; + + sph = malloc(block_size); + if (!sph) { + error(INFO, "sadump: cannot allocate partition header buffer\n"); + goto err; + } + + sdh = malloc(block_size); + if (!sdh) { + error(INFO, "sadump: cannot allocate disk set header buffer\n"); + goto err; + } + + sh = malloc(block_size); + if (!sh) { + error(INFO, "sadump: cannot allocate dump header buffer\n"); + goto err; + } + + smh = malloc(block_size); + if (!smh) { + error(INFO, "sadump: cannot allocate media header buffer\n"); + goto err; + } + +restart: + if (!read_device(sph, block_size, &offset)) { + error(INFO, "sadump: cannot read partition header\n"); + goto err; + } + + if (sph->signature1 != SADUMP_SIGNATURE1 || + sph->signature2 != SADUMP_SIGNATURE2) { + + flags |= SADUMP_MEDIA; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: read dump device as media " + "format\n"); + + offset = 0; + + if (!read_device(smh, block_size, &offset)) { + error(INFO, "sadump: cannot read media header\n"); + goto err; + } + + if (!read_device(sph, block_size, &offset)) { + error(INFO, "sadump: cannot read partition header\n"); + goto err; + } + + if (sph->signature1 != SADUMP_SIGNATURE1 || + sph->signature2 != SADUMP_SIGNATURE2) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have partition " + "header\n"); + goto err; + } + + } + + if (!verify_magic_number(sph->magicnum)) { + error(INFO, "sadump: invalid magic number\n"); + goto err; + } + + if (!(flags & SADUMP_MEDIA) && sph->set_disk_set) { + uint32_t header_blocks; + size_t header_size; + + flags |= SADUMP_DISKSET; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: read dump device as diskset\n"); + + if (sph->set_disk_set != 1 || + sph->set_disk_set > SADUMP_MAX_DISK_SET_NUM) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: invalid disk set number: " + "%d\n", + sph->set_disk_set); + goto err; + } + + if (!read_device(&header_blocks, sizeof(uint32_t), &offset)) { + error(INFO, "sadump: cannot read disk set header " + "size\n"); + goto err; + } + + offset -= sizeof(uint32_t); + header_size = header_blocks * block_size; + + if (header_size > block_size) { + new = realloc(sdh, header_size); + if (!new) { + error(INFO, "sadump: cannot re-allocate disk " + "set buffer\n"); + goto err; + } + sdh = new; + } + + if (!read_device(sdh, header_size, &offset)) { + error(INFO, "sadump: cannot read disk set header\n"); + goto err; + } + + } + + if (!read_device(sh, block_size, &offset)) { + error(INFO, "sadump: cannot read dump header\n"); + goto err; + } + + sub_hdr_offset = offset; + + if (strncmp(sh->signature, SADUMP_SIGNATURE, 8) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have dump header\n"); + goto err; + } + + if (flags & SADUMP_MEDIA) { + + if (memcmp(&sph->sadump_id, &smh->sadump_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: system ID mismatch\n" + " partition header: %s\n" + " media header: %s\n", + guid_to_str(&sph->sadump_id, guid1, sizeof(guid1)), + guid_to_str(&smh->sadump_id, guid2, sizeof(guid2))); + goto err; + } + + if (memcmp(&sph->disk_set_id, &smh->disk_set_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: disk set ID mismatch\n" + " partition header: %s\n" + " media header: %s\n", + guid_to_str(&sph->disk_set_id, guid1, sizeof(guid1)), + guid_to_str(&smh->disk_set_id, guid2, sizeof(guid2))); + goto err; + } + + if (memcmp(&sph->time_stamp, &smh->time_stamp, + sizeof(efi_time_t)) != 0) { + if (CRASHDEBUG(1)) { + error(INFO, "sadump: time stamp mismatch\n"); + error(INFO, "sadump: partition header: %s\n", + strip_linefeeds(asctime + (efi_time_t_to_tm + (&sph->time_stamp)))); + error(INFO, "sadump: media header: %s\n", + strip_linefeeds(asctime + (efi_time_t_to_tm + (&smh->time_stamp)))); + } + } + + if (smh->sequential_num != 1) { + error(INFO, "sadump: first media file has sequential " + "number %d\n", smh->sequential_num); + goto err; + } + + } + + if (sh->block_size != block_size) { + block_size = sh->block_size; + offset = 0; + goto restart; + } + + if (CRASHDEBUG(1)) { + if (flags & SADUMP_MEDIA) + error(INFO, "sadump: media backup file\n"); + + else if (flags & SADUMP_DISKSET) + error(INFO, "sadump: diskset configuration with %d " + "disks\n", sdh->disk_num); + + else + error(INFO, "sadump: single partition " + "configuration\n"); + } + + flags |= SADUMP_LOCAL; + + switch (sh->header_version) { + case 0: + sd->max_mapnr = (uint64_t)sh->max_mapnr; + break; + default: + error(WARNING, + "sadump: unsupported header version: %u\n" + "sadump: assuming header version: 1\n", + sh->header_version); + case 1: + sd->max_mapnr = sh->max_mapnr_64; + break; + } + + if (sh->sub_hdr_size > 0) { + if (!read_device(&smram_cpu_state_size, sizeof(uint32_t), + &offset)) { + error(INFO, + "sadump: cannot read SMRAM CPU STATE size\n"); + goto err; + } + smram_cpu_state_size /= sh->nr_cpus; + + offset -= sizeof(uint32_t); + offset += sh->sub_hdr_size * block_size; + } + + if (!sh->bitmap_blocks) { + error(INFO, "sadump: bitmap_blocks is zero\n"); + goto err; + } + bitmap_len = block_size * sh->bitmap_blocks; + bitmap = calloc(bitmap_len, 1); + if (!bitmap) { + error(INFO, "sadump: cannot allocate memory for bitmap " + "buffer\n"); + goto err; + } + if (!read_device(bitmap, bitmap_len, &offset)) { + error(INFO, "sadump: cannot read bitmap\n"); + goto err; + } + + if (!sh->dumpable_bitmap_blocks) { + error(INFO, "sadump: dumpable_bitmap_blocks is zero\n"); + goto err; + } + dumpable_bitmap_len = block_size * sh->dumpable_bitmap_blocks; + dumpable_bitmap = calloc(dumpable_bitmap_len, 1); + if (!dumpable_bitmap) { + error(INFO, "sadump: cannot allocate memory for " + "dumpable_bitmap buffer\n"); + goto err; + } + if (!read_device(dumpable_bitmap, dumpable_bitmap_len, &offset)) { + error(INFO, "sadump: cannot read dumpable bitmap\n"); + goto err; + } + + data_offset = offset; + + page_buf = malloc(block_size); + if (!page_buf) { + error(INFO, "sadump: cannot allocate page buffer\n"); + goto err; + } + + sd->filename = file; + + /* + * Switch to zero excluded mode by default on sadump-related + * formats because some Fujitsu troubleshooting software + * assumes the behavior. + */ + sd->flags = flags | SADUMP_ZERO_EXCLUDED; + + if (machine_type("X86")) + sd->machine_type = EM_386; + else if (machine_type("X86_64")) + sd->machine_type = EM_X86_64; + else { + error(INFO, "sadump: unsupported machine type: %s\n", + MACHINE_TYPE); + goto err; + } + + sd->data_offset = data_offset; + sd->block_size = block_size; + sd->block_shift = ffs(sd->block_size) - 1; + + sd->bitmap = bitmap; + sd->dumpable_bitmap = dumpable_bitmap; + + sd->sub_hdr_offset = sub_hdr_offset; + sd->smram_cpu_state_size = smram_cpu_state_size; + + sd->header = sph; + sd->dump_header = sh; + if (flags & SADUMP_DISKSET) + sd->diskset_header = sdh; + if (flags & SADUMP_MEDIA) + sd->media_header = smh; + + sd->page_buf = page_buf; + + if (flags & SADUMP_DISKSET) { + + sd_list_len_0 = malloc(sizeof(struct sadump_diskset_data)); + if (!sd_list_len_0) { + error(INFO, + "sadump: cannot allocate diskset data buffer\n"); + goto err; + } + + sd_list_len_0->filename = sd->filename; + sd_list_len_0->dfd = sd->dfd; + sd_list_len_0->header = sd->header; + sd_list_len_0->data_offset = sd->data_offset; + + sd->sd_list = malloc(sizeof(struct sadump_diskset_data *)); + if (!sd->sd_list) { + error(INFO, + "sadump: cannot allocate diskset list buffer\n"); + goto err; + } + + sd->sd_list_len = 1; + sd->sd_list[0] = sd_list_len_0; + } + + if (!block_table_init()) { + error(INFO, "sadump: cannot initialize block hash table\n"); + goto err; + } + + if (!(flags & SADUMP_DISKSET)) + free(sdh); + + if (!(flags & SADUMP_MEDIA)) + free(smh); + + return TRUE; + +err: + close(sd->dfd); + + free(sph); + free(sdh); + free(sh); + free(smh); + free(bitmap); + free(dumpable_bitmap); + free(page_buf); + free(sd_list_len_0); + + free(sd->sd_list); + + return FALSE; +} + +static int +add_disk(char *file) +{ + struct sadump_part_header *ph; + struct sadump_diskset_data *this_disk; + int diskid; + char guid1[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; + char guid2[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; + + diskid = sd->sd_list_len - 1; + this_disk = sd->sd_list[diskid]; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: add disk #%d\n", diskid+1); + + ph = malloc(sd->block_size); + if (!ph) { + error(INFO, "sadump: cannot malloc block_size buffer\n"); + return FALSE; + } + + if (lseek(this_disk->dfd, 0, SEEK_SET) == failed) { + error(INFO, "sadump: cannot lseek dump partition header\n"); + free(ph); + return FALSE; + } + if (read(this_disk->dfd, ph, sd->block_size) < sd->block_size) { + error(INFO, "sadump: cannot read dump partition header\n"); + free(ph); + return FALSE; + } + + if (ph->signature1 != SADUMP_SIGNATURE1 || + ph->signature2 != SADUMP_SIGNATURE2) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have partition header\n"); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->sadump_id, &ph->sadump_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: system ID mismatch\n" + " partition header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->header->sadump_id, guid1, + sizeof(guid1)), + diskid+1, + guid_to_str(&ph->sadump_id, guid2, + sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->disk_set_id, &ph->disk_set_id, sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: disk set ID mismatch\n" + " partition header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->header->disk_set_id, guid1, + sizeof(guid1)), + diskid+1, + guid_to_str(&ph->disk_set_id, guid2, + sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->diskset_header->vol_info[diskid - 1].id, &ph->vol_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: volume ID mismatch\n" + " disk set header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->diskset_header->vol_info[diskid-1].id, + guid1, sizeof(guid1)), + diskid+1, + guid_to_str(&ph->vol_id, guid2, sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->time_stamp, &ph->time_stamp, + sizeof(efi_time_t)) != 0) { + if (CRASHDEBUG(1)) { + error(INFO, "sadump: time stamp mismatch\n"); + error(INFO, + "sadump: partition header on disk #1: %s\n", + strip_linefeeds(asctime + (efi_time_t_to_tm + (&sd->header->time_stamp)))); + error(INFO, + "sadump: partition header on disk #%d: %s\n", + diskid+1, + strip_linefeeds(asctime + (efi_time_t_to_tm + (&ph->time_stamp)))); + } + } + + if (diskid != ph->set_disk_set - 1) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: wrong disk order; " + "#%d expected but #%d given\n", + diskid+1, ph->set_disk_set); + free(ph); + return FALSE; + } + + this_disk->header = ph; + this_disk->data_offset = sd->block_size; + this_disk->filename = file; + + return TRUE; +} + +static int +open_dump_file(char *file) +{ + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) { + error(INFO, "sadump: unable to open dump file %s", file); + return FALSE; + } + + sd->dfd = fd; + + return TRUE; +} + +static int +open_disk(char *file) +{ + struct sadump_diskset_data *this_disk; + + sd->sd_list_len++; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: open disk #%d\n", sd->sd_list_len); + + if (sd->sd_list_len > sd->diskset_header->disk_num) { + error(INFO, "sadump: too many diskset arguments; " + "this diskset consists of %d disks\n", + sd->diskset_header->disk_num); + return FALSE; + } + + sd->sd_list = realloc(sd->sd_list, + sd->sd_list_len * + sizeof(struct sadump_diskset_data *)); + if (!sd->sd_list) { + if (CRASHDEBUG(1)) { + error(INFO, "sadump: cannot malloc diskset list buffer\n"); + } + return FALSE; + } + + this_disk = malloc(sizeof(struct sadump_diskset_data)); + if (!this_disk) { + if (CRASHDEBUG(1)) { + error(INFO, "sadump: cannot malloc diskset data buffer\n"); + } + return FALSE; + } + memset(this_disk, 0, sizeof(*this_disk)); + sd->sd_list[sd->sd_list_len - 1] = this_disk; + + this_disk->dfd = open(file, O_RDONLY); + if (!this_disk->dfd) { + free(this_disk); + error(INFO, "sadump: unable to open dump file %s", file); + return FALSE; + } + + return TRUE; +} + +int is_sadump(char *file) +{ + if (SADUMP_VALID()) { + + if (!(sd->flags & SADUMP_DISKSET)) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not support multiple" + " file formats\n"); + (void) sadump_cleanup_sadump_data(); + return FALSE; + } + + if (!open_disk(file) || !add_disk(file)) { + (void) sadump_cleanup_sadump_data(); + return FALSE; + } + + return TRUE; + } + + if (!open_dump_file(file) || !read_dump_header(file)) + return FALSE; + + return TRUE; +} + +int sadump_is_diskset(void) +{ + if (!SADUMP_VALID()) + return FALSE; + + return !!(sd->flags & SADUMP_DISKSET); +} + +uint sadump_page_size(void) +{ + return sd->dump_header->block_size; +} + +/* + * Translate physical address in paddr to PFN number. This means normally that + * we just shift paddr by some constant. + */ +static uint64_t +paddr_to_pfn(physaddr_t paddr) +{ + return paddr >> sd->block_shift; +} + +static inline int +is_set_bit(char *bitmap, uint64_t pfn) +{ + ulong index, bit; + + index = pfn >> 3; + bit = 7 - (pfn & 7); + + return !!(bitmap[index] & (1UL << bit)); +} + +static inline int +page_is_ram(uint64_t nr) +{ + return is_set_bit(sd->bitmap, nr); +} + +static inline int +page_is_dumpable(uint64_t nr) +{ + return is_set_bit(sd->dumpable_bitmap, nr); +} + +static int +lookup_diskset(uint64_t whole_offset, int *diskid, uint64_t *disk_offset) +{ + uint64_t offset = whole_offset; + int i; + + for (i = 0; i < sd->sd_list_len; ++i) { + uint64_t used_device_i, ram_size; + ulong data_offset_i; + + used_device_i = sd->sd_list[i]->header->used_device; + data_offset_i = sd->sd_list[i]->data_offset; + + ram_size = used_device_i - data_offset_i; + + if (offset < ram_size) + break; + offset -= ram_size; + } + + if (i == sd->sd_list_len) + return FALSE; + + *diskid = i; + *disk_offset = offset; + + return TRUE; +} + +int read_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ + physaddr_t curpaddr ATTRIBUTE_UNUSED; + uint64_t pfn, whole_offset, perdisk_offset, block; + ulong page_offset; + int dfd; + + if (sd->flags & SADUMP_KDUMP_BACKUP && + paddr >= sd->backup_src_start && + paddr < sd->backup_src_start + sd->backup_src_size) { + ulong orig_paddr; + + orig_paddr = paddr; + paddr += sd->backup_offset - sd->backup_src_start; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: kdump backup region: %#llx => %#llx\n", + orig_paddr, paddr); + + } + + pfn = paddr_to_pfn(paddr); + + curpaddr = paddr & ~((physaddr_t)(sd->block_size-1)); + page_offset = paddr & ((physaddr_t)(sd->block_size-1)); + + if ((pfn >= sd->max_mapnr) || !page_is_ram(pfn)) + return SEEK_ERROR; + if (!page_is_dumpable(pfn)) { + if (!(sd->flags & SADUMP_ZERO_EXCLUDED)) + return PAGE_EXCLUDED; + memset(bufptr, 0, cnt); + return cnt; + } + + block = pfn_to_block(pfn); + + whole_offset = block * sd->block_size; + + if (sd->flags & SADUMP_DISKSET) { + int diskid; + + if (!lookup_diskset(whole_offset, &diskid, &perdisk_offset)) + return SEEK_ERROR; + + dfd = sd->sd_list[diskid]->dfd; + perdisk_offset += sd->sd_list[diskid]->data_offset; + + } else { + dfd = sd->dfd; + perdisk_offset = whole_offset + sd->data_offset; + + } + + if (lseek(dfd, perdisk_offset, SEEK_SET) == failed) + return SEEK_ERROR; + + if (read(dfd, sd->page_buf, sd->block_size) != sd->block_size) + return READ_ERROR; + + memcpy(bufptr, sd->page_buf + page_offset, cnt); + + return cnt; +} + +int write_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ + return 0; +} + +int sadump_init(char *unused, FILE *fptr) +{ + if (!SADUMP_VALID()) + return FALSE; + + return TRUE; +} + +ulong get_sadump_panic_task(void) +{ + return NO_TASK; +} + +ulong get_sadump_switch_stack(ulong task) +{ + return 0; +} + +static struct tm * +efi_time_t_to_tm(const efi_time_t *e) +{ + static struct tm t; + time_t ti; + + memset(&t, 0, sizeof(t)); + + t.tm_sec = e->second; + t.tm_min = e->minute; + t.tm_hour = e->hour; + t.tm_mday = e->day; + t.tm_mon = e->month - 1; + t.tm_year = e->year - 1900; + + if (e->timezone != EFI_UNSPECIFIED_TIMEZONE) + t.tm_hour += e->timezone; + + else if (CRASHDEBUG(1)) + error(INFO, "sadump: timezone information is missing\n"); + + ti = mktime(&t); + if (ti == (time_t)-1) + return &t; + + return localtime_r(&ti, &t); +} + +static char * +guid_to_str(efi_guid_t *guid, char *buf, size_t buflen) +{ + snprintf(buf, buflen, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + htonl(guid->data1), htons(guid->data2), htons(guid->data3), + guid->data4[0], guid->data4[1], guid->data4[2], + guid->data4[3], guid->data4[4], guid->data4[5], + guid->data4[6], guid->data4[7]); + + return buf; +} + +static int +verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) +{ + int i; + + for (i = 1; i < DUMP_PART_HEADER_MAGICNUM_SIZE; ++i) + if (magicnum[i] != (magicnum[i - 1] + 7) * 11) + return FALSE; + + return TRUE; +} + +int sadump_memory_used(void) +{ + return 0; +} + +int sadump_free_memory(void) +{ + return 0; +} + +/* + * This function is dump-type independent, and could be used to dump + * the diskdump_data structure contents and perhaps the sadump header + * data. + */ +int sadump_memory_dump(FILE *fp) +{ + struct sadump_part_header *sph; + struct sadump_disk_set_header *sdh; + struct sadump_header *sh; + struct sadump_media_header *smh; + int i, others; + char guid[SADUMP_EFI_GUID_TEXT_REPR_LEN+1]; + + fprintf(fp, "sadump_data: \n"); + fprintf(fp, " filename: %s\n", sd->filename); + fprintf(fp, " flags: %lx (", sd->flags); + others = 0; + if (sd->flags & SADUMP_LOCAL) + fprintf(fp, "%sSADUMP_LOCAL", others++ ? "|" : ""); + if (sd->flags & SADUMP_DISKSET) + fprintf(fp, "%sSADUMP_DISKSET", others++ ? "|" : ""); + if (sd->flags & SADUMP_MEDIA) + fprintf(fp, "%sSADUMP_MEDIA", others++ ? "|" : ""); + if (sd->flags & SADUMP_ZERO_EXCLUDED) + fprintf(fp, "%sSADUMP_ZERO_EXCLUDED", others++ ? "|" : ""); + if (sd->flags & SADUMP_KDUMP_BACKUP) + fprintf(fp, "%sSADUMP_KDUMP_BACKUP", others++ ? "|" : ""); + fprintf(fp, ") \n"); + fprintf(fp, " dfd: %d\n", sd->dfd); + fprintf(fp, " machine_type: %d ", sd->machine_type); + switch (sd->machine_type) + { + case EM_386: + fprintf(fp, "(EM_386)\n"); break; + case EM_X86_64: + fprintf(fp, "(EM_X86_64)\n"); break; + default: + fprintf(fp, "(unknown)\n"); break; + } + + fprintf(fp, "\n header: %lx\n", (ulong)sd->header); + sph = sd->header; + fprintf(fp, " signature1: %x\n", sph->signature1); + fprintf(fp, " signature2: %x\n", sph->signature2); + fprintf(fp, " enable: %u\n", sph->enable); + fprintf(fp, " reboot: %u\n", sph->reboot); + fprintf(fp, " compress: %u\n", sph->compress); + fprintf(fp, " recycle: %u\n", sph->recycle); + fprintf(fp, " label: (unused)\n"); + fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp)))); + fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); + fprintf(fp, " reserve: %u\n", sph->reserve); + fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); + fprintf(fp, " magicnum: %s\n", + verify_magic_number(sph->magicnum) + ? "(valid)" : "(invalid)"); + + fprintf(fp, "\n dump header: %lx\n", (ulong)sd->dump_header); + sh = sd->dump_header; + fprintf(fp, " signature: %s\n", sh->signature); + fprintf(fp, " header_version: %u\n", sh->header_version); + fprintf(fp, " reserve: %u\n", sh->reserve); + fprintf(fp, " timestamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sh->timestamp)))); + fprintf(fp, " status: %u\n", sh->status); + fprintf(fp, " compress: %u\n", sh->compress); + fprintf(fp, " block_size: %u\n", sh->block_size); + fprintf(fp, " extra_hdr_size: %u\n", sh->extra_hdr_size); + fprintf(fp, " sub_hdr_size: %u\n", sh->sub_hdr_size); + fprintf(fp, " bitmap_blocks: %u\n", sh->bitmap_blocks); + fprintf(fp, "dumpable_bitmap_blocks: %u\n", sh->dumpable_bitmap_blocks); + fprintf(fp, " max_mapnr: %u\n", sh->max_mapnr); + fprintf(fp, " total_ram_blocks: %u\n", sh->total_ram_blocks); + fprintf(fp, " device_blocks: %u\n", sh->device_blocks); + fprintf(fp, " written_blocks: %u\n", sh->written_blocks); + fprintf(fp, " current_cpu: %u\n", sh->current_cpu); + fprintf(fp, " nr_cpus: %u\n", sh->nr_cpus); + if (sh->header_version >= 1) { + fprintf(fp, + " max_mapnr_64: %" PRIu64 "\n" + " total_ram_blocks_64: %" PRIu64 "\n" + " device_blocks_64: %" PRIu64 "\n" + " written_blocks_64: %" PRIu64 "\n", + sh->max_mapnr_64, + sh->total_ram_blocks_64, + sh->device_blocks_64, + sh->written_blocks_64); + } + + fprintf(fp, "\n dump sub heaer: "); + if (sh->sub_hdr_size > 0) { + ulong offset = sd->sub_hdr_offset; + struct sadump_apic_state as; + struct sadump_smram_cpu_state scs, zero; + uint32_t size; + uint aid; + + memset(&zero, 0, sizeof(zero)); + + if (!read_device(&size, sizeof(uint32_t), &offset)) { + error(INFO, "sadump: cannot read sub header size\n"); + return FALSE; + } + fprintf(fp, "\n size: %u\n", size); + for (aid = 0; aid < sh->nr_cpus; ++aid) { + if (!read_device(&as, sizeof(as), &offset)) { + error(INFO, "sadump: cannot read sub header " + "apic_id\n"); + return FALSE; + } + fprintf(fp, " " + "apic_id[%u]: ApicId %llu: Ldr: %llu\n", + aid, (ulonglong)as.ApicId, (ulonglong)as.Ldr); + } + for (aid = 0; aid < sh->nr_cpus; ++aid) { + if (!read_device(&scs, sizeof(scs), &offset)) { + error(INFO, "sadump: cannot read sub header " + "cpu_state\n"); + return FALSE; + } + if (memcmp(&scs, &zero, sizeof(scs)) != 0) { + fprintf(fp, "\n"); + display_smram_cpu_state(aid, &scs); + } + } + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n disk set header: %lx ", (ulong)sd->diskset_header); + if ((sdh = sd->diskset_header)) { + fprintf(fp, "\ndisk_set_header_size: %u\n", sdh->disk_set_header_size); + fprintf(fp, " disk_num: %u\n", sdh->disk_num); + fprintf(fp, " disk_set_size: %llu\n", (ulonglong)sdh->disk_set_size); + for (i = 0; i < sdh->disk_num - 1; ++i) { + struct sadump_volume_info *vol = &sdh->vol_info[i]; + + fprintf(fp, " vol_info[%d]: \n", i); + fprintf(fp, " id: %s\n", guid_to_str(&vol->id, guid, sizeof(guid))); + fprintf(fp, " vol_size: %llu\n", (ulonglong)vol->vol_size); + fprintf(fp, " status: %u\n", vol->status); + fprintf(fp, " cache_size: %u\n", vol->cache_size); + } + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n media header: %lx ", (ulong)sd->media_header); + if ((smh = sd->media_header)) { + fprintf(fp, "\n sadump_id: %s\n", guid_to_str(&smh->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&smh->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&smh->time_stamp)))); + fprintf(fp, " sequential_num: %d\n", smh->sequential_num); + fprintf(fp, " term_cord: %d\n", smh->term_cord); + fprintf(fp, "disk_set_header_size: %d\n", smh->disk_set_header_size); + fprintf(fp, " disks_in_use: %d\n", smh->disks_in_use); + fprintf(fp, " reserve: (not displayed) \n"); + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n bitmap: %lx\n", (ulong)sd->bitmap); + fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)sd->dumpable_bitmap); + fprintf(fp, " sub_hdr_offset: %lx\n", (ulong)sd->sub_hdr_offset); + fprintf(fp, "smram_cpu_state_size: %lx\n", (ulong)sd->smram_cpu_state_size); + fprintf(fp, " data_offset: %lx\n", sd->data_offset); + fprintf(fp, " block_size: %d\n", sd->block_size); + fprintf(fp, " block_shift: %d\n", sd->block_shift); + fprintf(fp, " page_buf: %lx\n", (ulong)sd->page_buf); + fprintf(fp, " block_table: %lx\n", (ulong)sd->block_table); + fprintf(fp, " sd_list_len: %d\n", sd->sd_list_len); + fprintf(fp, " sd_list: %lx\n", (ulong)sd->sd_list); + fprintf(fp, " backup_src_start: %llx\n", sd->backup_src_start); + fprintf(fp, " backup_src_size: %lx\n", sd->backup_src_size); + fprintf(fp, " backup_offset: %llx\n", (ulonglong)sd->backup_src_size); + + for (i = 0; i < sd->sd_list_len; ++i) { + struct sadump_diskset_data *sdd = sd->sd_list[i]; + + fprintf(fp, "\n sd_list[%d]: \n", i); + fprintf(fp, " filename: %s\n", sdd->filename); + fprintf(fp, " dfd: %d\n", sdd->dfd); + + fprintf(fp, " header: %lx\n", (ulong)sdd->header); + sph = sdd->header; + fprintf(fp, " signature1: %x\n", sph->signature1); + fprintf(fp, " signature2: %x\n", sph->signature2); + fprintf(fp, " enable: %u\n", sph->enable); + fprintf(fp, " reboot: %u\n", sph->reboot); + fprintf(fp, " compress: %u\n", sph->compress); + fprintf(fp, " recycle: %u\n", sph->recycle); + fprintf(fp, " label: (unused)\n"); + fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp)))); + fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); + fprintf(fp, " reserve: %u\n", sph->reserve); + fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); + fprintf(fp, " magicnum: %s\n", + verify_magic_number(sph->magicnum) + ? "(valid)" : "(invalid)"); + + fprintf(fp, " data_offset: %lx\n", sdd->data_offset); + } + + return TRUE; +} + +static ulong +per_cpu_ptr(ulong ptr, int cpu) +{ + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (kt->cpus == 1) + return ptr; + + if (!(kt->flags & PER_CPU_OFF)) + return 0UL; + + if (machine_type("X86_64")) { + ulong __per_cpu_load; + + readmem(symbol_value("__per_cpu_load"), KVADDR, + &__per_cpu_load, sizeof(__per_cpu_load), + "__per_cpu_load", FAULT_ON_ERROR); + + if (kt->__per_cpu_offset[cpu] == __per_cpu_load) + return 0UL; + + } else if (machine_type("X86")) { + if (kt->__per_cpu_offset[cpu] == 0) + return 0UL; + + } + + return ptr + kt->__per_cpu_offset[cpu]; +} + +static ulong +early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu) +{ + char sym_early_ptr[BUFSIZE], sym_early_map[BUFSIZE]; + ulong early_ptr; + + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (!sym && !(sym = per_cpu_symbol_search(symbol))) + return 0UL; + + if (!(kt->flags & SMP)) + return per_cpu_ptr(sym->value, cpu); + + snprintf(sym_early_ptr, BUFSIZE, "%s_early_ptr", symbol); + snprintf(sym_early_map, BUFSIZE, "%s_early_map", symbol); + + if (!symbol_exists(sym_early_ptr) || !symbol_exists(sym_early_map)) + return 0UL; + + readmem(symbol_value(sym_early_ptr), KVADDR, &early_ptr, + sizeof(early_ptr), sym_early_ptr, FAULT_ON_ERROR); + + return early_ptr + ? symbol_value(sym_early_map)+cpu*sizeof(uint16_t) + : per_cpu_ptr(sym->value, cpu); +} + +static ulong +legacy_per_cpu_ptr(ulong ptr, int cpu) +{ + ulong addr; + + if (!(kt->flags & SMP)) + return ptr; + + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (!readmem(~ptr + cpu * sizeof(ulong), KVADDR, &addr, sizeof(ulong), + "search percpu_data", FAULT_ON_ERROR)) + return 0UL; + + return addr; +} + +/** + * Retrieve eip and esp register values from crash_notes saved by + * kdump at crash. If register values has not been saved yet, set 0 to + * eip and esp instead. + */ +static int +get_prstatus_from_crash_notes(int cpu, char *prstatus) +{ + ulong crash_notes, crash_notes_ptr, percpu_addr; + char *prstatus_ptr, *note_buf, *zero_buf, *name; + uint32_t *buf; + + if (cpu < 0 || kt->cpus <= cpu) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return FALSE; + } + + if (!symbol_exists("crash_notes")) { + error(INFO, "sadump: symbol crash_notes doesn't exist\n"); + return FALSE; + } + + crash_notes = symbol_value("crash_notes"); + + readmem(crash_notes, KVADDR, &crash_notes_ptr, sizeof(ulong), + "dereference crash_notes", FAULT_ON_ERROR); + + if (!crash_notes_ptr) { + if (CRASHDEBUG(1)) + error(INFO, + "sadump: buffer for crash_notes is NULL\n"); + return FALSE; + } + + percpu_addr = VALID_STRUCT(percpu_data) + ? legacy_per_cpu_ptr(crash_notes_ptr, cpu) + : per_cpu_ptr(crash_notes_ptr, cpu); + + zero_buf = GETBUF(SIZE(note_buf)); + BZERO(zero_buf, SIZE(note_buf)); + + note_buf = GETBUF(SIZE(note_buf)); + + readmem(percpu_addr, KVADDR, note_buf, SIZE(note_buf), + "read crash_notes", FAULT_ON_ERROR); + + if (memcmp(note_buf, zero_buf, SIZE(note_buf)) == 0) + return FALSE; + + if (BITS64()) { + Elf64_Nhdr *note64; + + note64 = (Elf64_Nhdr *)note_buf; + buf = (uint32_t *)note_buf; + name = (char *)(note64 + 1); + + if (note64->n_type != NT_PRSTATUS || + note64->n_namesz != strlen("CORE") + 1 || + strncmp(name, "CORE", note64->n_namesz) || + note64->n_descsz != SIZE(elf_prstatus)) + return FALSE; + + prstatus_ptr = (char *)(buf + (sizeof(*note64) + 3) / 4 + + (note64->n_namesz + 3) / 4); + + } else { + Elf32_Nhdr *note32; + + note32 = (Elf32_Nhdr *)note_buf; + buf = (uint32_t *)note_buf; + name = (char *)(note32 + 1); + + if ((note32->n_type != NT_PRSTATUS) && + (note32->n_namesz != strlen("CORE") + 1 || + strncmp(name, "CORE", note32->n_namesz) || + note32->n_descsz != SIZE(elf_prstatus))) + return FALSE; + + prstatus_ptr = (char *)(buf + (sizeof(*note32) + 3) / 4 + + (note32->n_namesz + 3) / 4); + + } + + memcpy(prstatus, prstatus_ptr, SIZE(elf_prstatus)); + + return TRUE; +} + +int +sadump_get_smram_cpu_state(int apicid, + struct sadump_smram_cpu_state *smram) +{ + ulong offset; + + if (!sd->sub_hdr_offset || !sd->smram_cpu_state_size || + apicid >= sd->dump_header->nr_cpus) + return FALSE; + + offset = sd->sub_hdr_offset + sizeof(uint32_t) + + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); + + if (lseek(sd->dfd, offset + apicid * sd->smram_cpu_state_size, + SEEK_SET) == failed) + error(FATAL, + "sadump: cannot lseek smram cpu state in dump sub header\n"); + + if (read(sd->dfd, smram, sd->smram_cpu_state_size) != sd->smram_cpu_state_size) + error(FATAL, "sadump: cannot read smram cpu state in dump sub " + "header\n"); + + return TRUE; +} + +static void +display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s) +{ + fprintf(fp, + "APIC ID: %d\n" + " RIP: %016llx RSP: %08x%08x RBP: %08x%08x\n" + " RAX: %08x%08x RBX: %08x%08x RCX: %08x%08x\n" + " RDX: %08x%08x RSI: %08x%08x RDI: %08x%08x\n" + " R08: %08x%08x R09: %08x%08x R10: %08x%08x\n" + " R11: %08x%08x R12: %08x%08x R13: %08x%08x\n" + " R14: %08x%08x R15: %08x%08x\n" + " SMM REV: %08x SMM BASE %08x\n" + " CS : %08x DS: %08x SS: %08x ES: %08x FS: %08x\n" + " GS : %08x\n" + " CR0: %016llx CR3: %016llx CR4: %08x\n" + " GDT: %08x%08x LDT: %08x%08x IDT: %08x%08x\n" + " GDTlim: %08x LDTlim: %08x IDTlim: %08x\n" + " LDTR: %08x TR: %08x RFLAGS: %016llx\n" + " EPTP: %016llx EPTP_SETTING: %08x\n" + " DR6: %016llx DR7: %016llx\n" + " Ia32Efer: %016llx\n" + " IoMemAddr: %08x%08x IoEip: %016llx\n" + " IoMisc: %08x LdtInfo: %08x\n" + " IoInstructionRestart: %04x AutoHaltRestart: %04x\n", + apicid, + (ulonglong)s->Rip, s->RspUpper, s->RspLower, s->RbpUpper, s->RbpLower, + s->RaxUpper, s->RaxLower, s->RbxUpper, s->RbxLower, s->RcxUpper, s->RcxLower, + s->RdxUpper, s->RdxLower, s->RsiUpper, s->RsiLower, s->RdiUpper, s->RdiLower, + s->R8Upper, s->R8Lower, s->R9Upper, s->R9Lower, s->R10Upper, s->R10Lower, + s->R11Upper, s->R11Lower, s->R12Upper, s->R12Lower, s->R13Upper, s->R13Lower, + s->R14Upper, s->R14Lower, s->R15Upper, s->R15Lower, + s->SmmRevisionId, s->Smbase, + s->Cs, s->Ds, s->Ss, s->Es, s->Fs, s->Gs, + (ulonglong)s->Cr0, (ulonglong)s->Cr3, s->Cr4, + s->GdtUpper, s->GdtLower, s->LdtUpper, s->LdtLower, s->IdtUpper, s->IdtLower, + s->GdtLimit, s->LdtLimit, s->IdtLimit, + s->Ldtr, s->Tr, (ulonglong)s->Rflags, + (ulonglong)s->Eptp, s->EptpSetting, + (ulonglong)s->Dr6, (ulonglong)s->Dr7, + (ulonglong)s->Ia32Efer, + s->IoMemAddrUpper, s->IoMemAddrLower, (ulonglong)s->IoEip, + s->IoMisc, s->LdtInfo, + s->IoInstructionRestart, + s->AutoHaltRestart); +} + +static int cpu_to_apicid(int cpu, int *apicid) +{ + struct syment *sym; + + if (symbol_exists("bios_cpu_apicid")) { + uint8_t apicid_u8; + + readmem(symbol_value("bios_cpu_apicid") + cpu*sizeof(uint8_t), + KVADDR, &apicid_u8, sizeof(uint8_t), "bios_cpu_apicid", + FAULT_ON_ERROR); + + *apicid = (int)apicid_u8; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: apicid %u for cpu %d from " + "bios_cpu_apicid\n", apicid_u8, cpu); + + } else if ((sym = per_cpu_symbol_search("x86_bios_cpu_apicid"))) { + uint16_t apicid_u16; + + readmem(early_per_cpu_ptr("x86_bios_cpu_apicid", sym, cpu), + KVADDR, &apicid_u16, sizeof(uint16_t), + "x86_bios_cpu_apicid", FAULT_ON_ERROR); + + *apicid = (int)apicid_u16; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: apicid %u for cpu %d from " + "x86_bios_cpu_apicid\n", apicid_u16, cpu); + + } else { + if (CRASHDEBUG(1)) + error(INFO, "sadump: no symbols for access to apicid\n"); + + return FALSE; + } + + return TRUE; +} + +static int +get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram) +{ + int apicid = 0; + + if (cpu < 0 || kt->cpus <= cpu) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return FALSE; + } + + if (!cpu_to_apicid(cpu, &apicid)) + return FALSE; + + sadump_get_smram_cpu_state(apicid, smram); + + return TRUE; +} + +void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp) +{ + ulong ip, sp; + struct sadump_smram_cpu_state smram; + char *prstatus; + int cpu = bt->tc->processor; + + if (!is_task_active(bt->task)) { + machdep->get_stack_frame(bt, ipp, spp); + return; + } + + bt->flags |= BT_DUMPFILE_SEARCH; + if (machine_type("X86_64")) + machdep->get_stack_frame(bt, ipp, spp); + else if (machine_type("X86")) + get_netdump_regs_x86(bt, ipp, spp); + if (bt->flags & BT_DUMPFILE_SEARCH) + return; + + prstatus = GETBUF(SIZE(elf_prstatus)); + + if (get_prstatus_from_crash_notes(cpu, prstatus)) { + ip = ULONG(prstatus + + OFFSET(elf_prstatus_pr_reg) + + (BITS64() + ? OFFSET(user_regs_struct_rip) + : OFFSET(user_regs_struct_eip))); + sp = ULONG(prstatus + + OFFSET(elf_prstatus_pr_reg) + + (BITS64() + ? OFFSET(user_regs_struct_rsp) + : OFFSET(user_regs_struct_eip))); + if (ip || sp) { + *ipp = ip; + *spp = sp; + return; + } + } + + get_sadump_smram_cpu_state(cpu, &smram); + ip = smram.Rip; + sp = ((uint64_t)smram.RspUpper << 32) + smram.RspLower; + + if (is_kernel_text(ip) && + (((sp >= GET_STACKBASE(bt->task)) && + (sp < GET_STACKTOP(bt->task))) || + in_alternate_stack(bt->tc->processor, sp))) { + *ipp = ip; + *spp = sp; + bt->flags |= BT_KERNEL_SPACE; + return; + } + + if (!is_kernel_text(ip) && + in_user_stack(bt->tc->task, sp)) + bt->flags |= BT_USER_SPACE; + +} + +void +sadump_display_regs(int cpu, FILE *ofp) +{ + struct sadump_smram_cpu_state smram; + + if (cpu < 0 || cpu >= kt->cpus) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return; + } + + get_sadump_smram_cpu_state(cpu, &smram); + + if (machine_type("X86_64")) { + fprintf(ofp, + " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" + " RAX: %016llx RBX: %016llx RCX: %016llx\n" + " RDX: %016llx RSI: %016llx RDI: %016llx\n" + " RBP: %016llx R8: %016llx R9: %016llx\n" + " R10: %016llx R11: %016llx R12: %016llx\n" + " R13: %016llx R14: %016llx R15: %016llx\n" + " CS: %04x SS: %04x\n", + (ulonglong)(smram.Rip), + (ulonglong)(((uint64_t)smram.RspUpper<<32)+smram.RspLower), + (ulonglong)(smram.Rflags), + (ulonglong)(((uint64_t)smram.RaxUpper<<32)+smram.RaxLower), + (ulonglong)(((uint64_t)smram.RbxUpper<<32)+smram.RbxLower), + (ulonglong)(((uint64_t)smram.RcxUpper<<32)+smram.RcxLower), + (ulonglong)(((uint64_t)smram.RdxUpper<<32)+smram.RdxLower), + (ulonglong)(((uint64_t)smram.RsiUpper<<32)+smram.RsiLower), + (ulonglong)(((uint64_t)smram.RdiUpper<<32)+smram.RdiLower), + (ulonglong)(((uint64_t)smram.RbpUpper<<32)+smram.RbpLower), + (ulonglong)(((uint64_t)smram.R8Upper<<32)+smram.R8Lower), + (ulonglong)(((uint64_t)smram.R9Upper<<32)+smram.R9Lower), + (ulonglong)(((uint64_t)smram.R10Upper<<32)+smram.R10Lower), + (ulonglong)(((uint64_t)smram.R11Upper<<32)+smram.R11Lower), + (ulonglong)(((uint64_t)smram.R12Upper<<32)+smram.R12Lower), + (ulonglong)(((uint64_t)smram.R13Upper<<32)+smram.R13Lower), + (ulonglong)(((uint64_t)smram.R14Upper<<32)+smram.R14Lower), + (ulonglong)(((uint64_t)smram.R15Upper<<32)+smram.R15Lower), + smram.Cs, + smram.Ss); + } + + if (machine_type("X86")) { + fprintf(ofp, + " EAX: %08llx EBX: %08llx ECX: %08llx EDX: %08llx\n" + " DS: %04x ESI: %08llx ES: %04x EDI: %08llx\n" + " SS: %04x ESP: %08llx EBP: %08llx GS: %04x\n" + " CS: %04x EIP: %08llx EFLAGS: %08llx\n", + (ulonglong)smram.RaxLower, + (ulonglong)smram.RbxLower, + (ulonglong)smram.RcxLower, + (ulonglong)smram.RdxLower, + smram.Ds & 0xffff, + (ulonglong)smram.RsiLower, + smram.Es & 0xffff, + (ulonglong)smram.RdiLower, + smram.Ss, + (ulonglong)smram.RspLower, + (ulonglong)smram.RbpLower, + smram.Gs, + smram.Cs, + (ulonglong)smram.Rip, + (ulonglong)smram.Rflags); + } +} + +/* + * sadump does not save phys_base; it must resort to another way. + */ +int sadump_phys_base(ulong *phys_base) +{ + if (SADUMP_VALID() && !sd->phys_base) { + if (CRASHDEBUG(1)) + error(NOTE, "sadump: does not save phys_base.\n"); + return FALSE; + } + + if (sd->phys_base) { + *phys_base = sd->phys_base; + return TRUE; + } + + return FALSE; +} + +int +sadump_set_phys_base(ulong phys_base) +{ + sd->phys_base = phys_base; + + return TRUE; +} + +/* + * Used by "sys" command to show diskset disk names. + */ +void sadump_show_diskset(void) +{ + int i; + + for (i = 0; i < sd->sd_list_len; ++i) { + char *filename = sd->sd_list[i]->filename; + + fprintf(fp, "%s%s", i ? " " : "", + filename); + if ((i+1) < sd->sd_list_len) + fprintf(fp, "\n"); + } +} + +static int block_table_init(void) +{ + uint64_t pfn, section, max_section, *block_table; + + max_section = divideup(sd->max_mapnr, SADUMP_PF_SECTION_NUM); + + block_table = calloc(sizeof(uint64_t), max_section); + if (!block_table) { + error(INFO, "sadump: cannot allocate memory for block_table\n"); + return FALSE; + } + + for (section = 0; section < max_section; ++section) { + if (section > 0) + block_table[section] = block_table[section-1]; + for (pfn = section * SADUMP_PF_SECTION_NUM; + pfn < (section + 1) * SADUMP_PF_SECTION_NUM; + ++pfn) + if (page_is_dumpable(pfn)) + block_table[section]++; + } + + sd->block_table = block_table; + + return TRUE; +} + +static uint64_t pfn_to_block(uint64_t pfn) +{ + uint64_t block, section, p; + + section = pfn / SADUMP_PF_SECTION_NUM; + + if (section) + block = sd->block_table[section - 1]; + else + block = 0; + + for (p = section * SADUMP_PF_SECTION_NUM; p < pfn; ++p) + if (page_is_dumpable(p)) + block++; + + return block; +} + +int sadump_is_zero_excluded(void) +{ + return (sd->flags & SADUMP_ZERO_EXCLUDED) ? TRUE : FALSE; +} + +void sadump_set_zero_excluded(void) +{ + sd->flags |= SADUMP_ZERO_EXCLUDED; +} + +void sadump_unset_zero_excluded(void) +{ + sd->flags &= ~SADUMP_ZERO_EXCLUDED; +} + +struct sadump_data * +get_sadump_data(void) +{ + return sd; +} + +#ifdef X86_64 +static int +get_sadump_smram_cpu_state_any(struct sadump_smram_cpu_state *smram) +{ + ulong offset; + struct sadump_header *sh = sd->dump_header; + int apicid; + struct sadump_smram_cpu_state scs, zero; + + offset = sd->sub_hdr_offset + sizeof(uint32_t) + + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); + + memset(&zero, 0, sizeof(zero)); + + for (apicid = 0; apicid < sh->nr_cpus; ++apicid) { + if (!read_device(&scs, sizeof(scs), &offset)) { + error(INFO, "sadump: cannot read sub header " + "cpu_state\n"); + return FALSE; + } + if (memcmp(&scs, &zero, sizeof(scs)) != 0) { + *smram = scs; + return TRUE; + } + } + + return FALSE; +} + +int +sadump_get_cr3_idtr(ulong *cr3, ulong *idtr) +{ + struct sadump_smram_cpu_state scs; + + memset(&scs, 0, sizeof(scs)); + get_sadump_smram_cpu_state_any(&scs); + + *cr3 = scs.Cr3; + *idtr = ((uint64_t)scs.IdtUpper)<<32 | (uint64_t)scs.IdtLower; + + return TRUE; +} +#endif /* X86_64 */ diff --git a/symbols.c b/symbols.c index f04e8b5..717a56b 100644 --- a/symbols.c +++ b/symbols.c @@ -3227,6 +3227,11 @@ dump_symbol_table(void) fprintf(fp, " kaiser_init_vmlinux: (unused)\n"); } + if (SADUMP_DUMPFILE()) + fprintf(fp, "linux_banner_vmlinux: %lx\n", st->linux_banner_vmlinux); + else + fprintf(fp, "linux_banner_vmlinux: (unused)\n"); + fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH, (ulong)&st->symval_hash[0]); @@ -12629,15 +12634,25 @@ numeric_forward(const void *P_x, const void *P_y) else if (STREQ(y->name, "idt_table")) st->idt_table_vmlinux = valueof(y); + if (STREQ(x->name, "kaiser_init")) + st->kaiser_init_vmlinux = valueof(x); + else if (STREQ(y->name, "kaiser_init")) + st->kaiser_init_vmlinux = valueof(y); + + if (STREQ(x->name, "linux_banner")) + st->linux_banner_vmlinux = valueof(x); + else if (STREQ(y->name, "linux_banner")) + st->linux_banner_vmlinux = valueof(y); + + if (STREQ(x->name, "pti_init")) + st->pti_init_vmlinux = valueof(x); + else if (STREQ(y->name, "pti_init")) + st->pti_init_vmlinux = valueof(y); + if (STREQ(x->name, "saved_command_line")) st->saved_command_line_vmlinux = valueof(x); else if (STREQ(y->name, "saved_command_line")) st->saved_command_line_vmlinux = valueof(y); - - if (STREQ(x->name, "pti_init")) - st->pti_init_vmlinux = valueof(x); - else if (STREQ(y->name, "kaiser_init")) - st->kaiser_init_vmlinux = valueof(y); } xs = bfd_get_section(x); diff --git a/symbols.cgithub_b97e7fd4e826_to_8b50d94ada21.patch b/symbols.cgithub_b97e7fd4e826_to_8b50d94ada21.patch new file mode 100644 index 0000000..f04e8b5 --- /dev/null +++ b/symbols.cgithub_b97e7fd4e826_to_8b50d94ada21.patch @@ -0,0 +1,13387 @@ +/* symbols.c - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. + * Copyright (C) 2002-2020 David Anderson + * Copyright (C) 2002-2020 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 kaslr_init(void); +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 int compare_size_name(const void *, const void *); +struct type_request; +static void append_struct_symbol (struct type_request *, struct gnu_request *); +static void request_types(ulong, ulong, char *); +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 struct syment *kallsyms_module_symbol(struct load_module *, symbol_info *); +static int kallsyms_module_function_size(struct syment *, struct load_module *, ulong *); +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 void do_datatype_addr(struct datatype_member *, ulong, int, + ulong, char **, int); +static void process_gdb_output(char *, unsigned, const char *, int); +static char *expr_type_name(const char *); +static int display_per_cpu_info(struct syment *, int, char *); +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 *); +struct struct_elem; +static void free_structure(struct struct_elem *); +static unsigned char is_right_brace(const char *); +static struct struct_elem *find_node(struct struct_elem *, char *); +static void dump_node(struct struct_elem *, char *, unsigned char, unsigned 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 SHOW_RAW_DATA (0x200000) +#define DEREF_POINTERS (0x400000) + +#define INTEGER_TYPE (UINT8|INT8|UINT16|INT16|UINT32|INT32|UINT64|INT64) + +#define INITIAL_INDENT (4) +#define INDENT_INCR (2) + +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); +static int member_to_datatype(char *, 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); + } + + /* + * 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 *)); + st->first_section_start = st->last_section_end = 0; + + 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); + } + } + + 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"); + + kaslr_init(); + + gnu_qsort(st->bfd, minisyms, symcount, size, sort_x, sort_y); + + store_symbols(st->bfd, FALSE, minisyms, symcount, size); + + free(minisyms); + + 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; +} + +/* + * Gather the relevant information from the dumpfile or live system + * and determine whether to derive the KASLR offset. + * + * Setting st->_stext_vmlinux to UNINITIALIZED will trigger the + * search for "_stext" from the vmlinux file during the initial + * symbol sort operation. + * + * Setting RELOC_AUTO will ensure that derive_kaslr_offset() is + * called after the sorting operation has captured the vmlinux + * file's "_stext" symbol value -- which it will compare to the + * relocated "_stext" value found in either a dumpfile's vmcoreinfo + * or in /proc/kallsyms on a live system. + * + * Setting KASLR_CHECK will trigger a search for "module_load_offset" + * during the initial symbol sort operation, and if found, will + * set (RELOC_AUTO|KASLR). On live systems, the search is done + * here by checking /proc/kallsyms. + */ +static void +kaslr_init(void) +{ + char *string; + + if ((!machine_type("X86_64") && !machine_type("ARM64") && !machine_type("X86") && + !machine_type("S390X")) || (kt->flags & RELOC_SET)) + return; + + if (!kt->vmcoreinfo._stext_SYMBOL && + (string = pc->read_vmcoreinfo("SYMBOL(_stext)"))) { + kt->vmcoreinfo._stext_SYMBOL = htol(string, RETURN_ON_ERROR, NULL); + free(string); + } + + /* + * --kaslr=auto + */ + if ((kt->flags2 & (RELOC_AUTO|KASLR)) == (RELOC_AUTO|KASLR)) + st->_stext_vmlinux = UNINITIALIZED; + + if (ACTIVE() && /* Linux 3.15 */ + (symbol_value_from_proc_kallsyms("module_load_offset") != BADVAL)) { + kt->flags2 |= (RELOC_AUTO|KASLR); + st->_stext_vmlinux = UNINITIALIZED; + } + + if (machine_type("S390X")) { + kt->flags2 |= (RELOC_AUTO|KASLR); + st->_stext_vmlinux = UNINITIALIZED; + } + + if (QEMU_MEM_DUMP_NO_VMCOREINFO()) { + if (KDUMP_DUMPFILE() && kdump_kaslr_check()) { + kt->flags2 |= KASLR_CHECK; + } else if (DISKDUMP_DUMPFILE() && diskdump_kaslr_check()) { + kt->flags2 |= KASLR_CHECK; + } + } else if (KDUMP_DUMPFILE() || DISKDUMP_DUMPFILE()) { + /* Linux 3.14 */ + if ((string = pc->read_vmcoreinfo("KERNELOFFSET"))) { + free(string); + kt->flags2 |= KASLR_CHECK; + st->_stext_vmlinux = UNINITIALIZED; + } + } + + if (SADUMP_DUMPFILE() || VMSS_DUMPFILE()) + kt->flags2 |= KASLR_CHECK; +} + +/* + * Derives the kernel aslr offset by comparing the _stext symbol from the + * the vmcoreinfo in the dump file to the _stext symbol in the vmlinux file. + */ +static void +derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte *start, bfd_byte *end, + unsigned int size, asymbol *store) +{ + unsigned long relocate; + ulong _stext_relocated; + + if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO() || VMSS_DUMPFILE()) { + ulong kaslr_offset = 0; + ulong phys_base = 0; + + calc_kaslr_offset(&kaslr_offset, &phys_base); + + if (kaslr_offset) { + kt->relocate = kaslr_offset * -1; + kt->flags |= RELOC_SET; + } + + if (phys_base) { + if (SADUMP_DUMPFILE()) + sadump_set_phys_base(phys_base); + else if (KDUMP_DUMPFILE()) + kdump_set_phys_base(phys_base); + else if (DISKDUMP_DUMPFILE()) + diskdump_set_phys_base(phys_base); + else if (VMSS_DUMPFILE()) + vmware_vmss_set_phys_base(phys_base); + } + + return; + } + + if (ACTIVE()) { + _stext_relocated = symbol_value_from_proc_kallsyms("_stext"); + if (_stext_relocated == BADVAL) + return; + } else { + _stext_relocated = kt->vmcoreinfo._stext_SYMBOL; + if (_stext_relocated == 0) + return; + } + + /* + * To avoid mistaking an mismatched kernel version with + * a kaslr offset, we make sure that the offset is + * aligned by 0x1000, as it always will be for kaslr. + */ + if (st->_stext_vmlinux && (st->_stext_vmlinux != UNINITIALIZED)) { + relocate = st->_stext_vmlinux - _stext_relocated; + if (relocate && !(relocate & 0xfff)) { + kt->relocate = relocate; + kt->flags |= RELOC_SET; + } + } + + if (CRASHDEBUG(1) && (kt->flags & RELOC_SET)) { + fprintf(fp, "KASLR:\n"); + fprintf(fp, " _stext from %s: %lx\n", + basename(pc->namelist), st->_stext_vmlinux); + fprintf(fp, " _stext from %s: %lx\n", + ACTIVE() ? "/proc/kallsyms" : "vmcoreinfo", + _stext_relocated); + fprintf(fp, " relocate: %lx (%ldMB)\n", + kt->relocate * -1, (kt->relocate * -1) >> 20); + } +} + +/* + * 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; + + first = 0; + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + + if (machine_type("X86")) { + if (kt->flags2 & KASLR) { + if ((kt->flags2 & RELOC_AUTO) && !(kt->flags & RELOC_SET)) + derive_kaslr_offset(abfd, dynamic, from, + fromend, size, store); + } else if (!(kt->flags & RELOC_SET)) + kt->flags |= RELOC_FORCE; + } else if (machine_type("X86_64") || machine_type("ARM64") || + machine_type("S390X")) { + if ((kt->flags2 & RELOC_AUTO) && !(kt->flags & RELOC_SET)) + derive_kaslr_offset(abfd, dynamic, from, + fromend, size, store); + } else + kt->flags &= ~RELOC_SET; + + 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") && !machine_type("X86_64") && + !machine_type("ARM64") && !machine_type("S390X")) + 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/arm64 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; + } + + if (machine_type("X86_64")) { + /* + * There are some symbols which are outside of any section + * either because they are offsets or because they are absolute + * addresses. These should not be relocated. + */ + if (symval >= st->first_section_start && + symval <= st->last_section_end) { + return symval - kt->relocate; + } else { + return symval; + } + } else + 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; +} + +/* + * Get a symbol value from /proc/kallsyms. + */ +ulong +symbol_value_from_proc_kallsyms(char *symname) +{ + FILE *kp; + char buf[BUFSIZE]; + char *kallsyms[MAXARGS]; + ulong kallsym; + int found; + + if (!file_exists("/proc/kallsyms", NULL)) { + if (CRASHDEBUG(1)) + error(INFO, "cannot determine value of %s: " + "/proc/kallsyms does not exist\n\n", symname); + return BADVAL; + } + + if ((kp = fopen("/proc/kallsyms", "r")) == NULL) { + if (CRASHDEBUG(1)) + error(INFO, "cannot determine value of %s: " + "cannot open /proc/kallsyms\n\n", symname); + return BADVAL; + } + + found = FALSE; + while (!found && fgets(buf, BUFSIZE, kp) && + (parse_line(buf, kallsyms) == 3)) { + if (hexadecimal(kallsyms[0], 0) && + STREQ(kallsyms[2], symname)) { + kallsym = htol(kallsyms[0], RETURN_ON_ERROR, NULL); + found = TRUE; + break; + } + } + fclose(kp); + + return(found ? kallsym : BADVAL); +} + +/* + * 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*2]; + char name[BUFSIZE]; + char rodata[BUFSIZE*2]; + 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); + BCOPY(name, lm->mod_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) + first = (ulong)modsym->name; + if ((ulong)modsym->name > last) + 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 = 0; i < nsyms; i++) { + + modsym = (struct module_symbol *) + (modsymbuf + (i * sizeof(struct module_symbol))); + + 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; +} + +union kernel_symbol { + struct kernel_symbol_v1 { + unsigned long value; + const char *name; + } v1; + /* kernel 4.19 introduced relative symbol positioning */ + struct kernel_symbol_v2 { + int value_offset; + int name_offset; + } v2; + /* kernel 5.4 introduced symbol namespaces */ + struct kernel_symbol_v3 { + int value_offset; + int name_offset; + int namespace_offset; + } v3; + struct kernel_symbol_v4 { + unsigned long value; + const char *name; + const char *namespace; + } v4; +}; + +static size_t +kernel_symbol_type_init(void) +{ + if (MEMBER_EXISTS("kernel_symbol", "value") && + MEMBER_EXISTS("kernel_symbol", "name")) { + if (MEMBER_EXISTS("kernel_symbol", "namespace")) { + st->kernel_symbol_type = 4; + return (sizeof(struct kernel_symbol_v4)); + } else { + st->kernel_symbol_type = 1; + return (sizeof(struct kernel_symbol_v1)); + } + } + if (MEMBER_EXISTS("kernel_symbol", "value_offset") && + MEMBER_EXISTS("kernel_symbol", "name_offset")) { + if (MEMBER_EXISTS("kernel_symbol", "namespace_offset")) { + st->kernel_symbol_type = 3; + return (sizeof(struct kernel_symbol_v3)); + } else { + st->kernel_symbol_type = 2; + return (sizeof(struct kernel_symbol_v2)); + } + } + + error(FATAL, "kernel_symbol data structure has changed\n"); + + return 0; +} + +static ulong +modsym_name(ulong syms, union kernel_symbol *modsym, int i) +{ + switch (st->kernel_symbol_type) + { + case 1: + return (ulong)modsym->v1.name; + case 2: + return (syms + i * sizeof(struct kernel_symbol_v2) + + offsetof(struct kernel_symbol_v2, name_offset) + + modsym->v2.name_offset); + case 3: + return (syms + i * sizeof(struct kernel_symbol_v3) + + offsetof(struct kernel_symbol_v3, name_offset) + + modsym->v3.name_offset); + case 4: + return (ulong)modsym->v4.name; + } + + return 0; +} + +static ulong +modsym_value(ulong syms, union kernel_symbol *modsym, int i) +{ + switch (st->kernel_symbol_type) + { + case 1: + return (ulong)modsym->v1.value; + case 2: + return (syms + i * sizeof(struct kernel_symbol_v2) + + offsetof(struct kernel_symbol_v2, value_offset) + + modsym->v2.value_offset); + case 3: + return (syms + i * sizeof(struct kernel_symbol_v3) + + offsetof(struct kernel_symbol_v3, value_offset) + + modsym->v3.value_offset); + case 4: + return (ulong)modsym->v4.value; + } + + return 0; +} + +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; + union kernel_symbol *modsym; + size_t kernel_symbol_size; + 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"); + } + + kernel_symbol_size = kernel_symbol_type_init(); + + 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(kernel_symbol_size*nsyms); + readmem((ulong)syms, KVADDR, modsymbuf, + nsyms * kernel_symbol_size, + "module symbols", FAULT_ON_ERROR); + } + + for (i = first = last = 0; i < nsyms; i++) { + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + if (!first + || first > modsym_name(syms, modsym, i)) + first = modsym_name(syms, modsym, i); + if (modsym_name(syms, modsym, i) > last) + last = modsym_name(syms, modsym, i); + } + + 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 = 0; i < nsyms; i++) { + + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + + BZERO(buf1, BUFSIZE); + + if (strbuf) + strcpy(buf1, + &strbuf[modsym_name(syms, modsym, i) - first]); + else + read_string(modsym_name(syms, modsym, i), buf1, + BUFSIZE-1); + + if (strlen(buf1)) { + st->ext_module_symtable[mcnt].value = + modsym_value(syms, modsym, i); + 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(kernel_symbol_size * + ngplsyms); + readmem((ulong)gpl_syms, KVADDR, modsymbuf, + ngplsyms * kernel_symbol_size, + "module gpl symbols", FAULT_ON_ERROR); + } + + for (i = first = last = 0; i < ngplsyms; i++) { + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + if (!first + || first > modsym_name(gpl_syms, modsym, i)) + first = modsym_name(gpl_syms, modsym, i); + if (modsym_name(gpl_syms, modsym, i) > last) + last = modsym_name(gpl_syms, modsym, i); + } + + 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 = 0; i < ngplsyms; i++) { + + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + + BZERO(buf1, BUFSIZE); + + if (strbuf) + strcpy(buf1, + &strbuf[modsym_name(gpl_syms, modsym, i) - first]); + else + read_string(modsym_name(gpl_syms, modsym, i), buf1, + BUFSIZE-1); + + if (strlen(buf1)) { + st->ext_module_symtable[mcnt].value = + modsym_value(gpl_syms, modsym, i); + 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; + ulong st_size; +}; + +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; + if ((e32->st_info >= ' ') && (e32->st_info < 0x7f)) + ec->st_info = e32->st_info; + else if (e32->st_info == 0x02) + ec->st_info = 't'; + else if (e32->st_info == 0x12) + ec->st_info = 'T'; + else + ec->st_info = '?'; + ec->st_size = (ulong)e32->st_size; +} + +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; + if ((e64->st_info >= ' ') && (e64->st_info < 0x7f)) + ec->st_info = e64->st_info; + else if (e64->st_info == 0x02) + ec->st_info = 't'; + else if (e64->st_info == 0x12) + ec->st_info = 'T'; + else + ec->st_info = '?'; + ec->st_size = (ulong)e64->st_size; +} + +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/ARM64 we have linker mapping symbols like '$a' + * or '$x' for ARM64, and '$d'. + * Make sure that these don't end up into our symbol list. + */ + if ((machine_type("ARM") || machine_type("ARM64")) && + !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)) && is_symbol_text(sp)) + return TRUE; + + for (sp = st->symtable; sp < st->symend; sp++) { + if (!is_symbol_text(sp)) + 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 (kt->flags2 & KASLR) { + start += (kt->relocate * -1); + end += (kt->relocate * -1); + } + + if ((value >= start) && (value < end)) + return TRUE; + } + } + } + + if ((sp = value_search(value, NULL)) && is_symbol_text(sp)) + return TRUE; + + if (NO_MODULES() || !(st->flags & MODULE_SYMS)) + 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); +} + +int +is_symbol_text(struct syment *sp) +{ + if ((sp->type == 'T') || (sp->type == 't')) + return TRUE; + + if ((sp->type == 'W') || (sp->type == 'w')) { + if ((sp->value >= kt->stext) && + (sp->value < kt->etext)) + return TRUE; + } + + return 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; +} + +/* + * For a given kernel virtual address, request that gdb return + * the address range of the containing function. For module + * text addresses, its debuginfo data must be loaded. + */ +int +get_text_function_range(ulong vaddr, ulong *low, ulong *high) +{ + struct syment *sp; + struct gnu_request gnu_request, *req = &gnu_request; + struct load_module *lm; + ulong size; + + if (!(sp = value_search(vaddr, NULL))) + return FALSE; + + if (module_symbol(vaddr, NULL, &lm, NULL, 0)) { + if (kallsyms_module_function_size(sp, lm, &size)) { + *low = sp->value; + *high = sp->value + size; + return TRUE; + } + } + + BZERO(req, sizeof(struct gnu_request)); + req->command = GNU_GET_FUNCTION_RANGE; + req->pc = sp->value; + req->name = sp->name; + gdb_interface(req); + if (req->flags & GNU_COMMAND_FAILED) + return FALSE; + + if ((vaddr < req->addr) || (vaddr >= req->addr2)) + return FALSE; + + *low = req->addr; + *high = req->addr2; + + return TRUE; +} + +/* + * Get the text size of a module function from kallsyms. + */ +static int +kallsyms_module_function_size(struct syment *sp, struct load_module *lm, ulong *size) +{ + int i; + ulong nksyms, ksymtab, st_size; + char *ptr, *module_buf, *module_buf_init, *modbuf, *locsymtab; + struct elf_common elf_common, *ec; + + if (!(lm->mod_flags & MOD_KALLSYMS) || !(kt->flags & KALLSYMS_V2)) + return FALSE; + + if (THIS_KERNEL_VERSION >= LINUX(5,0,0)) /* st_size not useable */ + return FALSE; + + module_buf = GETBUF(lm->mod_size); + modbuf = module_buf + (lm->module_struct - lm->mod_base); + + if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size, + "module (kallsyms)", RETURN_ON_ERROR|QUIET)) { + FREEBUF(module_buf); + return FALSE; + } + + 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)) { + FREEBUF(module_buf_init); + module_buf_init = NULL; + } + } else + module_buf_init = NULL; + + 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)) { + FREEBUF(module_buf); + if (module_buf_init) + FREEBUF(module_buf_init); + return FALSE; + } + + if (IN_MODULE(ksymtab, lm)) + locsymtab = module_buf + (ksymtab - lm->mod_base); + else + locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr); + + st_size = 0; + ec = &elf_common; + BZERO(&elf_common, sizeof(struct elf_common)); + + 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 (sp->value == ec->st_value) { + if (CRASHDEBUG(1)) + fprintf(fp, "kallsyms_module_function_size: " + "st_value: %lx st_size: %ld\n", + ec->st_value, ec->st_size); + st_size = ec->st_size; + break; + } + } + + if (module_buf_init) + FREEBUF(module_buf_init); + FREEBUF(module_buf); + + if (st_size) { + *size = st_size; + return TRUE; + } + + return FALSE; +} + +/* + * "help -s" output + */ +void +dump_symbol_table(void) +{ + int i, s, cnt, tot; + struct load_module *lm; + struct syment *sp; + struct downsized *ds; + 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, " first_section_start: %lx\n", st->first_section_start); + fprintf(fp, " last_section_end: %lx\n", st->last_section_end); + + fprintf(fp, " _stext_vmlinux: %lx ", st->_stext_vmlinux); + if (st->_stext_vmlinux == UNINITIALIZED) + fprintf(fp, "(UNINITIALIZED)\n"); + else if (st->_stext_vmlinux == 0) + fprintf(fp, "(unused)\n"); + else + fprintf(fp, "\n"); + + if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO() || VMSS_DUMPFILE()) { + fprintf(fp, "divide_error_vmlinux: %lx\n", st->divide_error_vmlinux); + fprintf(fp, " idt_table_vmlinux: %lx\n", st->idt_table_vmlinux); + fprintf(fp, "saved_command_line_vmlinux: %lx\n", st->saved_command_line_vmlinux); + fprintf(fp, " pti_init_vmlinux: %lx\n", st->pti_init_vmlinux); + fprintf(fp, " kaiser_init_vmlinux: %lx\n", st->kaiser_init_vmlinux); + } else { + fprintf(fp, "divide_error_vmlinux: (unused)\n"); + fprintf(fp, " idt_table_vmlinux: (unused)\n"); + fprintf(fp, "saved_command_line_vmlinux: (unused)\n"); + fprintf(fp, " pti_init_vmlinux: (unused)\n"); + fprintf(fp, " kaiser_init_vmlinux: (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); + } + + fprintf(fp, " loaded_objfile: %lx\n", (ulong)lm->loaded_objfile); + + 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)); + } + fprintf(fp, "\n downsized: "); + if (st->downsized.name) { + for (ds = &st->downsized, cnt = 0; ds->name; ds = ds->next) + fprintf(fp, "%s%s", cnt++ ? ", " : "", ds->name); + fprintf(fp, "\n"); + } else + fprintf(fp, "(none)\n"); + + fprintf(fp, " kernel_symbol_type: v%d\n", st->kernel_symbol_type); +} + + +/* + * 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; + + case EM_MIPS: + if (machine_type_mismatch(file, "MIPS", NULL, 0)) + goto bailout; + break; + + case EM_SPARCV9: + if (machine_type_mismatch(file, "SPARC64", 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; + } else + return FALSE; + +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 XZ (3) + +#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 (!memcmp(header, "\xfd""7zXZ", 6)) { + 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 = XZ; + } + + 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; + case XZ: + sprintf(command, "%s -c %s > %s", + file_exists("/bin/unxz", NULL) ? + "/bin/unxz" : "/usr/bin/unxz", + 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) && is_kernel(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") || + machine_type("MIPS")) + 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_MIPS: + if (machine_type("MIPS")) + 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") || machine_type("ARM64")) + return TRUE; + break; + + case EM_S390: + if (machine_type("S390X")) + return TRUE; + break; + + case EM_AARCH64: + if (machine_type("ARM64")) + return TRUE; + break; + + case EM_SPARCV9: + if (machine_type("SPARC64")) + 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; + char *namep; + + 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; + if (pc->namelist_orig) { + namep = pc->namelist_debug_orig; + pc->namelist_debug_orig = pc->namelist_orig; + pc->namelist_orig = namep; + } + 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 + if ((bfd = bfd_openr(filename, NULL)) == NULL) + return FALSE; + + if (!bfd_check_format_matches(bfd, bfd_object, NULL)) { + 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() && + (!symbol_exists(args[optind]) && 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; + lm = NULL; + + if (NO_LINE_NUMBERS() || !is_kernel_text(addr)) + return(buf); + + if (module_symbol(addr, NULL, &lm, NULL, 0)) { + if (!(lm->mod_flags & MOD_LOAD_SYMS)) + return(buf); + } else if (kt->flags2 & KASLR) + addr -= (kt->relocate * -1); + + 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 (lm && lm->loaded_objfile) + req->lm = lm; + 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 = strstr(buf, "/./arch/"))) + *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. + */ +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() || !(st->flags & MODULE_SYMS)) + 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 (machine_type("ARM64") && + IN_MODULE_PERCPU(sp->value, lm) && + !IN_MODULE_PERCPU(value, lm)) + continue; + + 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; + + /* + * Avoid "SyS" and "compat_SyS" kernel syscall + * aliases by returning the real symbol name, + * which is the next symbol in the list. + */ + if ((STRNEQ(sp->name, "SyS_") || + STRNEQ(sp->name, "compat_SyS_")) && + ((spnext = sp+1) < st->symend) && + (spnext->value == value)) + sp = spnext; + + /* + * If any of the special text region starting address + * delimiters declared in vmlinux.lds.S match the + * first "real" text symbol in the region, return + * that (next) one instead. + */ + if (strstr_rightmost(sp->name, "_text_start") && + ((spnext = sp+1) < st->symend) && + (spnext->value == value)) + sp = spnext; + + 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 MEMBER_TYPE_NAME(X,Y) datatype_info((X), (Y), MEMBER_TYPE_NAME_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 (dm == MEMBER_TYPE_NAME_REQUEST) ? 0 : -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 != MEMBER_TYPE_NAME_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 (dm == MEMBER_TYPE_NAME_REQUEST) ? 0 : -1; + + if (dm == MEMBER_SIZE_REQUEST) + return member_size; + else if (dm == MEMBER_TYPE_REQUEST) + return member_typecode; + else if (dm == MEMBER_TYPE_NAME_REQUEST) { + if (req->member_main_type_name) + return (ulong)req->member_main_type_name; + else if (req->member_main_type_tag_name) + return (ulong)req->member_main_type_tag_name; + else if (req->member_target_type_name) + return (ulong)req->member_target_type_name; + else if (req->member_target_type_tag_name) + return (ulong)req->member_target_type_tag_name; + else + return 0; + } 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); + } + + set_temporary_radix(radix, &restore_radix); + + open_tmpfile(); + print_struct(dm->name, addr); + + if (MEMBER_EXISTS(dm->name, dm->member)) + parse_for_member(dm, PARSE_FOR_DATA); + else + parse_for_member_extended(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*2]; + 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, "%s", p1+2); + } else + fprintf(pc->saved_fp, " %s", buf1); + } + + close_tmpfile2(); + + return TRUE; +} + +static void +cmd_datatype_common(ulong flags) +{ + int c; + ulong addr, aflag; + char *cpuspec; + ulong *cpus; + struct syment *sp; + ulong list_head_offset; + int count; + 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]; + char *typename; + + dm = &datatype_member; + count = 0xdeadbeef; + aflag = addr = 0; + list_head_offset = 0; + argc_members = 0; + radix = restore_radix = 0; + separator = members = NULL; + cpuspec = NULL; + cpus = NULL; + + while ((c = getopt(argcnt, args, "pxdhfuc:rvol:")) != EOF) { + switch (c) + { + case 'p': + flags |= DEREF_POINTERS; + 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': + flags |= SHOW_RAW_DATA; + 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 ((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 (!aflag) { + cpuspec = strchr(args[optind], ':'); + if (cpuspec) + *cpuspec++ = NULLCHAR; + } + + if (clean_arg() && IS_A_NUMBER(args[optind])) { + if (aflag) + count = stol(args[optind], + FAULT_ON_ERROR, NULL); + else if (cpuspec) { + if (pc->curcmd_flags & MEMTYPE_FILEADDR) + error(FATAL, "-f option cannot be used with percpu\n"); + addr = htol(args[optind], FAULT_ON_ERROR, NULL); + aflag++; + } 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]))) { + if (cpuspec && !is_percpu_symbol(sp)) { + error(WARNING, + "%s is not percpu; cpuspec ignored.\n", + sp->name); + cpuspec = NULL; + } + if (cpuspec) { + if ((typename = expr_type_name(sp->name))) { + if (LASTCHAR(typename) == '*') + error(WARNING, + "percpu symbol \"%s\" is of type pointer\n", + sp->name); + FREEBUF(typename); + } + } + 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; + } + } + + if (cpuspec) { + cpus = get_cpumask_buf(); + if (STREQ(cpuspec, "")) + SET_BIT(cpus, CURRENT_CONTEXT()->processor); + else + make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL); + } + + optind = optind_save; + + if (count == 0xdeadbeef) + count = 1; + else if (!aflag) + error(FATAL, "no kernel virtual address argument entered\n"); + + if ((flags & DEREF_POINTERS) && !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 (! (flags & (STRUCT_REQUEST|UNION_REQUEST)) ) { + flags |= dm->type; + if (!(flags & (UNION_REQUEST|STRUCT_REQUEST))) + error(FATAL, "invalid argument"); + } else if ( (flags &(STRUCT_REQUEST|UNION_REQUEST)) != dm->type) { + error(FATAL, "data type mismatch: %s is not a %s\n", + dm->name, flags & UNION_REQUEST ? "union" : "struct"); + } + + 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"); + + set_temporary_radix(radix, &restore_radix); + + /* + * No address was passed -- dump the structure/member declaration. + */ + if (!aflag) { + if (argc_members && + !member_to_datatype(memberlist[0], dm, + ANON_MEMBER_QUERY)) + error(FATAL, "invalid data structure reference: %s.%s\n", + dm->name, memberlist[0]); + do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); + } else if (cpus) { + for (c = 0; c < kt->cpus; c++) { + ulong cpuaddr; + + if (!NUM_IN_BITMAP(cpus, c)) + continue; + + cpuaddr = addr + kt->__per_cpu_offset[c]; + + fprintf(fp, "[%d]: ", c); + + if (hide_offline_cpu(c)) { + fprintf(fp, "[OFFLINE]\n"); + continue; + } + + fprintf(fp, "%lx\n", cpuaddr); + do_datatype_addr(dm, cpuaddr , count, + flags, memberlist, argc_members); + } + } else + do_datatype_addr(dm, addr, count, flags, + memberlist, argc_members); + + restore_current_radix(restore_radix); + +freebuf: + if (argc_members) { + FREEBUF(structname); + FREEBUF(members); + } + + if (cpus) + FREEBUF(cpus); +} + +static void +do_datatype_addr(struct datatype_member *dm, ulong addr, int count, + ulong flags, char **memberlist, int argc_members) +{ + int i, c; + long 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) { + /* This call works fine with fields + * of the second, third, ... levels. + * There is no need to fix it + */ + if (!member_to_datatype(memberlist[i], dm, + ANON_MEMBER_QUERY)) + error(FATAL, "invalid data structure reference: %s.%s\n", + dm->name, memberlist[i]); + if (flags & SHOW_RAW_DATA) + error(FATAL, + "member-specific output not allowed with -r\n"); + } + + /* + * Display member addresses or data + */ + if (flags & SHOW_OFFSET) { + dm->vaddr = addr; + do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); + } else if (flags & SHOW_RAW_DATA) + raw_data_dump(addr, len, flags & STRUCT_VERBOSE); + else if ((flags & DEREF_POINTERS) && !dm->member) { + print_struct_with_dereference(addr, dm, flags); + } else { + if (dm->member) + open_tmpfile(); + + if (flags & UNION_REQUEST) + print_union(dm->name, addr); + else if (flags & STRUCT_REQUEST) + print_struct(dm->name, addr); + + if (dm->member) { + if (!((flags & DEREF_POINTERS) && + dereference_pointer(addr, dm, flags))) { + if (count_chars(dm->member, '.') || count_chars(dm->member, '[')) + parse_for_member_extended(dm, PARSE_FOR_DATA); + else + parse_for_member(dm, PARSE_FOR_DATA); + } + close_tmpfile(); + } + + } + } while (++i < argc_members); + } +} + +int +is_string(char *structure, char *member) +{ + int retval; + char *t; + char buf[BUFSIZE]; + + retval = FALSE; + open_tmpfile(); + whatis_datatype(structure, STRUCT_REQUEST, pc->tmpfile); + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + if (!(t = strstr(buf, "char "))) + continue; + t += 5; + if (*t == '*') + t++; + if (t != strstr(t, member)) + continue; + t += strlen(member); + if (*t == ';' || *t == '[') { + retval = TRUE; + break; + } + } + + close_tmpfile(); + + return retval; +} + + +/* + * 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); + + if (dm->member && count_chars(dm->member, '.')) + error(FATAL, "invalid data structure reference: %s.%s\n", + dm->name, dm->member); + + 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, "%s", 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; + + if (member_to_datatype(p1 + 1, dm, flags)) + 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)); +} + +static int +member_to_datatype(char *s, struct datatype_member *dm, ulong flags) +{ + dm->member = s; + + if ((dm->member_offset = MEMBER_OFFSET(dm->name, s)) >= 0) + return TRUE; + + if ((flags & ANON_MEMBER_QUERY) && + ((dm->member_offset = ANON_MEMBER_OFFSET(dm->name, s)) >= 0)) + return TRUE; + + return FALSE; +} + +/* + * 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"); +} + +struct type_request { + int cnt; /* current number of entries in types array */ + int idx; /* index to next entry in types array */ + struct type_info { /* dynamically-sized array of collected types */ + char *name; + ulong size; + } *types; +}; + +static int +compare_size_name(const void *va, const void *vb) { + struct type_info *a, *b; + + a = (struct type_info *)va; + b = (struct type_info *)vb; + + if (a->size == b->size) + return strcmp(a->name, b->name); + else + return a->size < b->size ? -1 : 1; +} + +static void +append_struct_symbol (struct type_request *treq, struct gnu_request *req) +{ + int i; + long s; + + for (i = 0; i < treq->idx; i++) + if (treq->types[i].name == req->name) + break; + + if (i < treq->idx) // We've already collected this type + return; + + if (treq->idx == treq->cnt) { + s = sizeof(struct type_info) * treq->cnt; + RESIZEBUF(treq->types, s, s * 3); + treq->cnt *= 3; + } + + treq->types[treq->idx].name = req->name; + treq->types[treq->idx].size = req->length; + treq->idx++; +} + +static void +request_types(ulong lowest, ulong highest, char *member_name) +{ + int i, len; + char buf[BUFSIZE]; + struct type_request typereq; + struct gnu_request request = {0}; + + typereq.idx = 0; + typereq.cnt = 16; + typereq.types = (void *)GETBUF(16 * sizeof(struct type_info)); + +#if defined(GDB_5_3) || defined(GDB_6_0) || defined(GDB_6_1) || defined(GDB_7_0) + error(FATAL, "-r option not supported with this version of gdb\n"); +#else + request.type_name = member_name; +#endif + + while (!request.global_iterator.finished) { + request.command = GNU_GET_NEXT_DATATYPE; + gdb_interface(&request); + if (highest && + !(lowest <= request.length && request.length <= highest)) + continue; + + if (member_name) { + request.command = GNU_LOOKUP_STRUCT_CONTENTS; + gdb_interface(&request); + if (!request.value) + continue; + } + + append_struct_symbol(&typereq, &request); + } + + qsort(typereq.types, typereq.idx, sizeof(struct type_info), compare_size_name); + + if (typereq.idx == 0) + fprintf(fp, "(none found)\n"); + else { + sprintf(buf, "%ld", typereq.types[typereq.idx-1].size); + len = MAX(strlen(buf), strlen("SIZE")); + fprintf(fp, "%s TYPE\n", + mkstring(buf, len, RJUST, "SIZE")); + + for (i = 0; i < typereq.idx; i++) + fprintf(fp, "%s %s\n", + mkstring(buf, len, RJUST|LONG_DEC, + MKSTR(typereq.types[i].size)), + typereq.types[i].name); + } + + FREEBUF(typereq.types); +} + +/* + * 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. + * 6. If the -r and -m are given, then the structures/unions of specified size + * and/or contain a member type. + */ +void +cmd_whatis(void) +{ + int c, do_request; + struct datatype_member datatype_member, *dm; + struct syment *sp; + char buf[BUFSIZE], *pl, *ph, *member; + long len; + ulong lowest, highest; + ulong flags; + + dm = &datatype_member; + flags = 0; + lowest = highest = 0; + pl = buf; + member = NULL; + do_request = FALSE; + + while ((c = getopt(argcnt, args, "om:r:")) != EOF) { + switch(c) + { + case 'o': + flags |= SHOW_OFFSET; + break; + + case 'm': + member = optarg; + do_request = TRUE; + break; + + case 'r': + strncpy(buf, optarg, 15); + if ((ph = strstr(buf, "-")) != NULL) + *(ph++) = '\0'; + highest = lowest = stol(pl, FAULT_ON_ERROR, NULL); + if (ph) + highest = stol(ph, FAULT_ON_ERROR, NULL); + do_request = TRUE; + break; + + default: + argerrs++; + break; + } + } + + if (!argerrs && do_request) { + request_types(lowest, highest, member); + return; + } + + 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, "%s", 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; + int do_load_module_filter; + char buf1[BUFSIZE]; + char *cpuspec; + + do_load_module_filter = 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); + + cpuspec = strrchr(args[optind], ':'); + if (cpuspec) + *cpuspec++ = NULLCHAR; + + sp = NULL; + if ((sp = symbol_search(args[optind])) && !args[optind+1]) { + if ((percpu_sp = per_cpu_symbol_search(args[optind])) && + display_per_cpu_info(percpu_sp, radix, cpuspec)) + return; + 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, radix, cpuspec)) + return; + else if (st->flags & LOAD_MODULE_SYMS) + do_load_module_filter = TRUE; + + if (cpuspec) { + if (sp) + error(WARNING, "%s is not percpu; cpuspec ignored.\n", + sp->name); + else + /* maybe a valid C expression (e.g. ':') */ + *(cpuspec-1) = ':'; + } + + process_gdb_output(concat_args(buf1, 0, TRUE), radix, + sp ? sp->name : NULL, do_load_module_filter); +} + +static void +process_gdb_output(char *gdb_request, unsigned radix, + const char *leader, int do_load_module_filter) +{ + unsigned restore_radix; + int success; + char buf1[BUFSIZE]; + char *p1; + + if (leader || do_load_module_filter) + open_tmpfile(); + + set_temporary_radix(radix, &restore_radix); + + success = gdb_pass_through(gdb_request, NULL, GNU_RETURN_ON_ERROR); + + if (success && (leader || do_load_module_filter)) { + int firstline; + + if (leader) { + fprintf(pc->saved_fp, "%s = ", leader); + 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, "%s", 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", gdb_request); +} + +/* + * Get the type of an expression using gdb's "whatis" command. + * The returned string is dynamically allocated, and it should + * be passed to FREEBUF() when no longer needed. + * Return NULL if the type cannot be determined. + */ +static char * +expr_type_name(const char *expr) +{ + char buf[BUFSIZE], *p; + + open_tmpfile(); + sprintf(buf, "whatis %s", expr); + if (!gdb_pass_through(buf, fp, GNU_RETURN_ON_ERROR)) { + close_tmpfile(); + return NULL; + } + + rewind(pc->tmpfile); + while (fgets(buf, BUFSIZE, pc->tmpfile) && !STRNEQ(buf, "type = ")) + ; + p = feof(pc->tmpfile) ? NULL : buf + strlen("type = "); + close_tmpfile(); + + if (p) { + size_t len = strlen(clean_line(p)); + /* GDB reports unknown types as <...descriptive text...> */ + if (p[0] == '<' && p[len-1] == '>') + return NULL; + return strcpy(GETBUF(len + 1), p); + } + return NULL; +} + +/* + * 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 radix, char *cpuspec) +{ + ulong *cpus; + int c; + ulong addr; + char buf[BUFSIZE]; + char leader[sizeof("&per_cpu(") + strlen(sp->name) + + sizeof(", " STR(UINT_MAX) ")")]; + char *typename; + int do_load_module_filter; + + 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; + + if (cpuspec) { + cpus = get_cpumask_buf(); + if (STREQ(cpuspec, "")) + SET_BIT(cpus, CURRENT_CONTEXT()->processor); + else + make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL); + } else + cpus = NULL; + + typename = expr_type_name(sp->name); + + if (!cpus) { + fprintf(fp, "PER-CPU DATA TYPE:\n "); + if (!typename) + fprintf(fp, "[undetermined type] %s;\n", sp->name); + else + whatis_variable(sp); + + fprintf(fp, "PER-CPU ADDRESSES:\n"); + } + + do_load_module_filter = + module_symbol(sp->value, NULL, NULL, NULL, *gdb_output_radix); + + for (c = 0; c < kt->cpus; c++) { + if (hide_offline_cpu(c)) { + fprintf(fp, "cpu %d is OFFLINE\n", c); + continue; + } + + if (cpus && !NUM_IN_BITMAP(cpus, c)) + continue; + addr = sp->value + kt->__per_cpu_offset[c]; + if (!cpus) + fprintf(fp, " [%d]: %lx\n", c, addr); + else if (typename) { + snprintf(buf, sizeof buf, "p *(%s*) 0x%lx", + typename, addr); + sprintf(leader, "per_cpu(%s, %u)", + sp->name, c); + process_gdb_output(buf, radix, leader, + do_load_module_filter); + } else { + snprintf(buf, sizeof buf, "p (void*) 0x%lx", addr); + sprintf(leader, "&per_cpu(%s, %u)", + sp->name, c); + process_gdb_output(buf, radix, leader, + do_load_module_filter); + } + } + + if (typename) + FREEBUF(typename); + if (cpus) + FREEBUF(cpus); + + 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_downsized(s)) + pc->curcmd_flags |= PARTIAL_READ_OK; + + 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"); + + pc->curcmd_flags &= ~PARTIAL_READ_OK; +} + + +/* + * 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_downsized(s)) + pc->curcmd_flags |= PARTIAL_READ_OK; + + 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); + + pc->curcmd_flags &= ~PARTIAL_READ_OK; +} + +/* + * 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. + */ +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++ ? "|" : ""); + if (flags & SHOW_RAW_DATA) + fprintf(ofp, "%sSHOW_RAW_DATA", others++ ? "|" : ""); + if (flags & DEREF_POINTERS) + fprintf(ofp, "%sDEREF_POINTERS", 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; + } +} + +struct struct_elem { + char field_name[BUFSIZE]; + unsigned char field_len; + char value[BUFSIZE]; + unsigned char is_array_root:1; + + struct struct_elem *parent; + struct struct_elem *inner; + struct struct_elem *next; + struct struct_elem *prev; +}; + +#define ALLOC_XXX_ELEMENT(xxx, clone_parent) \ +{ \ + if (current == NULL) { \ + error(FATAL, "Internal error while parsing structure %s\n", dm->name); \ + } \ + current->xxx = (struct struct_elem *)GETBUF(sizeof(struct struct_elem)); \ + if (clone_parent) current->xxx->parent = current->parent; \ + else current->xxx->parent = current; \ + current = current->xxx; \ +} + +#define ALLOC_INNER_ELEMENT { ALLOC_XXX_ELEMENT(inner, 0) } +#define ALLOC_NEXT_ELEMENT { ALLOC_XXX_ELEMENT(next, 1) } + +static void +free_structure(struct struct_elem *p) +{ + if (p == NULL) + return; + free_structure(p->inner); + free_structure(p->next); + FREEBUF(p); +} + +static unsigned char +is_right_brace(const char *b) +{ + unsigned char r = 0; + for (; *b == ' '; b++); + if (*b == '}') { + b++; + r = 1; + if (*b == '}') { + r = 2; + b++; + } + } + + if (*b == ',') + b++; + + if (*b == '\0') + return r; + else + return 0; +} + +static struct struct_elem * +find_node(struct struct_elem *s, char *n) +{ + char *p, *b, *e; + struct struct_elem *t = s; + unsigned i; + + if (('\0' == *n) || (s == NULL)) + return s; + + /* [n .. p) - struct member with index*/ + if ((p = strstr(n, ".")) == NULL) + p = n + strlen(n); + + /* [n .. b) - struct member without index*/ + for (b = n; (b < p) && (*b != '['); b++); + + /* s - is the current level of items [s, s->next, ..., s->...->next] */ + for (; s; s = s->next) { + if (*s->field_name == '\0') + continue; + + /* `field_name` doesn't match */ + if (((b - n) != s->field_len) || memcmp(s->field_name, n, b - n)) + continue; + + // For case like `pids.node` where pids is an array + if (s->is_array_root && *b != '[' && *p) + return NULL; + + if (*b == '[') { /* Array */ + i = strtol(b + 1, &e, 10); + /* Check if the current node is array and + * we've parsed index more or less correctly + */ + if (!(s->is_array_root && *e == ']' && (e != b + 1))) + return NULL; + + /* Look for the i-th element */ + for (s = s->inner; s && i; s = s->next, i--); + if (i || (s == NULL)) + return NULL; + } + + /* Ok. We've found node, it's - the last member + * in our search string, let's return it. + */ + if ('\0' == *p) + return s; + else + return find_node(s->inner, p + 1); + } + + // We haven't found any field. + // Might happen, we've encountered anonymous structure + // of union. Lets try every record without `field_name` + s = t; + t = NULL; + for (; s; s = s->next) { + if (*s->field_name) + continue; + t = find_node(s->inner, n); + if (t) + break; + } + + return t; +} + +static void +dump_node(struct struct_elem *p, char *f, unsigned char level, unsigned char is_array) +{ + unsigned int i; + if (p == NULL) + return; + do { +#define PUT_INDENTED_STRING(m, ...) { \ + for (i = 0; i++ < 2 + 2 * (m * is_array + level); fprintf(pc->saved_fp, " ")); \ + fprintf(pc->saved_fp, __VA_ARGS__); } + + if (p->inner) { + if (*p->field_name) { + PUT_INDENTED_STRING(1, "%s = %s\n", f ? f : p->field_name, + p->inner->is_array_root ? "{{" : "{"); + } else { + if (f) /* For union */ + PUT_INDENTED_STRING(1, "%s = ", f); + PUT_INDENTED_STRING(1, "%s\n", p->inner->is_array_root ? "{{" : "{"); + } + dump_node(p->inner, NULL, is_array + level + 1, p->inner->is_array_root); + PUT_INDENTED_STRING(1, "%s%s\n", p->inner->is_array_root ? "}}" : "}", + (p->next && !p->next->is_array_root) ? "," : ""); + } else { + PUT_INDENTED_STRING(1, "%s = %s%s", f ? f : p->field_name, + p->value, p->next ? ",\n" : "\n"); + } + if (level) { + p = p->next; + if (p && p->is_array_root) + PUT_INDENTED_STRING(0, "}, {\n"); + } + } while (p && level); +} + +void +parse_for_member_extended(struct datatype_member *dm, + ulong __attribute__ ((unused)) flag) +{ + struct struct_elem *i, *current = NULL, *root = NULL; + + char buf[BUFSIZE]; + char *p, *p1; + char *s_e; // structure_element + unsigned int len; + unsigned char trailing_comma, braces, found = 0; + + rewind(pc->tmpfile); + + root = (struct struct_elem *)GETBUF(sizeof(struct struct_elem)); + current = root; + ALLOC_INNER_ELEMENT; + + while (fgets(buf, BUFSIZE, pc->tmpfile)) { + len = strlen(buf) - 1; + for (; buf[len] <= ' '; buf[len--] = '\0'); + if ((trailing_comma = (buf[len] == ','))) + buf[len--] = '\0'; + + if ((braces = is_right_brace(buf))) { + for (; braces && current; braces--) + current = current->parent; + + if ((current->parent == root) || trailing_comma) + ALLOC_NEXT_ELEMENT; + continue; + } + + for (p1 = buf; *p1 == ' '; p1++); + + if ((p = strstr(buf, " = ")) != NULL) + s_e = p + 3; + else + s_e = p1; + + /* + * After that we have pointers: + * foobar = bazzz + * -----^ ^ ^ + * | ------| | + * | | | + * p1 p s_e + * + * OR + * + * { + * ^ + * | + * --------- + * | | + * p1 s_e + * + * p == NULL + * + * + * p1 - the first non-whitespace symbol in line + * p - pointer to line ' = '. + * If not NULL, there is identifier + * s_e - element of structure (brace / double brace / array separator / scalar) + * + */ + + if (current && p && (p - p1 < BUFSIZE)) { +// strncpy(current->field_name, p1, p - p1); (NOTE: gcc-9.0.1 emits [-Wstringop-truncation] warning) + current->field_len = p - p1; + memcpy(current->field_name, p1, current->field_len); + current->field_name[current->field_len] = '\0'; + } + + if ( p && (*s_e != '{' || (*s_e == '{' && buf[len] == '}') )) { + /* Scalar or one-line array + * next = 0x0 + * or + * files = {0x0, 0x0} + */ + strcpy(current->value, s_e); + if (trailing_comma) ALLOC_NEXT_ELEMENT; + } + else if ( *s_e == '{' ) { + ALLOC_INNER_ELEMENT; + if (*(s_e + 1) == '{') { + current->parent->is_array_root = 1; + ALLOC_INNER_ELEMENT; + } + } + else if (strstr(s_e, "}, {")) { + /* Next array element */ + current = current->parent; + ALLOC_NEXT_ELEMENT; + ALLOC_INNER_ELEMENT; + } + else if (buf == (p = strstr(buf, "struct "))) { + p += 7; /* strlen "struct " */ + p1 = strstr(buf, " {"); + strncpy(current->field_name, p, p1 - p); + ALLOC_INNER_ELEMENT; + } + } + + for (i = root->inner; i; i = i->next) { + if ((current = find_node(i->inner, dm->member))) { + dump_node(current, dm->member, 0, 0); + found = 1; + break; + } + } + + free_structure(root); + + if (!found) + error(INFO, "invalid data structure member reference: %s\n", + dm->member); +} + +/* + * 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, "%s", &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, "height_to_maxnodes")) + lenptr = &array_table.height_to_maxnodes; + 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; + else if (STREQ(s, "task_struct.rlim")) + lenptr = &array_table.task_struct_rlim; + else if (STREQ(s, "signal_struct.rlim")) + lenptr = &array_table.signal_struct_rlim; + else if (STREQ(s, "vm_numa_stat")) + lenptr = &array_table.vm_numa_stat; + + 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, " inactive_task_frame_ret_addr: %ld\n", + OFFSET(inactive_task_frame_ret_addr)); + 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_thread_reg29: %ld\n", + OFFSET(task_struct_thread_reg29)); + fprintf(fp, " task_struct_thread_reg31: %ld\n", + OFFSET(task_struct_thread_reg31)); + fprintf(fp, " task_struct_thread_context_fp: %ld\n", + OFFSET(task_struct_thread_context_fp)); + fprintf(fp, " task_struct_thread_context_sp: %ld\n", + OFFSET(task_struct_thread_context_sp)); + fprintf(fp, " task_struct_thread_context_pc: %ld\n", + OFFSET(task_struct_thread_context_pc)); + 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_rss_stat: %ld\n", + OFFSET(task_struct_rss_stat)); + fprintf(fp, " task_rss_stat_count: %ld\n", + OFFSET(task_rss_stat_count)); + fprintf(fp, " task_struct_pids: %ld\n", + OFFSET(task_struct_pids)); + fprintf(fp, " task_struct_pid_links: %ld\n", + OFFSET(task_struct_pid_links)); + 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_stack: %ld\n", + OFFSET(task_struct_stack)); + 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, " task_struct_policy: %ld\n", + OFFSET(task_struct_policy)); + + 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_namespace_idr: %ld\n", + OFFSET(pid_namespace_idr)); + fprintf(fp, " idr_idr_rt: %ld\n", + OFFSET(idr_idr_rt)); + 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_mm_count: %ld\n", + OFFSET(mm_struct_mm_count)); + 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, " kernel_symbol_value: %ld\n", + OFFSET(kernel_symbol_value)); + fprintf(fp, " module_taints: %ld\n", + OFFSET(module_taints)); + fprintf(fp, " module_license_gplok: %ld\n", + OFFSET(module_license_gplok)); + fprintf(fp, " module_gpgsig_ok: %ld\n", + OFFSET(module_gpgsig_ok)); + fprintf(fp, " tnt_bit: %ld\n", OFFSET(tnt_bit)); + fprintf(fp, " tnt_true: %ld\n", OFFSET(tnt_true)); + fprintf(fp, " tnt_false: %ld\n", OFFSET(tnt_false)); + fprintf(fp, " tnt_mod: %ld\n", OFFSET(tnt_mod)); + + 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_slab_page: %ld\n", + OFFSET(page_slab_page)); + fprintf(fp, " page_first_page: %ld\n", + OFFSET(page_first_page)); + fprintf(fp, " page_freelist: %ld\n", + OFFSET(page_freelist)); + fprintf(fp, " page_s_mem: %ld\n", + OFFSET(page_s_mem)); + fprintf(fp, " page_active: %ld\n", + OFFSET(page_active)); + fprintf(fp, " page_compound_head: %ld\n", + OFFSET(page_compound_head)); + + fprintf(fp, " trace_print_flags_mask: %ld\n", + OFFSET(trace_print_flags_mask)); + fprintf(fp, " trace_print_flags_name: %ld\n", + OFFSET(trace_print_flags_name)); + + 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, " address_space_page_tree: %ld\n", + OFFSET(address_space_page_tree)); + 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, " irq_desc_irq_data: %ld\n", + OFFSET(irq_desc_irq_data)); + 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, " dentry_d_sb: %ld\n", + OFFSET(dentry_d_sb)); + 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_red_left_pad: %ld\n", + OFFSET(kmem_cache_red_left_pad)); + 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_cpu_partial: %ld\n", + OFFSET(kmem_cache_cpu_partial)); + fprintf(fp, " kmem_cache_cpu_cache: %ld\n", + OFFSET(kmem_cache_cpu_cache)); + fprintf(fp, " kmem_cache_oo: %ld\n", + OFFSET(kmem_cache_oo)); + fprintf(fp, " kmem_cache_random: %ld\n", + OFFSET(kmem_cache_random)); + + 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_node_total_objects: %ld\n", + OFFSET(kmem_cache_node_total_objects)); + + 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, " kmem_cache_memcg_params: %ld\n", + OFFSET(kmem_cache_memcg_params)); + fprintf(fp, "memcg_cache_params___root_caches_node: %ld\n", + OFFSET(memcg_cache_params___root_caches_node)); + fprintf(fp, " memcg_cache_params_children: %ld\n", + OFFSET(memcg_cache_params_children)); + fprintf(fp, " memcg_cache_params_children_node: %ld\n", + OFFSET(memcg_cache_params_children_node)); + + 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, " timer_base_vectors: %ld\n", + OFFSET(timer_base_vectors)); + + 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, " pci_dev_dev: %ld\n", + OFFSET(pci_dev_dev)); + fprintf(fp, " pci_dev_hdr_type: %ld\n", + OFFSET(pci_dev_hdr_type)); + fprintf(fp, " pci_dev_pcie_flags_reg: %ld\n", + OFFSET(pci_dev_pcie_flags_reg)); + fprintf(fp, " pci_bus_node: %ld\n", + OFFSET(pci_bus_node)); + fprintf(fp, " pci_bus_devices: %ld\n", + OFFSET(pci_bus_devices)); + fprintf(fp, " pci_bus_dev: %ld\n", + OFFSET(pci_bus_dev)); + fprintf(fp, " pci_bus_children: %ld\n", + OFFSET(pci_bus_children)); + fprintf(fp, " pci_bus_parent: %ld\n", + OFFSET(pci_bus_parent)); + fprintf(fp, " pci_bus_self: %ld\n", + OFFSET(pci_bus_self)); + fprintf(fp, " device_kobj: %ld\n", + OFFSET(device_kobj)); + fprintf(fp, " kobject_name: %ld\n", + OFFSET(kobject_name)); + + 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, " pt_regs_regs: %ld\n", + OFFSET(pt_regs_regs)); + fprintf(fp, " pt_regs_cp0_badvaddr: %ld\n", + OFFSET(pt_regs_cp0_badvaddr)); + 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, " radix_tree_node_shift: %ld\n", + OFFSET(radix_tree_node_shift)); + + 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, " rb_root_cached_rb_leftmost: %ld\n", + OFFSET(rb_root_cached_rb_leftmost)); + + 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, " mem_section_pageblock_flags: %ld\n", + OFFSET(mem_section_pageblock_flags)); + fprintf(fp, " memory_block_dev: %ld\n", + OFFSET(memory_block_dev)); + fprintf(fp, " memory_block_nid: %ld\n", + OFFSET(memory_block_nid)); + fprintf(fp, " memory_block_start_section_nr: %ld\n", + OFFSET(memory_block_start_section_nr)); + fprintf(fp, " memory_block_end_section_nr: %ld\n", + OFFSET(memory_block_end_section_nr)); + fprintf(fp, " memory_block_state: %ld\n", + OFFSET(memory_block_state)); + + 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_r7: %ld\n", + OFFSET(cpu_context_save_r7)); + 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, " bus_type_p: %ld\n", + OFFSET(bus_type_p)); + 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, " device_private_device: %ld\n", + OFFSET(device_private_device)); + fprintf(fp, " device_private_knode_bus: %ld\n", + OFFSET(device_private_knode_bus)); + fprintf(fp, " device_private_knode_class: %ld\n", + OFFSET(device_private_knode_class)); + 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, " hd_struct_dkstats: %ld\n", + OFFSET(hd_struct_dkstats)); + fprintf(fp, " disk_stats_in_flight: %ld\n", + OFFSET(disk_stats_in_flight)); + 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, " request_queue_mq_ops: %ld\n", + OFFSET(request_queue_mq_ops)); + fprintf(fp, " request_queue_queue_ctx: %ld\n", + OFFSET(request_queue_queue_ctx)); + fprintf(fp, " blk_mq_ctx_rq_dispatched: %ld\n", + OFFSET(blk_mq_ctx_rq_dispatched)); + fprintf(fp, " blk_mq_ctx_rq_completed: %ld\n", + OFFSET(blk_mq_ctx_rq_completed)); + 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, " hstate_nr_huge_pages: %ld\n", + OFFSET(hstate_nr_huge_pages)); + fprintf(fp, " hstate_free_huge_pages: %ld\n", + OFFSET(hstate_free_huge_pages)); + fprintf(fp, " hstate_name: %ld\n", + OFFSET(hstate_name)); + + 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, " idr_cur: %ld\n", + OFFSET(idr_cur)); + 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, " nsproxy_net_ns: %ld\n", + OFFSET(nsproxy_net_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, " cgroup_kn: %ld\n", + OFFSET(cgroup_kn)); + fprintf(fp, " kernfs_node_name: %ld\n", + OFFSET(kernfs_node_name)); + fprintf(fp, " kernfs_node_parent: %ld\n", + OFFSET(kernfs_node_parent)); + 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_head_rb_root: %ld\n", + OFFSET(timerqueue_head_rb_root)); + 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, " atomic_t_counter: %ld\n", + OFFSET(atomic_t_counter)); + fprintf(fp, " percpu_counter_count: %ld\n", + OFFSET(percpu_counter_count)); + fprintf(fp, " sk_buff_head_next: %ld\n", + OFFSET(sk_buff_head_next)); + fprintf(fp, " sk_buff_head_qlen: %ld\n", + OFFSET(sk_buff_head_qlen)); + fprintf(fp, " sk_buff_next: %ld\n", + OFFSET(sk_buff_next)); + fprintf(fp, " sk_buff_len: %ld\n", + OFFSET(sk_buff_len)); + fprintf(fp, " sk_buff_data: %ld\n", + OFFSET(sk_buff_data)); + fprintf(fp, " nlmsghdr_nlmsg_type: %ld\n", + OFFSET(nlmsghdr_nlmsg_type)); + fprintf(fp, " module_arch: %ld\n", + OFFSET(module_arch)); + fprintf(fp, " mod_arch_specific_num_orcs: %ld\n", + OFFSET(mod_arch_specific_num_orcs)); + fprintf(fp, "mod_arch_specific_orc_unwind_ip: %ld\n", + OFFSET(mod_arch_specific_orc_unwind_ip)); + fprintf(fp, " mod_arch_specific_orc_unwind: %ld\n", + OFFSET(mod_arch_specific_orc_unwind)); + fprintf(fp, " bpf_prog_aux: %ld\n", + OFFSET(bpf_prog_aux)); + fprintf(fp, " bpf_prog_type: %ld\n", + OFFSET(bpf_prog_type)); + fprintf(fp, " bpf_prog_tag: %ld\n", + OFFSET(bpf_prog_tag)); + fprintf(fp, " bpf_prog_jited_len: %ld\n", + OFFSET(bpf_prog_jited_len)); + fprintf(fp, " bpf_prog_bpf_func: %ld\n", + OFFSET(bpf_prog_bpf_func)); + fprintf(fp, " bpf_prog_len: %ld\n", + OFFSET(bpf_prog_len)); + fprintf(fp, " bpf_prog_pages: %ld\n", + OFFSET(bpf_prog_pages)); + fprintf(fp, " bpf_prog_insnsi: %ld\n", + OFFSET(bpf_prog_insnsi)); + fprintf(fp, " bpf_map_map_flags: %ld\n", + OFFSET(bpf_map_map_flags)); + fprintf(fp, " bpf_map_map_type: %ld\n", + OFFSET(bpf_map_map_type)); + fprintf(fp, " bpf_map_pages: %ld\n", + OFFSET(bpf_map_pages)); + fprintf(fp, " bpf_map_key_size: %ld\n", + OFFSET(bpf_map_key_size)); + fprintf(fp, " bpf_map_value_size: %ld\n", + OFFSET(bpf_map_value_size)); + fprintf(fp, " bpf_map_max_entries: %ld\n", + OFFSET(bpf_map_max_entries)); + fprintf(fp, " bpf_map_name: %ld\n", + OFFSET(bpf_map_name)); + fprintf(fp, " bpf_map_user: %ld\n", + OFFSET(bpf_map_user)); + + fprintf(fp, " bpf_prog_aux_used_map_cnt: %ld\n", + OFFSET(bpf_prog_aux_used_map_cnt)); + fprintf(fp, " bpf_prog_aux_used_maps: %ld\n", + OFFSET(bpf_prog_aux_used_maps)); + fprintf(fp, " bpf_prog_aux_load_time: %ld\n", + OFFSET(bpf_prog_aux_load_time)); + fprintf(fp, " bpf_prog_aux_user: %ld\n", + OFFSET(bpf_prog_aux_user)); + fprintf(fp, " user_struct_uid: %ld\n", + OFFSET(user_struct_uid)); + + fprintf(fp, " xarray_xa_head: %ld\n", + OFFSET(xarray_xa_head)); + fprintf(fp, " xa_node_slots: %ld\n", + OFFSET(xa_node_slots)); + fprintf(fp, " xa_node_shift: %ld\n", + OFFSET(xa_node_shift)); + + fprintf(fp, "\n size_table:\n"); + fprintf(fp, " page: %ld\n", SIZE(page)); + fprintf(fp, " page_flags: %ld\n", SIZE(page_flags)); + fprintf(fp, " trace_print_flags: %ld\n", SIZE(trace_print_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, " task_struct_flags: %ld\n", SIZE(task_struct_flags)); + fprintf(fp, " task_struct_policy: %ld\n", SIZE(task_struct_policy)); + 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, " pid: %ld\n", + SIZE(pid)); + 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, " timer_base: %ld\n", + SIZE(timer_base)); + fprintf(fp, " tnt: %ld\n", + SIZE(tnt)); + fprintf(fp, " taint_flag: %ld\n", + SIZE(taint_flag)); + fprintf(fp, " nlmsghdr: %ld\n", + SIZE(nlmsghdr)); + fprintf(fp, " nlmsghdr_nlmsg_type: %ld\n", + SIZE(nlmsghdr_nlmsg_type)); + fprintf(fp, " sk_buff_head_qlen: %ld\n", + SIZE(sk_buff_head_qlen)); + fprintf(fp, " sk_buff_len: %ld\n", + SIZE(sk_buff_len)); + fprintf(fp, " orc_entry: %ld\n", + SIZE(orc_entry)); + fprintf(fp, " bpf_prog: %ld\n", + SIZE(bpf_prog)); + fprintf(fp, " bpf_prog_aux: %ld\n", + SIZE(bpf_prog_aux)); + fprintf(fp, " bpf_map: %ld\n", + SIZE(bpf_map)); + fprintf(fp, " bpf_insn: %ld\n", + SIZE(bpf_insn)); + fprintf(fp, " xarray: %ld\n", + SIZE(xarray)); + fprintf(fp, " xa_node: %ld\n", + SIZE(xa_node)); + + + 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, " height_to_maxnodes: %d\n", + ARRAY_LENGTH(height_to_maxnodes)); + 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)); + fprintf(fp, " task_struct_rlim: %d\n", + ARRAY_LENGTH(task_struct_rlim)); + fprintf(fp, " signal_struct_rlim: %d\n", + ARRAY_LENGTH(signal_struct_rlim)); + fprintf(fp, " vm_numa_stat: %d\n", + ARRAY_LENGTH(vm_numa_stat)); + + 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, "%s", 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; + ulong section_end_address; + + 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")) { + st->first_section_start = (ulong) + bfd_get_section_vma(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); + } + + if (st->first_section_start != 0) { + section_end_address = + (ulong) bfd_get_section_vma(bfd, section) + + (ulong) bfd_section_size(bfd, section); + if (section_end_address > st->last_section_end) + st->last_section_end = section_end_address; + } + 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; + } + + if (lm->mod_section_data[i].flags & SEC_FOUND) { + 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/2]; + 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/2); + 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)); + BCOPY(buf, req->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; + lm->loaded_objfile = NULL; + } + 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; + lm->loaded_objfile = NULL; + } 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"); + + if (st->_stext_vmlinux == UNINITIALIZED) { + if (STREQ(x->name, "_stext")) + st->_stext_vmlinux = valueof(x); + else if (STREQ(y->name, "_stext")) + st->_stext_vmlinux = valueof(y); + } + if (kt->flags2 & KASLR_CHECK) { + if (STREQ(x->name, "module_load_offset") || + STREQ(y->name, "module_load_offset")) { + kt->flags2 &= ~KASLR_CHECK; + kt->flags2 |= (RELOC_AUTO|KASLR); + } + } + + if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO() || VMSS_DUMPFILE()) { + /* Need for kaslr_offset and phys_base */ + if (STREQ(x->name, "divide_error")) + st->divide_error_vmlinux = valueof(x); + else if (STREQ(y->name, "divide_error")) + st->divide_error_vmlinux = valueof(y); + + if (STREQ(x->name, "idt_table")) + st->idt_table_vmlinux = valueof(x); + else if (STREQ(y->name, "idt_table")) + st->idt_table_vmlinux = valueof(y); + + if (STREQ(x->name, "saved_command_line")) + st->saved_command_line_vmlinux = valueof(x); + else if (STREQ(y->name, "saved_command_line")) + st->saved_command_line_vmlinux = valueof(y); + + if (STREQ(x->name, "pti_init")) + st->pti_init_vmlinux = valueof(x); + else if (STREQ(y->name, "kaiser_init")) + st->kaiser_init_vmlinux = valueof(y); + } + + 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; + long relocate_display; + struct syment *sp_array[1000], *sp; + + if (req->name == PATCH_KERNEL_SYMBOLS_START) { + if (kt->relocate) { + if ((long)kt->relocate < 0) + relocate_display = (kt->relocate * -1) >> 20; + else + relocate_display = kt->relocate >> 20; + error(WARNING, + "\nkernel relocated [%ldMB]: patching %ld gdb minimal_symbol values\n", + relocate_display, 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; +} + +/* + * The caller fills in the structure and member name fields of + * the passed-in struct_member_data structure, which are then + * passed to the gdb "printm" command to get the member data. + * + * Adapted from Qiao Nuohan's "pstruct" extension module. + */ +int +fill_struct_member_data(struct struct_member_data *smd) +{ + int i, cnt; + char buf[BUFSIZE]; + char *printm_list[MAXARGS]; + + cnt = 0; + sprintf(buf, "printm ((struct %s *)0x0).%s", + smd->structure, smd->member); + + open_tmpfile2(); + + if (!gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR)) + return FALSE; + + rewind(pc->tmpfile2); + if (fgets(buf, BUFSIZE, pc->tmpfile2)) { + if (CRASHDEBUG(2)) + fprintf(fp, "%s.%s: %s", + smd->structure, smd->member, buf); + cnt = parse_line(buf, printm_list); + } + + close_tmpfile2(); + + if (cnt != 6) + return FALSE; + for (i = 0; i < cnt; i++) { + if (!decimal(printm_list[i], 0)) + return FALSE; + } + + smd->type = dtol(printm_list[0], RETURN_ON_ERROR, NULL); + smd->unsigned_type = dtol(printm_list[1], RETURN_ON_ERROR, NULL); + smd->length = dtol(printm_list[2], RETURN_ON_ERROR, NULL); + smd->offset = dtol(printm_list[3], RETURN_ON_ERROR, NULL); + smd->bitpos = dtol(printm_list[4], RETURN_ON_ERROR, NULL); + smd->bitsize = dtol(printm_list[5], RETURN_ON_ERROR, NULL); + + return TRUE; +} + +void +add_to_downsized(char *name) +{ + struct downsized *ds; + + ds = &st->downsized; + + while (ds->name) + ds = ds->next; + + if (!(ds->name = (char *)malloc(strlen(name)+1)) || + !(ds->next = (struct downsized *)calloc(1, sizeof(struct downsized)))) + error(FATAL, + "cannot calloc/malloc downsized struct or \"%s\" name string\n", name); + + strcpy(ds->name, name); + + if (CRASHDEBUG(1)) + fprintf(fp, "%sadd_to_downsized: \"%s\"\n", + (pc->flags & PLEASE_WAIT) ? "\n" : "", name); +} + +int +is_downsized(char *name) +{ + struct downsized *ds; + + for (ds = &st->downsized; ds->name; ds = ds->next) { + if (STREQ(name, ds->name)) + return TRUE; + } + + return FALSE; +} + +struct syment * +symbol_complete_match(const char *match, struct syment *sp_last) +{ + int i; + struct syment *sp, *sp_end, *sp_start; + struct load_module *lm; + int search_init; + + if (sp_last) { + sp_start = next_symbol(NULL, sp_last); + if (!sp_start) + return NULL; + } else + sp_start = st->symtable; + + if ((sp_start >= st->symtable) && (sp_start < st->symend)) { + for (sp = sp_start; sp < st->symend; sp++) { + if (STRNEQ(sp->name, match)) + return sp; + } + sp_start = NULL; + } + + 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_end = lm->mod_symend; + if (!sp_start) + sp_start = lm->mod_symtable; + + if ((sp_start >= lm->mod_symtable) && (sp_start < sp_end)) { + for (sp = sp_start; sp < sp_end; sp++) { + if (MODULE_START(sp)) + continue; + + if (STRNEQ(sp->name, match)) + return sp; + } + sp_start = NULL; + } + } + + if (!search_init) + return NULL; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + if (!lm->mod_init_symtable) + continue; + sp_end = lm->mod_init_symend; + if (!sp_start) + sp_start = lm->mod_init_symtable; + + if ((sp_start >= lm->mod_init_symtable) && (sp_start < sp_end)) { + for (sp = sp_start; sp < sp_end; sp++) { + if (MODULE_START(sp)) + continue; + + if (STRNEQ(sp->name, match)) + return sp; + } + } + } + + return NULL; +}