Shuva's blog
Recently learned vi tricks : Search a file from inside vi 
Wednesday, September 5, 2007, 07:01 AM - Tips and Tricks
vi (or vim) they say is very powerful. I wonder sometimes : "Why is everything that is supposed to be powerful has remained unexplored by me?"

Though I prefer xemacs more than vi but end up using vi many times. I recently learned that I could find a file from inside vi. Many time we do a #include "xyz.h" in our C/C++ programs and we want to jump to that file directly. Move your cursor over the file name and type [Esc]gf to open that file right into your vi. It is not necessary for the file to be in #include. It could be anywhere and its not C/C++ specific.

The way it works is vi searches for the file in the path variable. This is not the PATH environmental variable. This is a vim specific option which generally defaults to .,/usr/local/include,/usr/include/. It searches your currently directly fist and then the default system include dirs.

You can add your own search able dirs to the path variable. If you want to include /home/shuva/include or ./include (meaning the include dir from your current working dir) you can set the path option like this:

:set path+=/home/shuva/include,./include

Dont ask me how to go back to the file you have been editing. I don't know and if you find it please write it up in the comments section below. I will be thankful.

If you want to explore more on smart vim tricks read the Vim documentation at sourceforge..
3 comments ( 205 views )   |  0 trackbacks   |  permalink   |   ( 3 / 52 )
Scenario 1/N: The program crashes but not while debugging.  
Monday, September 3, 2007, 08:51 AM - Programming
The program crashes with a bad segmentation fault.
You try hard looking at the code and run over it many times and dont see the error so easily.
So you attach your favorite debugger and step through it and it does not crash.


For a developer, this scenario is very irritating. You become almost helpless when the tools that are supposed to detect flaws in your code dont.

There are many reasons why a program does not crash in your debugger. Today I will demonstrate with an example one of the "N" reasons why this could happen.

A little basics:
A Segmentation fault (SIGSEGV) occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed.

It is possible that you or your debugger performed certain actions that has made a memory location readable or writable. Once this happens, then the code which used to seg-fault will run smoothly user the process space of the debugger. When you start a debugger like gdb, you have the ability to read data from any memory that you can access, provided you as a user has permission to do so.

The program you wrote must not have set permissions to access certain memory areas and may be trying to read from that memory.

Our example today is based on two processes, one writer and the other reader and they use POSIX shared memory to pass a message to the other.

The writer creates a shared memory segment. If it exists, it deletes it and creates a new segment. It then attaches to it, write a few bytes of data and detaches.

The reader attaches to the shared memory and tries to read the data and print. it then detaches and destroys the segment.

Thats all our program does. Below is the code straight from my build-box. You can simple copy and compile using the Makefile below. Discussion follows below ....


Code:
------------------------------------------------------------
/* myshm.h */
#ifndef SHM_H
#define SHM_H

#define MY_SHARED_MEM_NAME "/my_shared_mem_name"
#define MY_SHARED_MEM_SIZE 1024 //1 kb
#define READER 0
#define WRITER 1

void* Attach(int rw_flag);
void Detach();
void Destroy();
void Write();
void Read();

#endif


----------------------------------------------------------

/* myshm.c */

#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "myshm.h"

void* mem_start = NULL;

