User talk:Srikanth007m

Strace and the GDB Debugger
The UNIX family has always provided abundantly for its users. UNIX is a treasure chest of tools with which you can not only do productive work but also educate and entertain yourself as you explore the depths of the operating system. Two useful tools for this purpose are strace, with which you can trace the system calls of any program, and the GDB Debugger, which is a full-featured debugger that allows you to run programs in a controlled environment.

The UNIX design consists of hundreds of function calls (called system calls) covering simple tasks, such as displaying a character string on the screen to setting task priorities. All UNIX programs accomplish their tasks by calling these low-level services that the operating system provides, and with the strace tool, you can actually see these calls and the parameters that they use. In this way, you can actually play with programs to learn about their low-level interactions with the operating system.

Let's begin
Let's begin by examining a simple UNIX command -- pwd -- and then dive deeper into what the command does to accomplish its purpose. Launch an xterm to create a controlled environment to experiment with, and then type the command:

$ pwd

The pwd command displays the current working directory. The output on my computer at that moment in time was:

/home/foo/

Such a simple function belies the complexity beneath the surface of the command (as do all computer programs, by the way). To get a picture of this complexity, run the pwd command again using the strace tool:

$ strace pwd

With that command, you can see just how much goes on in the UNIX machine to discover and list the current working directory you're in Output of the strace pwd command execve("/bin/pwd", ["pwd"], [/* 49 vars */]) = 0 brk(0)                                 = 0x608000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90735f000 access("/etc/ld.so.nohwcap", F_OK)     = -1 ENOENT (No such file or directory) mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90735d000 access("/etc/ld.so.preload", R_OK)     = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY)     = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=115733, ...}) = 0 mmap(NULL, 115733, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff907340000 close(3)                               = 0 access("/etc/ld.so.nohwcap", F_OK)     = -1 ENOENT (No such file or directory) open("/lib/libc.so.6", O_RDONLY)       = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\342"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1436976, ...}) = 0 mmap(NULL, 3543672, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff906de1000 mprotect(0x7ff906f39000, 2097152, PROT_NONE) = 0 mmap(0x7ff907139000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x158000) = 0x7ff907139000 mmap(0x7ff90713e000, 17016, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff90713e000 close(3)                               = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90733f000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90733e000 arch_prctl(ARCH_SET_FS, 0x7ff90733e6e0) = 0 mprotect(0x7ff907139000, 12288, PROT_READ) = 0 munmap(0x7ff907340000, 115733)         = 0 brk(0)                                 = 0x608000 brk(0x629000)                          = 0x629000 open("/usr/lib/locale/locale-archive", O_RDONLY) = -1 ENOENT (No such file or directory) open("/usr/share/locale/locale.alias", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=2586, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90735c000 read(3, "# Locale name alias data base.\n#"..., 4096) = 2586 read(3, "", 4096)                      = 0 close(3)                               = 0 munmap(0x7ff90735c000, 4096)           = 0 getcwd("/", 4096)                      = 2 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff90734e000 write(1, "/\n", 2/ )                     = 2 close(1)                               = 0 munmap(0x7ff90734e000, 4096)           = 0 close(2)                               = 0 exit_group(0)                          = ?

nweb
For the next steps, you need something larger and more complex than a simple UNIX command like pwd. A simple Hypertext Transfer Protocol (HTTP) server, such as nweb, is perfect. An HTTP server listens for your browser requests when you're surfing the Internet, and then responds to your browser requests by sending the objects you're requesting, such as Web pages and graphics files.

This is a simple Web server that has only 200 lines of C source code. It runs as a regular user and can't run any server-side scripts or programs, so it can't open up any special privileges or security holes.

Download and install nweb. After downloading es-nweb.zip to your $HOME/downloads directory, type the simple commands shown in Listing 2 to extract, compile, and launch the program: $ cd src $ mkdir nweb $ cd nweb $ unzip $HOME/downloads/es-nweb.zip $ gcc -ggdb -O -DLINUX nweb.c -o nweb $ ./nweb 9090 $HOME/src/nweb &

Next, to verify that the nweb server is running, use the ps command to check it.

$ ps PID TTY         TIME CMD 2913 pts/5   00:00:00 bash 4009 pts/5   00:00:00 nweb 4011 pts/5   00:00:00 ps

Finally, to verify that nweb is really running and that all is correct, launch a Web browser on your computer and type http://localhost:9090 in the address bar.

Using strace with nweb

Now, let's have some fun. Launch another xterm, and then use strace to trace the nweb server that is running. To do so, you must know the process ID of the program, and you must have the appropriate permissions. You'll watch only a specific set of system calls -- those related to networking. Begin by typing the command as shown below.

