From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23395 invoked by alias); 10 Jan 2002 20:14:11 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 23211 invoked from network); 10 Jan 2002 20:14:02 -0000 Received: from unknown (HELO cygnus.com) (205.180.230.5) by sources.redhat.com with SMTP; 10 Jan 2002 20:14:02 -0000 Received: from reddwarf.cygnus.com (reddwarf.sfbay.redhat.com [205.180.231.12]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id MAA18963; Thu, 10 Jan 2002 12:14:00 -0800 (PST) Received: (from msnyder@localhost) by reddwarf.cygnus.com (8.11.2/8.11.2) id g0AK8p112983; Thu, 10 Jan 2002 12:08:51 -0800 Date: Thu, 10 Jan 2002 12:14:00 -0000 From: Michael Snyder Message-Id: <200201102008.g0AK8p112983@reddwarf.cygnus.com> To: gdb-patches@sources.redhat.com Subject: [RFA] New command "info proc" for Linux Cc: drow@mvista.com, kettenis@gnu.org X-SW-Source: 2002-01/txt/msg00250.txt.bz2 What do you Linux guys think of this? It's modelled after the info proc command from procfs.c, but uses/exposes the /proc information available on Linux. Do you see any architecture/portability issues? Thanks Michael 2002-01-10 Michael Snyder * linux-proc.c: Add "info proc" command, a la procfs.c. (read_mapping): New function, abstract and re-use code. (linux_find_memory_regions): Use new func read_mapping. (linux_info_proc_cmd): New function, implement "info proc". (_initialize_linux_proc): Add new command "info proc". Index: linux-proc.c =================================================================== RCS file: /cvs/src/src/gdb/linux-proc.c,v retrieving revision 1.3 diff -c -3 -p -r1.3 linux-proc.c *** linux-proc.c 2002/01/09 02:21:25 1.3 --- linux-proc.c 2002/01/10 20:04:03 *************** *** 22,31 **** --- 22,34 ---- #include "inferior.h" #include /* for MAXPATHLEN */ #include + #include /* for struct stat */ + #include /* for isdigit */ #include "gregset.h" /* for gregset */ #include "gdbcore.h" /* for get_exec_file */ #include "gdbthread.h" /* for struct thread_info etc. */ #include "elf-bfd.h" + #include "cli/cli-decode.h" /* Function: child_pid_to_exec_file * *************** child_pid_to_exec_file (int pid) *** 52,57 **** --- 55,90 ---- return name1; } + /* Function: read_mappings + * + * Service function for corefiles and info proc. + */ + + static int + read_mapping (FILE *mapfile, + long long *addr, + long long *endaddr, + char *permissions, + long long *offset, + char *device, + long long *inode, + char *filename) + { + int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx", + addr, endaddr, permissions, offset, device, inode); + + if (ret > 0 && ret != EOF && *inode != 0) + { + ret += fscanf (mapfile, "%s\n", filename); + } + else + { + filename[0] = '\0'; /* no filename */ + fscanf (mapfile, "\n"); + } + return (ret != 0 && ret != EOF); + } + /* Function: linux_find_memory_regions * * Fills the "to_find_memory_regions" target vector. *************** linux_find_memory_regions (int (*func) ( *** 66,107 **** void *obfd) { long long pid = PIDGET (inferior_ptid); ! char procfilename[MAXPATHLEN]; ! FILE *procfile; long long addr, endaddr, size, offset, inode; ! char perms[8], dev[8], filename[MAXPATHLEN]; int read, write, exec; int ret; /* Compose the filename for the /proc memory map, and open it. */ ! sprintf (procfilename, "/proc/%lld/maps", pid); ! if ((procfile = fopen (procfilename, "r")) == NULL) ! error ("Could not open %s\n", procfilename); if (info_verbose) fprintf_filtered (gdb_stdout, ! "Reading memory regions from %s\n", procfilename); ! ! /* Read the first memory segment descriptor from the maps file. */ ! ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx", ! &addr, &endaddr, perms, &offset, dev, &inode); ! if (inode) ! fscanf (procfile, " %s\n", filename); ! else ! { ! filename[0] = '\0'; ! fscanf (procfile, "\n"); ! } /* Now iterate until end-of-file. */ ! while (ret > 0 && ret != EOF) { size = endaddr - addr; /* Get the segment's permissions. */ ! read = (strchr (perms, 'r') != 0); ! write = (strchr (perms, 'w') != 0); ! exec = (strchr (perms, 'x') != 0); if (info_verbose) { --- 99,130 ---- void *obfd) { long long pid = PIDGET (inferior_ptid); ! char mapsfilename[MAXPATHLEN]; ! FILE *mapsfile; long long addr, endaddr, size, offset, inode; ! char permissions[8], device[8], filename[MAXPATHLEN]; int read, write, exec; int ret; /* Compose the filename for the /proc memory map, and open it. */ ! sprintf (mapsfilename, "/proc/%lld/maps", pid); ! if ((mapsfile = fopen (mapsfilename, "r")) == NULL) ! error ("Could not open %s\n", mapsfilename); if (info_verbose) fprintf_filtered (gdb_stdout, ! "Reading memory regions from %s\n", mapsfilename); /* Now iterate until end-of-file. */ ! while (read_mapping (mapsfile, &addr, &endaddr, &permissions[0], ! &offset, &device[0], &inode, &filename[0])) { size = endaddr - addr; /* Get the segment's permissions. */ ! read = (strchr (permissions, 'r') != 0); ! write = (strchr (permissions, 'w') != 0); ! exec = (strchr (permissions, 'x') != 0); if (info_verbose) { *************** linux_find_memory_regions (int (*func) ( *** 119,139 **** /* Invoke the callback function to create the corefile segment. */ func (addr, size, read, write, exec, obfd); - - /* Read the next memory region. */ - filename[0] = '\0'; - ret = fscanf (procfile, "%llx-%llx %s %llx %s %llx", - &addr, &endaddr, perms, &offset, dev, &inode); - if (inode) - fscanf (procfile, " %s\n", filename); - else - { - filename[0] = '\0'; - fscanf (procfile, "\n"); - } } ! ! fclose (procfile); return 0; } --- 142,149 ---- /* Invoke the callback function to create the corefile segment. */ func (addr, size, read, write, exec, obfd); } ! fclose (mapsfile); return 0; } *************** linux_make_note_section (bfd *obfd, int *** 268,273 **** --- 278,550 ---- return note_data; } + /* + * Function: linux_info_proc_cmd + * + * Implement the "info proc" command. + */ + + static void + linux_info_proc_cmd (char *args, int from_tty) + { + long long pid = PIDGET (inferior_ptid); + FILE *procfile; + char **argv = NULL; + char buffer[MAXPATHLEN]; + char fname1[MAXPATHLEN], fname2[MAXPATHLEN]; + int cmdline_f = 1; + int cwd_f = 1; + int exe_f = 1; + int mappings_f = 0; + int environ_f = 0; + int status_f = 0; + int stat_f = 0; + int all = 0; + struct stat dummy; + + if (args) + { + /* Break up 'args' into an argv array. */ + if ((argv = buildargv (args)) == NULL) + nomem (0); + else + make_cleanup_freeargv (argv); + } + while (argv != NULL && *argv != NULL) + { + if (isdigit (argv[0][0])) + { + pid = strtoul (argv[0], NULL, 10); + } + else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0) + { + mappings_f = 1; + } + else if (strcmp (argv[0], "status") == 0) + { + status_f = 1; + } + else if (strcmp (argv[0], "stat") == 0) + { + stat_f = 1; + } + else if (strcmp (argv[0], "cmd") == 0) + { + cmdline_f = 1; + } + else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0) + { + exe_f = 1; + } + else if (strcmp (argv[0], "cwd") == 0) + { + cwd_f = 1; + } + else if (strncmp (argv[0], "all", strlen (argv[0])) == 0) + { + all = 1; + } + else + { + /* [...] (future options here) */ + } + argv++; + } + if (pid == 0) + error ("No current process: you must name one."); + + sprintf (fname1, "/proc/%lld", pid); + if (stat (fname1, &dummy) != 0) + error ("No /proc directory: '%s'", fname1); + + printf_filtered ("process %lld\n", pid); + if (cmdline_f || all) + { + sprintf (fname1, "/proc/%lld/cmdline", pid); + if ((procfile = fopen (fname1, "r")) > 0) + { + fgets (buffer, sizeof (buffer), procfile); + printf_filtered ("cmdline = '%s'\n", buffer); + fclose (procfile); + } + else + warning ("unable to open /proc file '%s'", fname1); + } + if (cwd_f || all) + { + sprintf (fname1, "/proc/%lld/cwd", pid); + memset (fname2, 0, sizeof (fname2)); + if (readlink (fname1, fname2, sizeof (fname2)) > 0) + printf_filtered ("cwd = '%s'\n", fname2); + else + warning ("unable to read link '%s'", fname1); + } + if (exe_f || all) + { + sprintf (fname1, "/proc/%lld/exe", pid); + memset (fname2, 0, sizeof (fname2)); + if (readlink (fname1, fname2, sizeof (fname2)) > 0) + printf_filtered ("exe = '%s'\n", fname2); + else + warning ("unable to read link '%s'", fname1); + } + if (mappings_f || all) + { + sprintf (fname1, "/proc/%lld/maps", pid); + if ((procfile = fopen (fname1, "r")) > 0) + { + long long addr, endaddr, size, offset, inode; + char permissions[8], device[8], filename[MAXPATHLEN]; + char *header_fmt_string, *data_fmt_string; + + if (TARGET_ADDR_BIT == 32) + { + header_fmt_string = "\t%10s %10s %10s %10s %7s\n"; + data_fmt_string = "\t%#10lx %#10lx %#10x %#10x %7s\n"; + } + else + { + header_fmt_string = " %18s %18s %10s %10s %7s\n"; + data_fmt_string = " %#18lx %#18lx %#10x %#10x %7s\n"; + } + + printf_filtered ("Mapped address spaces:\n\n"); + printf_filtered (header_fmt_string, + "Start Addr", + " End Addr", + " Size", + " Offset", + "objfile"); + + while (read_mapping (procfile, &addr, &endaddr, &permissions[0], + &offset, &device[0], &inode, &filename[0])) + { + size = endaddr - addr; + printf_filtered (data_fmt_string, + (unsigned long) addr, /* FIXME: pr_addr */ + (unsigned long) endaddr, + (int) size, + (unsigned int) offset, + filename[0] ? filename : ""); + + } + + fclose (procfile); + } + else + warning ("unable to open /proc file '%s'", fname1); + } + if (status_f || all) + { + sprintf (fname1, "/proc/%lld/status", pid); + if ((procfile = fopen (fname1, "r")) > 0) + { + while (fgets (buffer, sizeof (buffer), procfile) != NULL) + printf_filtered (buffer); + fclose (procfile); + } + else + warning ("unable to open /proc file '%s'", fname1); + } + if (stat_f || all) + { + sprintf (fname1, "/proc/%lld/stat", pid); + if ((procfile = fopen (fname1, "r")) > 0) + { + int itmp; + char ctmp; + + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Process: %d\n", itmp); + if (fscanf (procfile, "%s ", &buffer[0]) > 0) + printf_filtered ("Exec file: %s\n", buffer); + if (fscanf (procfile, "%c ", &ctmp) > 0) + printf_filtered ("State: %c\n", ctmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Parent process: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Process group: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Session id: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("TTY: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("TTY owner process group: %d\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Flags: 0x%x\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Minor faults (no memory page): %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Minor faults, children: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Major faults (memory page faults): %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Major faults, children: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("utime: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("stime: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("utime, children: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("stime, children: %d\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("jiffies remaining in current time slice: %d\n", + itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("'nice' value: %d\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("jiffies until next timeout: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("jiffies until next SIGALRM: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("start time (jiffies since system boot): %d\n", + itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Virtual memory size: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Resident set size: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("rlim: %u\n", + (unsigned int) itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Start of text: 0x%x\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("End of text: 0x%x\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) + printf_filtered ("Start of stack: 0x%x\n", itmp); + #if 0 /* Don't know how architecture-dependent the rest is... + Anyway the signal bitmap info is available from "status". */ + if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ + printf_filtered ("Kernel stack pointer: 0x%x\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ + printf_filtered ("Kernel instr pointer: 0x%x\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Pending signals bitmap: 0x%x\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Blocked signals bitmap: 0x%x\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Ignored signals bitmap: 0x%x\n", itmp); + if (fscanf (procfile, "%d ", &itmp) > 0) + printf_filtered ("Catched signals bitmap: 0x%x\n", itmp); + if (fscanf (procfile, "%u ", &itmp) > 0) /* FIXME arch? */ + printf_filtered ("wchan (system call): 0x%x\n", itmp); + #endif + fclose (procfile); + } + else + warning ("unable to open /proc file '%s'", fname1); + } + } + void _initialize_linux_proc (void) { *************** _initialize_linux_proc (void) *** 276,279 **** --- 553,565 ---- inftarg_set_find_memory_regions (linux_find_memory_regions); inftarg_set_make_corefile_notes (linux_make_note_section); + + add_info ("proc", linux_info_proc_cmd, + "Show /proc process information about any running process.\n\ + Specify any process id, or use the program being debugged by default.\n\ + Specify any of the following keywords for detailed info:\n\ + mappings -- list of mapped memory regions.\n\ + stat -- list a bunch of random process info.\n\ + status -- list a different bunch of random process info.\n\ + all -- list all available /proc info."); }