Saturday, February 19, 2011

~Core-dump Analysis- II~

// Test Program which generate SIGSEGV signal
// Purpose:: Just copy the string provided by the user and print.

#include"stdio.h"
#include"string.h"
#include"stdlib.h"

void *my_memcpy(char *,char *, short);
void printf_info(char *);

// Global Arrary
extern char *garray[3] = {NULL};

int main(int argc, char *argv[]) {

if(argc != 3) {
printf("Please enter the the inputs in appropriate manner\n");
printf("<%s> \n", argv[0]);
return 1;
}

short len = atoi(argv[2]);
char *str = argv[1];
char *dest = (char *)malloc((len +1)*sizeof(char));
if(NULL==dest)
printf("Error while allocating memory\n");

garray[0] = str;
garray[1] = dest;
garray[2] = (char *)&len;

my_memcpy(dest, str, len);
free(dest);
return 0;
}

// Copy the given memory region
void *my_memcpy(char *dest, char *source, short length) {
int i;
char *base = dest;
for(i =0; i < length ; i++) {
*dest = *source ;
dest = dest +1;
source = source +1;
}
printf_info(base);
return base;
}

// Print the information
void printf_info(char *info) {
int *segv, length;
int *i = NULL;
printf("desired string is: %s\n",info);
length= *garray[2];
//This would generate the SIGSEGV signal
*segv = *i;
}


Now lets compile and run this program. I have given otest as my program file for above test program.

mantosh@ubuntu:~/Desktop$ ./otest LinuxWorldRocks 10
desired string is: LinuxWorld
Segmentation fault (core dumped)
mantosh@ubuntu:~/Desktop$ ls -al
total 148
-rw------- 1 mantosh mantosh 286720 2011-02-19 18:07 core.23515


Now we have core-dump file. Now lets load into the gdb and try to get
some useful information.

mantosh@ubuntu:~/Desktop$ gdb
(gdb) core core.23515
(no debugging symbols found)
Core was generated by `./otest LinuxWorldRocks 10'.
Program terminated with signal 11, Segmentation fault.
[New process 23515]
==> Signal 11(SIGSEGV) was the reason for this core-dump file
==> pid of a program is 23515
#0 0x080485f8 in ?? ()
(gdb) bt
#0 0x080485f8 in ?? ()
#1 0x080485c2 in ?? ()
#2 0x0804855d in ?? ()
#3 0xb7df2775 in ?? ()
#4 0x08048401 in ?? ()
(gdb) symbol ./otest
Reading symbols from /home/mantosh/Desktop/otest...done.
(gdb) bt
#0 0x080485f8 in printf_info (info=0x8ec5008 "LinuxWorld") at test.c:58
#1 0x080485c2 in my_memcpy (dest=0x8ec5012 "", source=0xbfb9c6fe "Rocks",
length=10) at test.c:47
#2 0x0804855d in main (argc=3, argv=0xbfb9b3f4) at test.c:33
(gdb) bt full
==> bt full would display additional information of all variables along
==> with the function call.
#0 0x080485f8 in printf_info (info=0x8ec5008 "LinuxWorld") at test.c:58
segv = (int *) 0xbfb9b328
length = 10
i = (int *) 0x0
#1 0x080485c2 in my_memcpy (dest=0x8ec5012 "", source=0xbfb9c6fe "Rocks", length=10) at test.c:47
i = 10
base = 0x8ec5008 "LinuxWorld"
#2 0x0804855d in main (argc=3, argv=0xbfb9b3f4) at test.c:33
len = 10
str = 0xbfb9c6f4 "LinuxWorldRocks"
dest = 0x8ec5008 "LinuxWorld"
(gdb) f 2
#2 0x0804855d in main (argc=3, argv=0xbfb9b3f4) at test.c:33
33 my_memcpy(dest, str, len);
(gdb) info args
argc = 3
argv = (char **) 0xbfb9b3f4
(gdb) p garray
==> garray is global variable defined in the program, so we can access it
==> from anywhere in core-dump. However we will not get the information
==> while giving command like info locals inside any particular frame.
$1 = {[0] = 0xbfb9c6f4 "LinuxWorldRocks",
[1] = 0x8ec5008 "LinuxWorld",
[2] = 0xbfb9b352 "\n"}
(gdb) p *garray[2]
$2 = 10 '\n'
(gdb) p argv[0]
$3 = 0xbfb9c6ec "./otest"
(gdb) p argv[1]
$4 = 0xbfb9c6f4 "LinuxWorldRocks"
(gdb) p argv[2]
$5 = 0xbfb9c704 "10"
(gdb) p argv[3]
$6 = 0x0
(gdb) x/3xw argv
0xbfb9b3f4: 0xbfb9c6ec 0xbfb9c6f4 0xbfb9c704
(gdb) x/4xw argv
==> 4 unit display. Notice argv would be terminated by null pointer.
0xbfb9b3f4: 0xbfb9c6ec 0xbfb9c6f4 0xbfb9c704 0x00000000
(gdb) info locals
len = 10
str = 0xbfb9c6f4 "LinuxWorldRocks"
dest = 0x8ec5008 "LinuxWorld"
(gdb) p &str
$7 = (char **) 0xbfb9b34c
(gdb) x/1xw &str
0xbfb9b34c: 0xbfb9c6f4
(gdb) x/10cb 0xbfb9c6f4
0xbfb9c6f4:76 'L' 105 'i' 110 'n' 117 'u' 120 'x' 87 'W' 111 'o' 114 'r'
0xbfb9c6fc: 108 'l' 100 'd'
(gdb) p garray
$8 = {[0] = 0xbfb9c6f4 "LinuxWorldRocks",
[1] = 0x8ec5008 "LinuxWorld",
[2] = 0xbfb9b352 "\n"}
(gdb) x/3xw garray
==> Since we have defined garray as array of pointers. So by this command we
==> get the address information of 3 variables.
0x804a02c : 0xbfb9c6f4 0x08ec5008 0xbfb9b352
(gdb) info frame
Stack level 2, frame at 0xbfb9b360:
eip = 0x804855d in main (test.c:33); saved eip 0xb7df2775
caller of frame at 0xbfb9b330
source language c.
Arglist at 0xbfb9b32c, args: argc=3, argv=0xbfb9b3f4
Locals at 0xbfb9b32c, Previous frame's sp at 0xbfb9b354
Saved registers:
ebp at 0xbfb9b358, eip at 0xbfb9b35c
(gdb) frame 1
#1 0x080485c2 in my_memcpy (dest=0x8ec5012 "", source=0xbfb9c6fe "Rocks", length=10) at test.c:47
47 printf_info(base);
(gdb) info locals
i = 10
base = 0x8ec5008 "LinuxWorld"
(gdb) p *base
$9 = 76 'L'
(gdb) p *base@10
$10 = "LinuxWorld"
(gdb) p *base@12
$11 = "LinuxWorld\000"
(gdb) p &i
$12 = (int *) 0xbfb9b324
(gdb) x/4db &i
0xbfb9b324: 10 0 0 0
(gdb) x/1dw &i
0xbfb9b324: 10
(gdb) info args
dest = 0x8ec5012 ""
source = 0xbfb9c6fe "Rocks"
length = 10
(gdb) frame 0
#0 0x080485f8 in printf_info (info=0x8ec5008 "LinuxWorld") at test.c:58
58 *segv = *i;
(gdb) info locals
segv = (int *) 0xbfb9b328
length = 10
i = (int *) 0x0
(gdb) info args
info = 0x8ec5008 "LinuxWorld"
(gdb) ptype garray
type = char *[3]
(gdb) p *garray
$13 = 0xbfb9c6f4 "LinuxWorldRocks"
(gdb) p *garray@3
$14 = {[0] = 0xbfb9c6f4 "LinuxWorldRocks",
[1] = 0x8ec5008 "LinuxWorld",
[2] = 0xbfb9b352 "\n"}
(gdb) info reg
eax 0x0 0
ecx 0x0 0
edx 0xb7f3c0d0 -1208762160
ebx 0xb7f3aff4 -1208766476
esp 0xbfb9b2f0 0xbfb9b2f0
ebp 0xbfb9b308 0xbfb9b308
esi 0x8048620 134514208
edi 0x80483e0 134513632
eip 0x80485f8 0x80485f8
eflags 0x10296 [ PF AF SF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/i $eip
0x80485f8:Cannot access memory at address
0x80485f8
(gdb) info file
Symbols from "/home/mantosh/Desktop/otest".
Local core dump file:
`/home/mantosh/Desktop/core.23515', file type elf32-i386.
0x08048000 - 0x08048000 is load1
0x08049000 - 0x0804a000 is load2
0x0804a000 - 0x0804b000 is load3
0x08ec5000 - 0x08ee6000 is load4
0xb7ddb000 - 0xb7ddc000 is load5
0xb7ddc000 - 0xb7ddc000 is load6
0xb7f38000 - 0xb7f38000 is load7
0xb7f39000 - 0xb7f3b000 is load8
0xb7f3b000 - 0xb7f3c000 is load9
0xb7f3c000 - 0xb7f3f000 is load10
0xb7f56000 - 0xb7f59000 is load11
0xb7f59000 - 0xb7f5a000 is load12
0xb7f5a000 - 0xb7f5a000 is load13
0xb7f76000 - 0xb7f77000 is load14
0xb7f77000 - 0xb7f78000 is load15
0xbfb88000 - 0xbfb9d000 is load16
(gdb) q










====================================================

// Test Program which generate SIGFPE signal.
/// Purpose:: Just add two number provided by the user

#include"stdio.h"
#include"string.h"
#include"stdlib.h"

int add_sum(int * );
void fun_sigfpe(int *);

int main(int argc, char *argv[]) {

int a[2];
int sum;

if(argc != 3) {
printf("Please enter the the inputs in appropriate manner\n");
printf("<%s> \n", argv[0]);
return 1;
}

a[0] = atoi(argv[1]);
a[1] = atoi(argv[2]);
sum = add_sum(a);

return 0;
}

// Addition of 2 number
int add_sum(int x[]) {
int temp;

temp = x[0] +x[1];
printf("sum = %d\n",temp);

fun_sigfpe(x);
return temp;
}

// Dummy function for generating the SIGFPE signal
void fun_sigfpe(int x[]) {

int *a = NULL;
int diff,c,d;
a = malloc(2*sizeof(int));
memcpy(a,x,2*sizeof(int));
c = *a;
a = a+ 1;
d = *a;

if(c !=d)
c = d;

diff = c -d ;
// This would generate SIGFPE signal
diff = c/diff;

}


Now lets compile and run this program. I have given otest as my program file for above test program.

mantosh@ubuntu:~/Desktop$ ./otest 22 03
sum = 25
Floating point exception (core dumped)



Now we have core-dump file. Now lets load into the gdb and try to get
some useful information.