void* Attach(int rw_flag) {
int ret = 0;
int fd = 0;
int shmExists = 0;

if (rw_flag == READER) {
fd = shm_open(MY_SHARED_MEM_NAME, O_RDWR ,S_IRWXU | S_IRWXG);
if (fd == -1) {
printf("Shared memory does not
exist..\n");
return NULL;
}
}

if (rw_flag == WRITER) {
fd = shm_open(MY_SHARED_MEM_NAME, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG);
if ((fd == -1) && (errno == EEXIST)) {
Destroy();
fd = shm_open(MY_SHARED_MEM_NAME,
O_RDWR | O_CREAT,
S_IRWXU | S_IRWXG);
if (fd == -1) {
return NULL;
}
}
} else if (fd == -1) {
return NULL;
}

if (rw_flag == WRITER) {
ret = ftruncate(fd, MY_SHARED_MEM_SIZE);
if (ret == -1) {
return NULL;
}
}

mem_start = mmap(0, MY_SHARED_MEM_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
if (mem_start == MAP_FAILED) {
return NULL;
}

ret = close(fd);
if (ret == -1) {
return NULL;
}

printf("Attached to shared memory at:%p\n",mem_start);

return mem_start;

}

void Detach() {
printf("Detaching...\n");
munmap(mem_start, MY_SHARED_MEM_SIZE);
return;
}

void Destroy() {
printf("Destroying shared memory..\n");
shm_unlink(MY_SHARED_MEM_NAME);
}

void Write() {
printf("Writing into shared memory..\n");
char* data = "NETOTTO";
memcpy(mem_start, (void*)data, 8);
return;
}

void Read() {
printf("Reading from shared memory..\n");
char data[8];
memcpy(data, mem_start, 8);
printf("Data is: %s\n", data);
return;
}


-----------------------------------------------------------

/* Writer.c */

#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include "myshm.h"

int main() {

int ret = 0;
if (Attach(WRITER) == NULL) {
perror("Error attaching to shared memory\n");
exit(1);
}
Write();
Detach();
return 0;
}



------------------------------------------------------------
/* reader.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include "myshm.h"
int main() {

int ret = 0;
if (Attach(READER) == NULL) {
perror("Error attaching to shared memory\n");
return(1);
}
Read();
Detach();
Destroy();
return 0;
}


-------------------------------------------------------------
/* Makefile */
default: all

all: writer reader

writer: myshm.o writer.o
g++ -g myshm.o writer.o -lrt -o writer

reader: myshm.o reader.o
g++ -g myshm.o reader.o -lrt -o reader

myshm.o: myshm.h myshm.c
gcc -c -g myshm.c

reader.o: reader.c
gcc -c -g reader.c

writer.o: writer.c
gcc -c -g writer.c

clean:
rm -f *.o reader writer


-----------------------------------------------------------

This is what happens when you run the writer followed by the reader.

[root@shuvavmrhel ]# make
gcc -c -g myshm.c
gcc -c -g writer.c
g++ -g myshm.o writer.o -lrt -o writer
gcc -c -g reader.c
g++ -g myshm.o reader.o -lrt -o reader

[root@shuvavmrhel ]# ./writer
Attached to shared memory at:0xb7fff000
Writing into shared memory..
Detaching...

[root@shuvavmrhel ]# ./reader
Attached to shared memory at:0xb7fff000
Reading from shared memory..
Segmentation fault
[root@shuvavmrhel ]#

The core dump file would suggest that the segmentation error in question is coming from the function Read():myshm.c at the memcpy() statement as shown below:

void Read() {
printf("Reading from shared memory..\n");
char data[8];
memcpy(data, mem_start, 8);
printf("Data is: %s\n", data);
return;
}

It is obvious that for some reason we are not allowed to read from the memory pointed by mem_start. If you run gdb and reach this line and try to access the memory pointed to by mem_start, it would display as follows:

81 memcpy(data, mem_start, 8);
(gdb) x/2 mem_start
0xb7fff000: 0x4f54454e 0x004f5454
(gdb) n
82 printf("Data is: %s\n", data);
(gdb) n
Data is: NETOTTO
84 }


You can now proceed with the gdb session. The memcpy works and we can see the data string "NETOTTO" printed for us.

No segmentation fault.

This is because when the reader memory mapped the shared memory into the process space, it did so with only the PROT_WRITE flag and not PROT_READ flag.

mem_start = mmap(0, MY_SHARED_MEM_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);

The correct statement should have been

mem_start = mmap(0, MY_SHARED_MEM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

In gdb however, since we accessed the memory using the x/2 gdb-command, gdb acquired the read permissions and effectively the rest of our program which is running in the same space got the read permission for that memory segment. So it does not fail.

If we dont use the x/2 command in gdb, we would get the fault in gdb too.

This is a very important thing that I have learned and I am writing it here so that I dont waste another half a day scratching my head to figure out what went wrong.

Thoughts?
1 comment ( 176 views )   |  0 trackbacks   |  permalink   |   ( 2.9 / 65 )
My favourite Open Source application  
Saturday, September 1, 2007, 03:34 PM - Technology
Powered By ReadTheWords.com
Today as I start my Netotto blog, I thank all open-source software contributers, to start with, with Alexander Palmo, the author of the Simple PHP Blog. This blog wouldn't have made it live so soon without his contribution. I will talk more about Netotto and Simple PHP Blog sometime later.

Talking and thinking of open source software, I was wondering the other day -- "Which is the one open source software which has helped me the most?", filtering the Mama of all Open source, Linux. I was specifically thinking of applications and tools.

I, like most software developers, use a lot of open-source tools/applications, and take these freebies for granted. Coming to think of it hard, they have made life easier for me so many times. They helped me earn my bread and butter too.

So, which is my favorite? Cygwin.

Yes Cygwin.

When I entered the IT industry as a software developer 7 years back, I was working on UNIX for the first 3.5 years. College was also all UNIX. Windows was only for checking emails, playing games and chatting (IM). When it comes to work, I was quite afraid of windows.

After three years, when I changed my job, they gave me a box with Windows 2000 Professional and I found myself working like a handicapped person. It was difficult to move the mouse all day long. I did not even know how to write simple tools in DOS. Without shell and Perl, my productivity was taking a hit.I was missing something seriously.

But fortunately it was a pleasant accident to stumble upon Cygwin while Googling. This tool claimed that I can run any UNIX command on my windows machine. Its an emulator. Since then I have never been able to live without Cygwin at my workplace or even at home.

For those those who dont know what Cygwin is, you must visit its website to find out more, but here it is as I see it.

In layman's terms:

Once you install Cygwin on your Windows box, and start the app, it opens a window just like your Windos Command Prompt. At this command prompt you may RUN ALL UNIX COMMANDS AND WINDOWS COMMANDS. dir or ls. It works. You can even change and see file permissions in rwxrwxrwx formats. Dont believe it. Try it.

All my UNIX scripting languages, XEMACS editor, vi, Perl, Bash, gcc, everything that a user on UNIX can think of is available on your Windows box. For a moment you think, WOW --this is called cross breeding.

Click the icon below to have a look:

(If you are wondering what /usr/bin/gcc maps to in my C drive, it is actually C:\cygwin\bin. In short, the way you see files on your Windows OS is made usable for you in UNIX format)


In technical terms:
# Cygwin is a Linux-like environment for Windows. It consists of two parts: A DLL (cygwin1.dll) which acts as a Linux API emulation layer providing substantial Linux API functionality.
# A collection of tools which provide Linux look and feel.
# Cygwin is not a way to run native linux apps on Windows. You have to rebuild your application from source if you want it to run on Windows.
# Cygwin is not a way to magically make native Windows apps aware of UNIX ® functionality, like signals, ptys, etc. Again, you need to build your apps from source if you want to take advantage of Cygwin functionality.

Add to Cygwin a Window Manager over an X Server, you have a Linux-KDE or your Exceed(HummingBird) like environment on your Widnows desktop. Can life be more cool free of cost?

There are many free Window Managers available like Cygwin/X, CyGNOME, KDE-Cygwin. However, I personally have been using WindowMaker and so far I haven't faced any trouble using it.It consumes about 4MB of your RAM with no applications loaded and when left idle, the memory usage goes down to 1.5MB. 99% of the times I use the WindowMaker just opening multiple ssh sessions. I generally work with multiple UNIX servers and end up having 10+ ssh logins neatly organized over work-spaces. Being an X manager, you could also set the DISPLAY and open UNIX GUIs on your X, but thats very rare for me.


Installation tricks and hacks:

If you are going to install Cygwin and WindowMaker, here are some of the tricks and hacks which might be useful.

1. Downloading Cygwin is the first step. You get the setup.exe and run it. Choose to download all files first and then install in another session of setup.exe. While downloading I would suggest you download all packages (650MB+). The package choosing part is not very obvious to most first time users. You need to click on a rounded arrow as shown in the screen shot below. Wait for a few seconds after you click. Wait till it all becomes "Install".

The screen shot by default will be.

Click the rounded arrows to make it look like:


The same trick holds true while installing. Keep you Download dir and install dir separate. I generally choose C:\Downloads\cygwin and C:\cygwin respectively.

I haven't seen a single team member so far who did not do this mistake the first time.

2. While installing WindowMaker, you need to build it the GNU-style. configure, make, make install. While running he configure script, if you get permission denied errors, go to the WindowMaker dir and get write permissions for yourself. There is a high chance you will get this error, if you are using Windows XP and are logged on in a domain.

3. While running the configure, run it with the --enable-kde option. You will get a lot of useful kde-like GUI on your X.

Once you are done with make-install, you type in the following commands:

x& --- this will start your Xserver.
wmaker& --- this will start the Windowmaker.

If you dont face trouble while running wmaker and see a purple workspace on your X, you are lucky. You are however very likely to get the two following errors:

1. Display not set. To fix this type:
export DISPLAY=localhost:0.0

2. You get lots of errors like "Could not create directory". This will most probably happen if you are at office and not at home. This is because you have a space in your home directory. Example: "C:\Documents and Settings\shuva". wmaker apparantly does not like spaces in the path. It actually tries to create a dir called GNUstep" where it would keep all preferneces. You can override this by setting the environmental variable GNUSTEP_USER_ROOT. I keep it in my C:\Documents and Settings\shuva\.bashrc file.

alias ll='ls -l'
export DISPLAY='localhost:0.0'
export GNUSTEP_USER_ROOT='/usr/local/GNUstep'


So whenever you start your computer fresh you do these steps:
1. Double click on the Cygwin icon on your desktop.
2. source .bashrc
3. x&
4. wmaker&

It may appear that its a pretty difficult thing to setup in your computer, but it actually is not. Once you start using the power of cygwin.dll on your Windows box, you will know what its worth.

8 comments ( 2902 views )   |  0 trackbacks   |  permalink   |   ( 2.9 / 69 )

<<First <Back | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |