/* Warning : *** 09/24/2007 This file is provided as reference. The commands defined here have only been tested the 2.6.14 kernel version as this was the only kernel dump available to me for the crash port effort. *** Immediately below are two simple commands implementations. Refer to README for information on the sial implementation for crash and sial itself. README.sial gives the list of #define available in the context of the macro. The "main" command is a skeletton which shows the different parts of the command in a clear manner. Fot a complete example, see th ps command implementation below. The -l and -t options are not implemented yet. The -t functionality could be implemnted by defining the missing functions. The -h option shows a hierarchical list of processes. It makes extensive use of the dynamic arrays. */ string main_help() { return "this is the << help >> for main"; } string main_opt() { return "lth"; } string main_usage() { return "[ [-l] [-h] ] | [-t]"; } int main() { // printf("Linux version : 0x%08x\n", LINUX_RELEASE); // /* *** You can use LINUX_2_??? macros to change execution based on *** crash file version. These macros are "injected" into the sial context *** by the main sial.c initialization code which defines them as: {"LINUX_2_2_16", "(LINUX_RELEASE==0x020210)"}, {"LINUX_2_2_17", "(LINUX_RELEASE==0x020211)"}, {"LINUX_2_4_0", "(LINUX_RELEASE==0x020400)"}, {"LINUX_2_2_X", "(((LINUX_RELEASE) & 0xffff00) == 0x020200)"}, {"LINUX_2_4_X", "(((LINUX_RELEASE) & 0xffff00) == 0x020400)"}, {"LINUX_2_6_X", "(((LINUX_RELEASE) & 0xffff00) == 0x020600)"}, */ #if LINUX_2_2_X printf("Running linux 2.2.X [0x%08x]\n", LINUX_RELEASE); #elif LINUX_2_4_X printf("Running linux 2.4.X [0x%08x]\n", LINUX_RELEASE); #elif LINUX_2_6_X printf("Running linux 2.6.X [0x%08x]\n", LINUX_RELEASE); #else printf("Running Linux version : 0x%08x\n", LINUX_RELEASE); #endif return 1; } #if LINUX_RELEASE > 0x020611 typedef struct task_struct task_t; #endif struct mm_struct *x; void walk_tasks(string callback) { struct task_struct *ts, *tsp; #if LINUX_2_6_X if(exists("init_task")) { ts=(struct task_struct *)init_task; #else if(exists("init_tasks")) { ts=(struct task_struct *)init_tasks; } else if(exists("init_task_union")) { ts=(struct task_struct *)init_task_union; #endif } else { printf("Task list not found!\n"); exit(1); } tsp=ts; callback((task_t*)0, 0); do { if(!callback((task_t*)tsp, 1)) break; #if LINUX_2_6_X { unsigned long tasks; tasks = (unsigned long)(tsp->tasks.next); tsp = (struct task_struct *)((unsigned long)(tsp->tasks.next) - ((unsigned long)&(tsp->tasks) - (unsigned long)tsp)); } #else tsp = tsp->next_task; #endif } while(tsp != ts); callback((task_t*)0, 2); } /* Get some of the processes address space attributes. */ int getasattr(task_t *t, int f) { if(!t->mm) return 0; switch(f) { case 1: if (LINUX_RELEASE < 0x0002060f) { return t->mm->rss*4; } else { struct mm_struct *mm=t->mm?t->mm:t->active_mm; if (member(&mm->_file_rss, "counter")) return (mm->_file_rss.counter+mm->_anon_rss.counter)*4; else return (mm->_file_rss+mm->_anon_rss)*4; } case 2: return t->mm->total_vm*4; default: printf("Unknown getasattr function [%d]\n", f); return 0; } } string get_proc_cmd(task_t *t, int l) { // long args not implemented at the moment. // creates a loop in klib if(0 && l) { char *s=(char*)t->mm->arg_start; char *e=(char*)t->mm->arg_end; string cmd=""; if(!s) return ""; // args have address only menaingful for task space printf("settask=%d\n", settask(t)); // strcat all parameters while(s < e) { string thisarg=getstr(s); cmd=cmd+" "+thisarg; s += strlen(thisarg)+1; } return cmd; } else { return getstr(t->comm); } } void print_proc(task_t *t) { int rss, size; string cmd; // get the command line string // lflag is set from the icrash command line with '-l' if(lflag) cmd = get_proc_cmd(t, 1); else cmd = get_proc_cmd(t, 0); rss=getasattr(t, 1); size=getasattr(t, 2); printf("%p %7d %7d %7d 0x%02x 0x%08x %5d:%-5d %s\n" , t , t->uid , t->pid #if LINUX_2_6_X , t->parent->pid #else , t->p_pptr->pid #endif , t->state , t->flags , size , rss , cmd ); } /* Do the real work for a ps */ int dops(task_t *t, int phase) { static int np; switch(phase) { case 0: // // the %> format prints 8 characters (like the one following the '>') on a 32 bit // system and does nothing on a 64 bit system. This permits seamless alignment of // of the header and fields on either types of systems. // // ex: %>- print '--------' on a 32bit and nothing on a 64bit. // printf("Address %> Uid Pid PPid Stat Flags %> SIZE:RSS Command\n"); printf("--------%>-----------------------------------------------%>------------------------\n"); np=0; break; case 1: print_proc(t); np++; break; case 2: printf("--------%>-----------------------------------------------%>------------------------\n"); printf("%d process%s found\n", np, np>1?"es":""); break; } return 1; } string sps_opt() { return "lth"; } string sps_usage() { return "[-l] [-t] [-h]\n"; } static void sps_showusage() { printf("usage : sps %s\n", sps_usage()); } string sps_help() { return // in sial "xxx" is a type 'string' and the + operator is supported. // char* refers to a string address in the image and char[] is illegal // except in structure or union declarations. // " This command displays various information about processes.\n\n" + " -t Give a list of the current timers for each threads\n" + " and a aproximated elaps time (in seconds) in the corresponding state.\n\n" + " -l Show the complete command line w/ arguments. (not implemented yet)\n\n" + " -h show the hiearchy of processes."; } int dotimer(task_t *t, int phase) { static int np; switch(phase) { case 0: printf(" State Time Pid Name\n"); printf("--------------------------------------\n"); np=0; break; case 1: { printf("%12s %10lld %8d %s\n" , timer_getname(t) , timer_elaps(t) , t->pid , getnstr(t->comm, 16)); } np++; break; case 2: printf("--------------------------------------\n"); printf("%d process%s found\n", np, np>1?"es":""); break; } return 1; } #define MAXLEV 10 static void pindent(int level) { int i; for(i=0;iparent->pid][t->pid]=t; #else procs[t->p_pptr->pid][t->pid]=t; #endif procs[t->pid][0]=t; break; case 2: // start at level 0 pid 0 prlevel(0, 0); dops((task_t*)0, 2); break; } return 1; } /* find the task pointer given the PID */ static int pidMatch=0; static task_t *taskMatch=(task_t *)0; int findPid(task_t *t, int phase) { if(phase == 1 && t->pid == pidMatch) { taskMatch=t; return 0; } return 1; } task_t *pidToTask(int pid) { pidMatch=pid; taskMatch=0; walk_tasks("findPid"); return taskMatch; } /* Core of the ps command. */ int sps() { // // for functions that are command entry points, sial // defines argv[] and argc as global variables. // argv[0] is set to the entry point name e.g. "ps" // // Variables for each specified options will exists // ex: bflag. If an option has an associated parameter // then a corresponding global ?arg will exists. // ex: int bflag and string barg. // if(argc > 1) sps_showusage(); else if(tflag) /* With sial function callbacks are implemented using 'string' variable. At the time of the call sial will use the value of a string variable to call the corresponding function. Below we call walk_tasks() passing the name of the function to callback as a tring value. */ walk_tasks("dotimer"); else if(hflag) walk_tasks("pstree"); else walk_tasks("dops"); return 1; }