mantosh@ubuntu:~/Desktop$ gdb
(gdb) core core.25586
(no debugging symbols found)
Core was generated by `./otest 22 03'.
Program terminated with signal 8, Arithmetic exception.
[New process 25586]
#0 0x080485d7 in ?? ()
==> Signal 08(SIGFPE) was the reason for this core-dump file
==> pid of a program is 25586
(gdb) bt
#0 0x080485d7 in ?? ()
#1 0x08048561 in ?? ()
#2 0x08048514 in ?? ()
#3 0xb7f01775 in ?? ()
#4 0x08048401 in ?? ()
(gdb) symbol ./otest
Reading symbols from /home/mantosh/Desktop/otest...done.
(gdb) bt
#0 0x080485d7 in fun_sigfpe (x=0xbfdf0648) at test.c:56
#1 0x08048561 in add_sum (x=0xbfdf0648) at test.c:36
#2 0x08048514 in main (argc=3, argv=0xbfdf06f4) at test.c:24
(gdb) bt full
#0 0x080485d7 in fun_sigfpe (x=0xbfdf0648) at test.c:56
a = (int *) 0x839f00c
diff = 0
c = 3
d = 3
#1 0x08048561 in add_sum (x=0xbfdf0648) at test.c:36
temp = 25
#2 0x08048514 in main (argc=3, argv=0xbfdf06f4) at test.c:24
a = {[0] = 22,
[1] = 3}
sum = -1207469952
(gdb) f 2
#2 0x08048514 in main (argc=3, argv=0xbfdf06f4) at test.c:24
24 sum = add_sum(a);
(gdb) info locals
a = {[0] = 22,
[1] = 3}
sum = -1207469952
(gdb) p a
$1 = {[0] = 22,
[1] = 3}
(gdb) x/2dw a
==> This would print the 2 unit value from the base address a. Its same as
==> we are printing array a as i did in above command.
0xbfdf0648: 22 3
(gdb) info args
argc = 3
argv = (char **) 0xbfdf06f4
(gdb) x/3xw argv
0xbfdf06f4: 0xbfdf26f9 0xbfdf2701 0xbfdf2704
(gdb) x/4xw argv
0xbfdf06f4: 0xbfdf26f9 0xbfdf2701 0xbfdf2704 0x00000000
(gdb) bt
#0 0x080485d7 in fun_sigfpe (x=0xbfdf0648) at test.c:56
#1 0x08048561 in add_sum (x=0xbfdf0648) at test.c:36
#2 0x08048514 in main (argc=3, argv=0xbfdf06f4) at test.c:24
(gdb) f 1
#1 0x08048561 in add_sum (x=0xbfdf0648) at test.c:36
36 fun_sigfpe(x);
(gdb) info locals
temp = 25
(gdb) info args
x = (int *) 0xbfdf0648
(gdb) f 0
#0 0x080485d7 in fun_sigfpe (x=0xbfdf0648) at test.c:56
56 diff = c/diff;
(gdb) info locals
a = (int *) 0x839f00c
diff = 0
c = 3
d = 3
(gdb) ptype a
type = int *
(gdb) info args
x = (int *) 0xbfdf0648
(gdb) p x
$2 = (int *) 0xbfdf0648
(gdb) p *x
$3 = 22
(gdb) p *x@2
$4 = {[0] = 22,
[1] = 3}
(gdb) info reg
eax 0x3 3
ecx 0x0 0
edx 0x0 0
ebx 0xb8049ff4 -1207656460
esp 0xbfdf05e0 0xbfdf05e0
ebp 0xbfdf0608 0xbfdf0608
esi 0x80485f0 134514160
edi 0x80483e0 134513632
eip 0x80485d7 0x80485d7
eflags 0x10246 [ PF ZF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/i $eip
0x80485d7 :Cannot access memory at address 0x80485d7
(gdb) info frame
Stack level 0, frame at 0xbfdf0610:
eip = 0x80485d7 in fun_sigfpe (test.c:56); saved eip 0x8048561
called by frame at 0xbfdf0630
source language c.
Arglist at 0xbfdf05dc, args: x=0xbfdf0648
Locals at 0xbfdf05dc, Previous frame's sp is 0xbfdf0610
Saved registers:
ebp at 0xbfdf0608, eip at 0xbfdf060c
(gdb) q







====================================================
Now i have written a program, in which kernel would generate the core-dump
file because i have called abort() system call. This sample program display
the entries in a particular directory as we get by using utility "ls".
Now for demonstration purpose i take the number from the users which decide
whether abort() would be called or not. If we give numbers which is larger than the number of current entries in a particular directory,program exists
normally. Otherwise it display some entries and then make core-dump file for
this particular program.



// Test Program which generate SIGABRT signal.
// Purpose:: Display the basic information of each entry in a directory

#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#include"unistd.h"
#include"dirent.h"
#include"sys/types.h"
#include"sys/stat.h"
#define MAX_ENTRY 50

extern struct dirent *entry[MAX_ENTRY] = {NULL};
extern struct stat sb[MAX_ENTRY] = {NULL};
extern int abrtcounter = 0;

int open_read( char *);
void display_entry( int );


int main(int argc, char *argv[]) {

char *name;

name = malloc(40*sizeof(char));
memset(name, '\0', 40*sizeof(char));
if( argc !=3) {
strcpy(name, ".");
abrtcounter = 1000;
}
else {
strcpy(name, argv[1] );
abrtcounter = atoi(argv[2]);
}

open_read(name);

free(name);
return 0;
}


// Function for opening and reading the directory information
int open_read( char *dirname) {

DIR *dir;
int ret;
int i , nentry;

dir = opendir(dirname);
ret = dirfd(dir);
if(ret == -1) {
printf("Error while reading the directory\n");
return 1;
}

for(i =0;; i++) {
entry[i] = readdir(dir);
if (entry[i] == NULL)
break;
}
// Save the number of entries counter
nentry = i;

ret = closedir (dir);
if(ret == -1) {
printf("Error while closing the directory\n");
}

display_entry(nentry);

return nentry;
}


// Function for displaying each entry information
void display_entry( int nentry) {

int i,ret;
printf("Total Number of entries: %d\n", nentry);
printf("Inode\taccess\tlink\tUid\tGid\tSize\tName\n");

for(i = 0;i < nentry ;i++) {
ret = stat( entry[i]->d_name, &sb[i]);
if(i ==abrtcounter)
// This line would generate SIGABRT signal
abort();

printf("%d\t%d\t%d\t%d\t%d\t%d\t%s\n",(int)sb[i].st_ino,
sb[i].st_mode, sb[i].st_nlink, sb[i].st_uid, sb[i].st_gid,
(int )sb[i].st_size, entry[i]->d_name);
}

return;
}



Now lets compile and run this program. I have given otest as my program
file for above test program.

mantosh@ubuntu:~/Desktop$ ./otest
Total Number of entries: 10
Inode access link Uid Gid Size Name
491338 16877 7 1000 1000 4096 practice
184457 33188 1 1000 1000 1845 test.c
244715 33261 1 1000 1000 12274 otest
184451 33188 1 1000 1000 25812 blog.c
237904 16895 6 1000 1000 4096 .
240305 16877 105 1000 1000 4096 ..
245380 16877 3 1000 1000 4096 LinuxPI
524903 16877 2 1000 1000 4096 OSystem
184455 33188 1 1000 1000 8358 Core-Dump.c
531516 16877 6 1000 1000 4096 gnu-linux

mantosh@ubuntu:~/Desktop$ ./otest . 16
Total Number of entries: 10
Inode access link Uid Gid Size Name
491338 16877 7 1000 1000 4096 practice
184457 33188 1 1000 1000 1845 test.c
244715 33261 1 1000 1000 12274 otest
184451 33188 1 1000 1000 25812 blog.c
237904 16895 6 1000 1000 4096 .
240305 16877 105 1000 1000 4096 ..
245380 16877 3 1000 1000 4096 LinuxPI
524903 16877 2 1000 1000 4096 OSystem
184455 33188 1 1000 1000 8358 Core-Dump.c
531516 16877 6 1000 1000 4096 gnu-linux

mantosh@ubuntu:~/Desktop$ ./otest . 6
Total Number of entries: 10
Inode access link Uid Gid Size Name
491338 16877 7 1000 1000 4096 practice
184457 33188 1 1000 1000 1845 test.c
244715 33261 1 1000 1000 12274 otest
184451 33188 1 1000 1000 25812 blog.c
237904 16895 6 1000 1000 4096 .
240305 16877 105 1000 1000 4096 ..
Aborted (core dumped)



Now lets load the core-dump file into the gdb.

mantosh@ubuntu:~/Desktop$ gdb
(gdb) core core.26853
(no debugging symbols found)
Core was generated by `./otest . 6'.
Program terminated with signal 6, Aborted.
[New process 26853]
==> Signal 06(SIGABRT) was the reason for this core-dump file
==> pid of a program is 265853
#0 0xb7fb9430 in __kernel_vsyscall ()
(gdb) bt
#0 0xb7fb9430 in __kernel_vsyscall ()
#1 0xb7e676d0 in ?? ()
#2 0xb7e69098 in ?? ()
#3 0x08048880 in ?? ()
#4 0x08048806 in ?? ()
#5 0x0804874e in ?? ()
#6 0xb7e52775 in ?? ()
#7 0x08048611 in ?? ()
(gdb) symbol ./otest
Reading symbols from /home/mantosh/Desktop/otest...done.
(gdb) bt
#0 0xb7fb9430 in __kernel_vsyscall ()
#1 0xb7e676d0 in ?? ()
#2 0xb7e69098 in ?? ()
#3 0x08048880 in display_entry (nentry=10) at test.c:87
#4 0x08048806 in open_read (dirname=0x8f1c008 ".") at test.c:70
#5 0x0804874e in main (argc=3, argv=0xbfab6804) at test.c:36
(gdb) info frame
Stack level 0, frame at 0xbfab6588:
eip = 0xb7fb9430 in __kernel_vsyscall; saved eip 0xb7e676d0
called by frame at 0xbfab6598
Arglist at 0xbfab6580, args:
Locals at 0xbfab6580, Previous frame's sp is 0xbfab6588
Saved registers:
ebp at 0xbfab6578, eip at 0xbfab6584
(gdb) f 5
#5 0x0804874e in main (argc=3, argv=0xbfab6804) at test.c:36
36 open_read(name);
(gdb) info args
argc = 3
argv = (char **) 0xbfab6804
(gdb) x/4xw argv
0xbfab6804: 0xbfab86fb 0xbfab8703 0xbfab8705 0x00000000
(gdb) p argv
$1 = (char **) 0xbfab6804
(gdb) p *argv@3
$2 = {[0] = 0xbfab86fb "./otest",
[1] = 0xbfab8703 ".",
[2] = 0xbfab8705 "6"}
(gdb) info locals
name = 0x8f1c008 "."
(gdb) p abrtcounter
==> abrtcounter, sb[1], *entry[1] are global variable. So we can check
==> their values from any frame in the program.
$3 = 6
(gdb) p sb[1]
$4 = {
st_dev = 1792,
__pad1 = 0,
st_ino = 184457,
st_mode = 33188,
st_nlink = 1,
st_uid = 1000,
st_gid = 1000,
st_rdev = 0,
__pad2 = 0,
st_size = 1845,
st_blksize = 4096,
st_blocks = 8,
st_atim = {
tv_sec = 1298123976,
tv_nsec = 0
},
st_mtim = {
tv_sec = 1298123613,
tv_nsec = 0
},
st_ctim = {
tv_sec = 1298123613,
tv_nsec = 0
},
__unused4 = 0,
__unused5 = 0
}
(gdb) p entry[1]
$5 = (struct dirent *) 0x8f1c064
(gdb) p *entry[1]
$6 = {
d_ino = 184457,
d_off = 328961605,
d_reclen = 20,
d_type = 8 '\b',
d_name = "test.c\000\000\b��\003\000K��\035\024\000\botest\000\000\000\b\203�\002\000�~�2\024\000\bblog.c\000\000\bP�\003\000��\205>\020\000\004.\000\000\000\004��\003\000���A\020\000\004..\000\000\004\204�\003\000\031��C\024\000\004LinuxPI\000\004g\002\b\000s��T\024\000\004OSystem\000\004\207�\002\000���U\030\000\bCore-Dump.c\000\b<\034\b\000���\177\030\000\004gnu-linux\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
}
(gdb) ptype sb[1]
type = struct stat {
__dev_t st_dev;
short unsigned int __pad1;
__ino_t st_ino;
__mode_t st_mode;
__nlink_t st_nlink;
__uid_t st_uid;
__gid_t st_gid;
__dev_t st_rdev;
short unsigned int __pad2;
__off_t st_size;
__blksize_t st_blksize;
__blkcnt_t st_blocks;
struct timespec st_atim;
struct timespec st_mtim;
struct timespec st_ctim;
long unsigned int __unused4;
long unsigned int __unused5;
}
(gdb) ptype entry[1]
type = struct dirent {
__ino_t d_ino;
__off_t d_off;
short unsigned int d_reclen;
unsigned char d_type;
char d_name[256];
} *
(gdb) p *(struct stat *)0x8f1c064
==> Here i am just typecasting the address 0x8f1c064 which is of type
==>(struct dirent *). Notice how dangerous if we do typecast the different
==> kind of structures.Be careful while typecasting the pointers into the
==> other type into the program code.
$7 = {
st_dev = 1412879335114854537,
__pad1 = 20,
st_ino = 779383653,
st_mode = 134217827,
st_nlink = 244715,
st_uid = 498858059,
st_gid = 1862795284,
st_rdev = 576460754257143156,
__pad2 = 53379,
st_size = 852524765,
st_blksize = 1644691476,
st_blocks = 778530668,
st_atim = {
tv_sec = 134217827,
tv_nsec = 237904
},
st_mtim = {
tv_sec = 1048952490,
tv_nsec = 772014096
},
st_ctim = {
tv_sec = 67108864,
tv_nsec = 240305
},
__unused4 = 1103745453,
__unused5 = 772014096
}
(gdb) p &sb[1]
$8 = (struct stat *) 0x804a1b8
(gdb) p *(struct dirent *)0x804a1b8
==> Here i am typecasting the address 0x804a1b8 which is having type
==>(struct stat *) type into the (struct dirent *).
$9 = {
d_ino = 1792,
d_off = 0,
d_reclen = 0,
d_type = 0 '\0',
d_name = "\000\211�\002\000�\201\000\000\001\000\000\000�\003\000\000�\003\000\000\000\000\000\000\000\000\000\000\000\000\000\0005\a\000\000\000\020\000\000\b\000\000\000��_M\000\000\000\000]�_M\000\000\000\000]�_M\000\000\000\000\000\000\000\000\000\000\000\000\000\a\000\000\000\000\000\000\000\000\000\000��\003\000�\201\000\000\001\000\000\000�\003\000\000�\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000�/\000\000\000\020\000\000\030\000\000\000��_M\000\000\000\000\236�_M\000\000\000\000\236�_M\000\000\000\000\000\000\000\000\000\000\000\000\000\a\000\000\000\000\000\000\000\000\000\000\203�\002\000�\201\000\000\001\000\000\000�\003\000\000�\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000�d\000\000\000\020\000\0008\000\000\000��_M\000\000\000\000��_M\000\000\000\000��_M\000\000\000\000\000\000\000\000\000\000\000\000\000\a"
}
(gdb) bt
#0 0xb7fb9430 in __kernel_vsyscall ()
#1 0xb7e676d0 in ?? ()
#2 0xb7e69098 in ?? ()
#3 0x08048880 in display_entry (nentry=10) at test.c:87
#4 0x08048806 in open_read (dirname=0x8f1c008 ".") at test.c:70
#5 0x0804874e in main (argc=3, argv=0xbfab6804) at test.c:36
(gdb) info locals
name = 0x8f1c008 "."
(gdb) ptype name
type = char *
(gdb) p *(int *)(name -4)
==> Since name store the base address which has been returned from
==> heap. So if we go 4 byte lower to the base address and see the value
==> it would be more than the sizeof values has been passed to malloc.
==> In this case we passed 40, so we can see the value stored is 49. This
==> information would be used internally when we pass the base address to
==> free(). Please notice the concept which i have discussed is highly
==> system dependent and i am talking about the Linux machine.
$10 = 49
(gdb) frame 4
#4 0x08048806 in open_read (dirname=0x8f1c008 ".") at test.c:70
70 display_entry(nentry);
(gdb) info locals
dir = (DIR *) 0x8f1c038
ret = 0
i = 10
nentry = 10
(gdb) ptype dir
type = struct __dirstream {

} *
(gdb) p *dir
$12 =
(gdb) f 3
#3 0x08048880 in display_entry (nentry=10) at test.c:87
87 abort();
(gdb) info locals
i = 6
ret = 0
(gdb) p abrtcounter
$13 = 6
(gdb) p MAX_ENTRY
No symbol "MAX_ENTRY" in current context.
(gdb) info reg
eax 0x0 0
ecx 0x68e5 26853
edx 0x6 6
ebx 0x68e5 26853
esp 0xbfab66c0 0xbfab66c0
ebp 0xbfab6708 0xbfab6708
esi 0x3e8 1000
edi 0xb7f9aff4 -1208373260
eip 0x8048880 0x8048880
eflags 0x246 [ PF ZF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/i $eip
0x8048880 :Cannot access memory at address 0x8048880
(gdb) bt full
#0 0xb7fb9430 in __kernel_vsyscall ()
No symbol table info available.
#1 0xb7e676d0 in ?? ()
No symbol table info available.
#2 0xb7e69098 in ?? ()
No symbol table info available.
#3 0x08048880 in display_entry (nentry=10) at test.c:87
i = 6
ret = 0
#4 0x08048806 in open_read (dirname=0x8f1c008 ".") at test.c:70
dir = (DIR *) 0x8f1c038
ret = 0
i = 10
nentry = 10
#5 0x0804874e in main (argc=3, argv=0xbfab6804) at test.c:36
name = 0x8f1c008 "."
(gdb) quit

Friday, February 18, 2011

~Core-dump Analysis - I~

Today we would discuss the basics of core-dump analysis on GNU/Linux machine.
I would try to cover topics like:

* What extra do we need while compiling the program?
* Why & When Kernel try to make core-dump of a process?
* Do we need to set/enable parameter in order to create core-dump?
* How many ways we can get core-dump of a process?
* Sample Programs which sends various signals to kernel?
* Analysis of core-dump using gdb.



Q. What extra do we need while compiling the program?
Using -g flag in gcc generates the extra symbols which would be useful
while debugging and while analyzing the core-dump analysis. Even if you
don't have the object file compiled with -g option, we can have core-dump
file for a process. But sometime these core file may not be of use for
analysis. So if possible,try to compile your program with -g option. Following commands generates the object file "osource" for the source file
"source.c" with extra symbol.

mantosh@ubuntu:~$ gcc -Wall -g source.c -o osource
mantosh@ubuntu:~$ gcc -save-temps -g source.c -o osource



Q. Why & When Kernel try to make core-dump of a process?
Signal is a notification to a process that an event has occurred. Signals
are sometimes described as software interrupts. The usual source of many
signals sent to a process is the kernel. A signal is said to be generated
by some event. Once generated, a signal is later delivered to a process,
which then takes some action in response to the signal. Upon delivery of
a signal, a process carries out one of the following default actions,
depending on the signal: "ignored", "terminated", "core-dump file". Detailed information can be found on these by doing "man core" and
"man signal" on our machine terminal.




Q. Do we need to set/enable parameter in order to create core-dump?
Yes. On most of machine we need to set some kernel parameter in order to
enable the core-dump file. Just check the output of the following command.


mantosh@ubuntu:~$ ulimit -a
core file size (blocks, -c) 0 ==>default core file size is 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 20
file size (blocks, -f) unlimited
pending signals (-i) 16382
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited


mantosh@ubuntu:~$ cat /proc/sys/kernel/core_uses_pid
0 ==>By setting this parameter to 1,kernel would generate the core
==>file name ike core.pid in our current working directory.

mantosh@ubuntu:~$ cat /proc/sys/kernel/core_pattern
core


The core file size can be changed to unlimited size by the command.
mantosh@ubuntu:~$ ulimit -c unlimited

Similarly we can generate the core file like core.pid by setting the
mantosh@ubuntu:~$ echo 1 > /proc/sys/kernel/core_uses_pid
mantosh@ubuntu:~$ cat /proc/sys/kernel/core_uses_pid
1



Now kernel should be able to generate the core-dump file. Please note that
these setting should be done using the "root" user in order to take effect.






Q. How many ways we can get core-dump of a process?
We can get a core-dump in 3 ways. These are :
1. If program is running and does like invalid memory reference,floating point exception or trying to execute invalid instruction,kernel would
generate the core-dump file for that particular process.
2. we can call abort() system call inside our program. When program executes abort(),process will be aborted and kernel would take the
core-dump of a program which would contain the information of a program before abort() call.
3. While debugging our program using gdb, we can use "gcore" command which
generate the core file. The biggest advantage of "gcore" is that you can get core-dump at anytime,(i.e its on user when he/she want to generate core file).





=====================================================
Sample Program which i would be using to demonstrate the concept of core-
dump. I have written most of test program which uses multiple function
calls, global variable, multiple local variable, so that while analysing we
would have so many variables and stacktrace. Now lets start some actual stuff :)