Starting a trace of nweb $ strace -e trace=network -p 4009 accept(0,

Notice that the trace has stopped in the middle of a call to the network accept function. Refresh the http://localhost:9090 page in your browser a few times, and notice what strace displays each time you refresh the page. Isn't that great? What you are watching is a low-level network call by the HTTP server, nweb, when it has been called by your Web browser. Simply put, nweb is accepting your browser's call.

You can stop tracing the network calls on the running nweb process by pressing Ctrl+C when the xterm in which the strace is running has the window focus.

On to the GDB Debugger

As you saw, strace can be a great program for learning how user programs interact with the operating system through certain system calls. The GDB Debugger can also attach itself to a currently running process and help you to dig even deeper.

The GDB Debugger is such a useful tool that a lot of information about it is available on the Internet. Debuggers in general are valuable tools, and anyone responsible for the development and upkeep of a computer system should know how to use them. So, while nweb is still running in another xterm session, halt the strace by pressing Ctrl+C, and then launch the GDB Debugger by typing the commands shown below. $ gdb --quiet (gdb) attach 4009 Attaching to process 4009 Reading symbols from /home/bill/src/nweb/nweb...done. Reading symbols from /lib/tls/libc.so.6...done. Loaded symbols for /lib/tls/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 0xffffe410 in ?? (gdb)

The -quiet option tells the GDB Debugger to display only its prompt and not all the other startup information that it typically displays. If you want the extra text, leave the -quiet option off.

The attach 4009 command starts debugging the currently running nweb server, and the GDB Debugger responds in kind by reading all the symbolic information about the process it can. Next, use the info command to list information about the program you're exploring.

The info command lists program information (gdb) info proc process 4009 cmdline = './nweb' cwd = '/home/bill/src/nweb' exe = '/home/bill/src/nweb/nweb' (gdb)

Another useful variant of the info command is info functions; however, the list of functions can be very long. Functions list from the info functions command (gdb) info functions All defined functions: File nweb.c: void log(int, char *, char *, int); int main(int, char **); void web(int, int); File __finite: int __finite; . . . (gdb)

Because you compiled the nweb program with the -ggdb option, a lot of debugging information was included in the executable, allowing the debugger to see the defined functions listed by file, as shown below.

The list and disassemble commands

Two important GDB Debugger commands are list and disassemble. Try these commands by working with the code. (gdb) list main 121            exit(1); 122    } 123 124 125     main(int argc, char **argv) 126    { 127             int i, port, pid, listenfd, socketfd, hit; 128            size_t length; 129            char *str; 130            static struct sockaddr_in cli_addr; /* static = initialised to zeros */ (gdb) 131            static struct sockaddr_in serv_addr; /* static = initialised to zeros */ 132 133            if( argc < 3  || argc > 3 || !strcmp(argv[1], "-?") ) { 134                    (void)printf("hint: nweb Port-Number Top-Directory\n\n" 135             "\tnweb is a small and very safe mini web server\n" 136             "\tnweb only servers out file/web pages with extensions named below\n" 137             "\t and only from the named directory or its sub-directories.\n" 138             "\tThere is no fancy features = safe and secure.\n\n" 139             "\tExample: nweb 8181 /home/nwebdir &\n\n" 140             "\tOnly Supports:");

As you can see, the list command lists the running program in source form with line numbers. Pressing the Return key (shown between lines 130 and 131) simply continues listing from where the last list left off. Now, try the disassemble command, which you can abbreviate to disass (gdb) disass main Dump of assembler code for function main: 0x08048ba2 :   push   ebp 0x08048ba3 :   mov    ebp,esp 0x08048ba5 :   push   edi 0x08048ba6 :   push   esi 0x08048ba7 :   push   ebx 0x08048ba8 :   sub    esp,0xc 0x08048bab :   mov    ebx,DWORD PTR [ebp+12] 0x08048bae :  and    esp,0xfffffff0 .	.	. 0x08048c01 :  call   0x8048664 0x08048c06 : add    esp,0x10 0x08048c09 : inc    esi 0x08048c0a : cmp    DWORD PTR [ebx+esi],0x0 ---Type to continue, or q to quit---

This disassembly listing shows the assembler-language listing of the main function. In this case, the assembler code indicates that the computer running the code has an Intel® Pentium® processor.

Watching it live

Because you're watching an actual running program, you can set breakpoints, and then see the program as it replies to browser requests and transmits .html and .jpg files to the browser making the request. (gdb) break 188 Breakpoint 1 at 0x8048e70: file nweb.c, line 188. (gdb) commands 1 Type commands for when breakpoint 1 is hit, one per line. End with a line saying just "end". continue end (gdb) c Continuing.

At this point, the GDB Debugger is set to break at the line where the nweb server accepts browser requests; the debugger will simply display the request and continue processing other requests without interrupting the running program. Refresh the http://localhost:9090/ page in your browser a few times, and watch the GDB Debugger display the breakpoint and continue running.

While refreshing the browser page, you should see breakpoint information, such as that shown below, scrolling in the GDB Debugger xterm. Just as with strace, you can stop debugging the nweb server by pressing Ctrl+C. After stopping the tracing, you can exit the GDB Debugger by typing the quit command.

Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188 188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188 188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188 188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) Breakpoint 1, main (argc=3, argv=0x1) at nweb.c:188 188 if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) Program received signal SIGINT, Interrupt. 0xffffe410 in ?? (gdb) quit The program is running. Quit anyway (and detach it)? (y or n) y Detaching from program: /home/bill/src/nweb/nweb, process 4009 $

Notice that you're telling the GDB Debugger to quit debugging a program that is still active in memory. Even after leaving the debugger, you can refresh the browser page and see that nweb is still running. You can halt the program by typing the kill 4009 command, or the page will disappear when you leave your session.

As always, you can learn a lot about tools, such as strace and the GDB Debugger, from their man and info pages. Be sure to use the tools that UNIX provides you!