// Test Program:: 1, Langauge :c++
// Purpose:: Fetch the basic information about a filename provided by the
user.


#include"iostream"
#include"cstring"
#include"cstdlib"
#include"fcntl.h"
#include"sys/stat.h"
using namespace std;
// class declaration
class fileinfo {
private:
char *filename;
int filedp;
struct stat status;
int success_flag;
public:
fileinfo(char *fname);
int file_open();
int file_stat();
int file_close();
void file_information();
~fileinfo();
};

// Constructor
fileinfo :: fileinfo(char *fname) {
filedp = -1;
success_flag = 0;
memset(&status, 0, sizeof(struct stat));
int length = strlen(fname);
filename = (char *)malloc(length);
strcpy(filename,fname);
}

// Member function for open the file by calling open()
int fileinfo :: file_open() {
filedp = open(filename,O_RDONLY);
if(-1 == filedp)
cout << "Error while opening the " < else
success_flag = 1;
return success_flag;
}

//Member function for getting information about particular file
int fileinfo :: file_stat() {
int retv;
retv = fstat(filedp, &status);
if(-1 == retv)
cout << "Error while getting status of "< else
success_flag = 1;
return success_flag;
}

// Main member function for displaying the basics information about file,
// if we are able to open a file and able to do successfull call of fstat()

void fileinfo :: file_information() {
int retv;
retv = file_open();
if(1 == retv) {
retv = file_stat();
if(1==retv) {
cout << "File: " << filename << "\n";
cout << "Inode: " << status.st_ino << "\n";
cout << "Links: " << status.st_nlink <<"\n";
cout <<"Size: " << status.st_size << "\n";
}
}
file_close();
}

// Member function for closing the file by calling close()
int fileinfo :: file_close() {
int retv;
retv = close(filedp);
if(-1== retv)
cout << "Error while closing the " << filename << " file\n";
else
success_flag = 1;
return success_flag;
}

// Destructor
fileinfo :: ~fileinfo() {

free(filename);
}

// Main program which usage all above functions.
int main(int argc, char *argv[]) {

if(argc !=2) {
cout <<"Invalid Usage:"<< argv[0] <<" \n";
return 1;
}

char *name = argv[1];
fileinfo f1(name);
f1.file_information();
return 0;
}




==> Now we should compile using g++ and run the program "otest" inside gdb,
==> so that we should be able to take core-dump using gcore command.


mantosh@ubuntu:~/Desktop$ gdb --args ./otest blog.c
(gdb) b main
Breakpoint 1 at 0x8048c84: file test.cc, line 93.
(gdb) b fileinfo :: ~fileinfo()
Breakpoint 2 at 0x8048956: file test.cc, line 87. (2 locations)
(gdb) r
Starting program: /home/mantosh/Desktop/otest blog.c

Breakpoint 1, main (argc=2, argv=0xbfc436d4) at test.cc:93
93 if(argc !=2) {
(gdb) bt
#0 main (argc=2, argv=0xbfc436d4) at test.cc:93
(gdb) n
98 char *name = argv[1];
(gdb)
99 fileinfo f1(name);
(gdb)
100 f1.file_information();
(gdb)
File: blog.c
Inode: 244585
Links: 1
Size: 4640
101 return 0;
(gdb) c
Continuing.

Breakpoint 2, ~fileinfo (this=0xbfc435c4) at test.cc:87
87 free(filename);
(gdb) bt
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
(gdb) help gcore
Save a core file with the current state of the debugged process.
Argument is optional filename. Default filename is 'core.'.
(gdb) gcore
Saved corefile core.9987 ==> core file name is " core.9987"
(gdb) q
The program is running. Exit anyway? (y or n) y




// Now we can do core-dump analysis which we just generated by the command // gcore inside gdb. See my explaination during the analysis which i have
// put using prefix ==>

mantosh@ubuntu:~/Desktop$ gdb

(gdb) core core.9987 ==>load core.9987 in gdb session
(no debugging symbols found)
Core was generated by `/home/mantosh/Desktop/otest blog.c'.
Program terminated with signal 5, Trace/breakpoint trap.
[New process 9987]
==> signal 5(SIGTRAP) was the reason for this core-file
==> process id was 9987.
#0 0x08048956 in ?? ()
(gdb) bt
==>backtrace of program without loading the symbol
#0 0x08048956 in ?? ()
#1 0x08048d13 in ?? ()
#2 0xb7dd5775 in ?? ()
#3 0x08048861 in ?? ()
(gdb) symbol ./otest
==> Load symbol otest
Reading symbols from /home/mantosh/Desktop/otest...done.
(gdb) bt
==>Now we get the actual backtrace of a prgram
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
(gdb) frame 1
==>select frame 1
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
101 return 0;
(gdb) info args
==>for displaying arguments information for frame 1
argc = 2
argv = (char **) 0xbfc436d4
(gdb) p argv[0]
$1 = 0xbfc456cb "/home/mantosh/Desktop/otest"
(gdb) p argv[1]
$2 = 0xbfc456e7 "blog.c"
(gdb) p argv[2]
$3 = 0x0
(gdb) x/3xw argv
==>display the addresses of argv[0], argv[1], note how
==> argv is null terminated.
0xbfc436d4: 0xbfc456cb 0xbfc456e7 0x00000000
(gdb) info locals
==> for displaying the locals variables inside frame 1
name = 0xbfc456e7 "blog.c"
f1 = {
filename = 0x896f008 "blog.c",
filedp = 6,
status = {
st_dev = 1792,
__pad1 = 0,
st_ino = 244585,
st_mode = 33188,
st_nlink = 1,
st_uid = 1000,
st_gid = 1000,
st_rdev = 0,
__pad2 = 0,
st_size = 4640,
st_blksize = 4096,
st_blocks = 16,
st_atim = {
tv_sec = 1298087485,
tv_nsec = 0
},
st_mtim = {
tv_sec = 1298085235,
tv_nsec = 0
},
st_ctim = {
tv_sec = 1298085235,
tv_nsec = 0
},
__unused4 = 0,
__unused5 = 0
},
success_flag = 1
}
(gdb) ptype f1
==>type information of any variable(Here object of class
==>fileinfo which is f1).
type = class fileinfo {
private:
char *filename;
int filedp;
stat status;
int success_flag;

public:
fileinfo(char *);
int file_open();
int file_stat();
int file_close();
void file_information();
~fileinfo(int);
}
(gdb) p sizeof(f1)
==> size of object f1
$4 = 100
(gdb) p name
$5 = 0xbfc456e7 "blog.c"
(gdb) x/10cb name
0xbfc456e7:98 'b' 108 'l' 111 'o' 103 'g' 46 '.' 99 'c' 0 '\0' 79 'O'
0xbfc456ef:82 'R' 66 'B'
(gdb) p &f1
==> address of object f1 of type fileinfo class
$6 = (fileinfo *) 0xbfc435c4
(gdb) x/25xw &f1
==> the above command would display the 25 unit of size word(which is 4byt)
==> in hexadecimal format.(x/nfu). 1st unit store the address of filename
==> which is(0x0896f008). Next unit store the variable filedp value which
==> is 6 and so on ...we can interpret in different ways of the information
==> stored into the address &f1.
0xbfc435c4: 0x0896f008 0x00000006 0x00000700 0x00000000
0xbfc435d4: 0x00000000 0x0003bb69 0x000081a4 0x00000001
0xbfc435e4: 0x000003e8 0x000003e8 0x00000000 0x00000000
0xbfc435f4: 0x00000000 0x00001220 0x00001000 0x00000010
0xbfc43604: 0x4d5f3e3d 0x00000000 0x4d5f3573 0x00000000
0xbfc43614: 0x4d5f3573 0x00000000 0x00000000 0x00000000
0xbfc43624: 0x00000001
(gdb) x/10cb 0x0896f008
==> this would print the f1->filename, since filename has been stored at
==> 1st offset of object f1.
0x896f008: 98 'b' 108 'l' 111 'o' 103 'g' 46 '.' 99 'c' 0 '\0' 0 '\0'
0x896f010: 0 '\0' 0 '\0'

(gdb) p f1.filedp
$7 = 6
(gdb) p/d 0x00000006
==> print the decimal eqv of hex val 0x00000006
$8 = 6
(gdb) p f1.status.st_dev
$9 = 1792
(gdb) p sizeof(f1.status.st_dev)
$10 = 8
(gdb) p/x 1792
$11 = 0x700
(gdb) p/d 0x00000700
$12 = 1792
(gdb) p f1.status.st_ino
$13 = 244585
(gdb) p f1.status.st_nlink
$14 = 1
(gdb) x/25dw &f1
==> print the 25 unit information in decimal from starting address &f1
0xbfc435c4: 144109576 6 1792 0
0xbfc435d4: 0 244585 33188 1
0xbfc435e4: 1000 1000 0 0
0xbfc435f4: 0 4640 4096 16
0xbfc43604: 1298087485 0 1298085235 0
0xbfc43614: 1298085235 0 0 0
0xbfc43624: 1
(gdb) p/x 144109576
$15 = 0x896f008
(gdb) bt
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
(gdb) f 0
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
87 free(filename);
(gdb) info locals
No locals.
(gdb) info args
==> Note how internally this pointer passed to its member function in cpp .
this = (fileinfo * const) 0xbfc435c4
(gdb) p sizeof(*this)
$16 = 100
(gdb) p filename
$17 = 0x896f008 "blog.c"
(gdb) info reg
==> This would display the value/state of various registers at the time of core-file was generated.
eax 0xbfc435c4 -1077660220
ecx 0x1 1
edx 0x1220 4640
ebx 0xb7f1dff4 -1208885260
esp 0xbfc43590 0xbfc43590
ebp 0xbfc43598 0xbfc43598
esi 0x8048de0 134516192
edi 0x8048840 134514752
eip 0x8048956 0x8048956 <~fileinfo+6 at test.cc:87>
eflags 0x200286 [ PF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) p $eax
==> for printing the registers values use prefix $
$18 = -1077660220
(gdb) p/x -1077660220
==> we can see from here $eax store the "this" pointer.
$19 = 0xbfc435c4
(gdb) p this
$19 = (fileinfo * const) 0xbfc435c4
(gdb) x/i $eip
==> $eip store the next instruction which was supposed to be executed. Most
==> of time $eip would store the information of instruction which cause the
==> trouble. See your processor architecure manual for understanding of
==> various regeisters utility.
0x8048956 <~fileinfo+6 at test.cc:87>:Cannot access memory at address 0x8048956
(gdb) bt
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
(gdb) info frame
==> for getting additional information of a prticular selected frame
Stack level 0, frame at 0xbfc435a0:
eip = 0x8048956 in ~fileinfo (test.cc:87); saved eip 0x8048d13
called by frame at 0xbfc43640
source language c++.
Arglist at 0xbfc4358c, args: this=0xbfc435c4
Locals at 0xbfc4358c, Previous frame's sp is 0xbfc435a0
Saved registers:
ebp at 0xbfc43598, eip at 0xbfc4359c
(gdb) bt
#0 ~fileinfo (this=0xbfc435c4) at test.cc:87
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
(gdb) f 1
#1 0x08048d13 in main (argc=2, argv=0xbfc436d4) at test.cc:101
101 return 0;
(gdb) info frame
Stack level 1, frame at 0xbfc43640:
eip = 0x8048d13 in main (test.cc:101); saved eip 0xb7dd5775
caller of frame at 0xbfc435a0
source language c++.
Arglist at 0xbfc4359c, args: argc=2, argv=0xbfc436d4
Locals at 0xbfc4359c, Previous frame's sp at 0xbfc4362c
Saved registers:
ebx at 0xbfc43630, ebp at 0xbfc43638, esi at 0xbfc43634, eip at 0xbfc4363c
(gdb) q



Please see my the next article on the same topic.

Tuesday, February 1, 2011

~/proc Directory~

Hello Everyone,

In this article we would discuss about the /proc directory. GNU/Linux maintains the detailed information about each process in directory /proc.
I would update the basics information/layout of each process shortly.
However i have written shell script which take PID of a process as input
and display detailed information in one go........Here is the pstate.sh script.


#########################################################


#!/bin/sh

# Copyright (C) 2011 Free Software Foundation, Inc.
# Author : Mantosh Kumar, mantosh4u@gmail.com

# The GNU Script is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# The GNU Script 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 Lesser General Public License for more details.


################Brief Description##################
# The script name would be "pstate.sh". The script would take the PID as
# argument and check whether the process exists or not. If process is there,
# then script should give the whole set of information about the process in
# organized manner, so that user would be having whole set of information
# at one go. Just Type " ps aux " on terminal and check about the number of
# processes running on your machine. Now you can select any PID to enter
# while running with this script.This script works fine most of time, but
# in case if user wants to get info about processess like pid:1(init),
# he/she needs to run this as root user.This scripts does not work sometime
# for the processes which has opened file and file number are not in
# sequence.


echo -n "The detailed status information of a particular process\n";
echo -n "=================================";
echo -n "=======================\n";

# The most important input argument would be passed from the user, which
# can be accessed from $1 value.Lets save into Global variable.Since we
# have defined this variable which is not inside any scope.
PID=$1;

# Now declare other variable which should be dedicated directory for a
# process mantained by the kernel. Before processing further we should
# check whether directory exists or not. If process is still there, there
# would be directory in /proc If directory exists go on or else immediately
# return, by giving user message like process does not exists.This is also
# Global variable.
proc_direct=/proc/$PID;



# Shell function for fetching system info and current time as well as date.

sys_time() {

local sys_name=`uname`;
local sys_month=`date +%B`;
local sys_date=`date +%d`;
local sys_year=`date +%Y`;
local sys_minute=`date +%M`;
local sys_second=`date +%S`;

echo -n "System:$sys_name, $sys_month $sys_date, $sys_year "
echo -n "$sys_minute:$sys_second\n";
}



# Shell function for fetching process control info of a given PID.

pid_process() {


# status.log file would contain the all information releated to
# process Now /proc/[pid]/status file contains all stuff, just
# redirecting to temp.log
cat $proc_direct/status > $PWD/status.log;

#echo -n "pwd: $PWD\n";
#Processing for pid, Ppid,Process Name, State, Thread Counter value
pid_proc=`awk '$1 == "Pid:" { print $2 }' status.log`;
ppid_proc=`awk '$1 == "PPid:" { print $2 }' status.log`;
p_name=`awk '$1 == "Name:" { print $2 }' status.log`;
p_state=`awk '$1 == "State:" { print $2 }' status.log`;
thread_c=`awk '$1 == "Threads:" { print $2 }' status.log`;
echo -n "Process Name\t:$p_name\n";
echo -n "State\t\t:$p_state\n";
echo -n "Pid\t\t:$pid_proc\n";
echo -n "Parent Pid\t:$ppid_proc\n";
echo -n "Threads\t\t:$thread_c\n";

#Priority of process
cat $proc_direct/sched > $PWD/sched.log;
p_priority=`awk '$1 == "prio" { print $3 }' sched.log`;
echo -n "Priority\t:$p_priority\n";

#Uid & Gid Information of User
p_uid=`awk '$1 == "Uid:" { print $2 }' status.log`;
p_guid=`awk '$1 == "Gid:" { print $2 }' status.log`;
echo -n "Uid\t\t:$p_uid\n";
echo -n "Gid\t\t:$p_guid\n\n";


#Memory Management Information
VmPeak=`awk '$1 == "VmPeak:" { print $2 }' status.log`;
VmSize=`awk '$1 == "VmSize:" { print $2 }' status.log`;
VmLck=`awk '$1 == "VmLck:" { print $2 }' status.log`;
VmHWM=`awk '$1 == "VmHWM:" { print $2 }' status.log`;
VmRSS=`awk '$1 == "VmRSS:" { print $2 }' status.log`;
VmData=`awk '$1 == "VmData:" { print $2 }' status.log`;
VmStk=`awk '$1 == "VmStk:" { print $2 }' status.log`;
VmExe=`awk '$1 == "VmExe:" { print $2 }' status.log`;
VmLib=`awk '$1 == "VmLib:" { print $2 }' status.log`;
VmPTE=`awk '$1 == "VmLib:" { print $2 }' status.log`;

echo -n "Peak Virtual Memory Size\t:$VmPeak\n";
echo -n "Current Virtual Memory Size\t:$VmSize\n";
echo -n "Locked Memory Size\t\t:$VmLck\n";
echo -n "Peak resident Set Size\t\t:$VmHWM\n";
echo -n "Current Resident Set Size\t:$VmRSS\n";
echo -n "Data Segment Size\t\t:$VmData\n";
echo -n "Stack Size\t\t\t:$VmStk\n";
echo -n "Text(Instruction) Size\t\t:$VmExe\n";
echo -n "Shared library Code Size\t:$VmLib\n";
echo -n "Page Table Size\t\t\t:$VmPTE\n";

#Now purge the two log files which we created inside this function
# status.log, sched.log
rm sched.log;
rm status.log;

}


# Shell function for displaying detailed map section of virtual memory
# of process.

pid_maps() {

#cat /proc/$PID/maps
echo -n "\n";
echo -n "Detailed Information about the memory map section\n";
echo -n "================================";
echo -n "=================\n";
cat $proc_direct/maps;

}



#Shell function for displaying basic info about files opend by PID.

pid_fileinformation() {

echo -n "\n";
echo -n "The detailed information about the files opened"
echo -n "by process\n";
echo -n "================================";
echo -n "==========================\n";
echo -n "\n";

fcounter=`ls $proc_direct/fd | wc -w`;
echo -n "Number of files opened by the process\t\t:$fcounter\n\n";

#change the cwd to the location $proc_direct/fdinfo, so that we can
#directoly use the stat utility for each of file number
cd $proc_direct/fd;

#Now Use Loop so that we get basics information about each of
# file number.

count=0;
while [ $count -lt $fcounter ] ; do
echo -n "Information about filenumber: $count\n";
echo -n "-------------------------------\n";

#stat $count;
filename=`stat -c %N $count`;
filetype=`stat -c %F $count`;
access=`stat -c %A $count`;
owner=`stat -c %U $count`;
size=`stat -c %s $count`;

echo -n "FileName\t:$filename\n";
echo -n "FileType\t:$filetype\n";
echo -n "Size\t\t:$size\n";
echo -n "Owner\t\t:$owner\n";
echo -n "Access\t\t:$access\n";
echo -n "\n";

count=`expr $count + 1`
done
}



# Main Body of Script, Each of above function has been called from this
# area. We can assume this as main function of C program.

if [ -d $proc_direct ]
then

sys_time
echo -n "\n";
pid_process
pid_maps
pid_fileinformation

else
echo -n "\n";
echo -n "Process(PID:$PID) does not exist on the system\n";

fi




#################################################################



Output:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mantosh@ubuntu:~$ ./pstate.sh 8417
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



The detailed status information of a particular process
========================================================
System:Linux, February 02, 2011 33:37

Process Name :ocat
State :T
Pid :8417
Parent Pid :8416
Threads :1
Priority :120
Uid :1000
Gid :1000

Peak Virtual Memory Size :1748
Current Virtual Memory Size :1652
Locked Memory Size :0
Peak resident Set Size :288
Current Resident Set Size :280
Data Segment Size :28
Stack Size :84
Text(Instruction) Size :4
Shared library Code Size :1504
Page Table Size :1504

Detailed Information about the memory map section
=================================================
08048000-08049000 r-xp 00000000 07:00 248189 /home/mantosh/Desktop/LinuxPI/ocat
08049000-0804a000 r--p 00000000 07:00 248189 /home/mantosh/Desktop/LinuxPI/ocat
0804a000-0804b000 rw-p 00001000 07:00 248189 /home/mantosh/Desktop/LinuxPI/ocat
b7e38000-b7e39000 rw-p b7e38000 00:00 0
b7e39000-b7f95000 r-xp 00000000 07:00 33170 /lib/tls/i686/cmov/libc-2.9.so
b7f95000-b7f96000 ---p 0015c000 07:00 33170 /lib/tls/i686/cmov/libc-2.9.so
b7f96000-b7f98000 r--p 0015c000 07:00 33170 /lib/tls/i686/cmov/libc-2.9.so
b7f98000-b7f99000 rw-p 0015e000 07:00 33170 /lib/tls/i686/cmov/libc-2.9.so
b7f99000-b7f9c000 rw-p b7f99000 00:00 0
b7fb4000-b7fb6000 rw-p b7fb4000 00:00 0
b7fb6000-b7fb7000 r-xp b7fb6000 00:00 0 [vdso]
b7fb7000-b7fd3000 r-xp 00000000 07:00 577782 /lib/ld-2.9.so
b7fd3000-b7fd4000 r--p 0001b000 07:00 577782 /lib/ld-2.9.so
b7fd4000-b7fd5000 rw-p 0001c000 07:00 577782 /lib/ld-2.9.so
bfbca000-bfbdf000 rw-p bffeb000 00:00 0 [stack]

The detailed information about the files opened by process
==========================================================

Number of files opened by the process :6

Information about filenumber: 0
-------------------------------
FileName :`0' -> `/dev/pts/0'
FileType :symbolic link
Size :64
Owner :mantosh
Access :lrwx------

Information about filenumber: 1
-------------------------------
FileName :`1' -> `/dev/pts/0'
FileType :symbolic link
Size :64
Owner :mantosh
Access :lrwx------

Information about filenumber: 2
-------------------------------
FileName :`2' -> `/dev/pts/0'
FileType :symbolic link
Size :64
Owner :mantosh
Access :lrwx------

Information about filenumber: 3
-------------------------------
FileName :`3' -> `pipe:[44415]'
FileType :symbolic link
Size :64
Owner :mantosh
Access :lr-x------

Information about filenumber: 4
-------------------------------
FileName :`4' -> `pipe:[44415]'
FileType :symbolic link
Size :64
Owner :mantosh
Access :l-wx------

Information about filenumber: 5
-------------------------------
FileName :`5' -> `/home/mantosh/Desktop/LinuxPI/ocat'
FileType :symbolic link
Size :64
Owner :mantosh
Access :lr-x------




Hope that this article might be of some use for the reader. Feel free to put yours comment.