Wednesday, November 30, 2011

How to get process full name programmatically (Linux)

In the previous post I described Windows API that can be used to get command line and full path of the EXE file of the process.
This post describes how to get the same information on Linux.

There is a  pseudo-filesystem directory called “/proc/[PROCESS-ID]”,  which contains a set of useful files that describe the process with PROCESS-ID. In our case we may use files “/proc/[PROCESS-ID]/cmdline” and “/proc/[PROCESS-ID]/exe”.

/proc/[PROCESS-ID]/cmdline” is a text file which contains the command line. Note that arguments are separated by 0 character, so if you just fgets / puts you see program name only.
/proc/[PROCESS-ID]/exe” is a symbolic link to executed command. To read the value of symbolic link you may use readlink (note that readlink may not append 0 character to the string!).

So the code may look like:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

void get_command_line() {
 FILE *f;
 char file[256], cmdline[256] = {0};
 sprintf(file, "/proc/%d/cmdline", getpid());

 f = fopen(file, "r");
 if (f) {
    char *p = cmdline;
    fgets(cmdline, sizeof(cmdline) / sizeof(*cmdline), f);
    fclose(f);

    while (*p) {
     p += strlen(p);
     if (*(p + 1)) {
       *p = ' ';
     }
     p++;
    }
    puts(cmdline);
 } else {
    printf("unable to open file %s\n", file);
 }
}

void get_full_process_name() {
 size_t linknamelen;
 char file[256], cmdline[256] = {0};

 sprintf(file, "/proc/%d/exe", getpid());
 linknamelen = readlink(file, cmdline, sizeof(cmdline) / sizeof(*cmdline) - 1);
 cmdline[linknamelen + 1] = 0;

 printf("Full name is %s\n", cmdline);
}

To get more information:

man proc
man 2 getpid
man 2 readlink

And now a few notes about links. Suppose that you compile the source to “a.out” file and created a soft link called “aaa” to it:
ln -s ./a.out aaa

Now if you run
./aaa
the result is:
Command line: aaa
Full name: /home/ivbel/my_tests/a.out

And if you create a hard link like
link ./a.out hard_a

The result of running hard_a is
Command line: hard_a
Full name: /home/ivbel/my_tests/hard_a 

Monday, November 21, 2011

How to get process full name programmatically (Windows)

This post describes the Windows API that can be used to get the command line and the full process name.


To get command line, use the function GetCommandLine. Of course we could use the arguments of the functions main (in case of console app) or WinMain (in case of GUI app) instead, but this code makes things a bit easier (for instance, in cases when we need to add command line parsing to large existing project or when we just want to print command line for debug purposes etc).
To get the path of the executable file of the current process, use GetModuleFileName.

So the code may look like:

char s[MAX_PATH];
printf("GetCommandLine=%s\n", GetCommandLine());

if (GetModuleFileName(NULL, s, sizeof(s) / sizeof(*s)) > 0)
  printf("GetModuleFileName=%s\n", s);

To illustrate the difference between these two functions let's compile the program to "c:\t\testtesttest.exe" and run several tests from the command line:

c:\t>testtesttest.exe 1 2 3
GetCommandLine=testtesttest.exe  1 2 3
GetModuleFileName=c:\t\testtesttest.exe

c:\t>testte~1.exe    1
GetCommandLine=testte~1.exe     1
GetModuleFileName=c:\t\testtesttest.exe

c:\t>testtesttest arg1
GetCommandLine=testtesttest  arg1
GetModuleFileName=c:\t\testtesttest.exe

c:\t>c:\t\testtesttest.exe
GetCommandLine=c:\t\testtesttest.exe
GetModuleFileName=c:\t\testtesttest.exe

Friday, November 18, 2011

MS Visual Studio: debugging tips

How to cause a debug break of a Windows process.

Sometimes it's impossible to start a process under debugger. Instead, I want the debugger to be started when a process reaches some point.

To cause a debug break from the code, choose any of the following:
  1. Call DebugBreak() API.
  2. Call the built-in function __debugbreak().
  3. __asm int 3;
When any of this instruction is reached, a special window is usually displayed with a possibility to start debugger.

Why it is not working:

1. If you have Windows 7, go to Control Panel->Action Center->Change Action Center Settings->Problem Report Settings and make sure "Each time a problem occurs, ask me before checking for solutions" is checked (thanks to http://stackoverflow.com/questions/890890/debug-program-option-in-windows-7). Actually this is very important option. If it is not selected, the program crash can be silent, which is terrible for developers and testers.
2. In fact, all these commands cause breakpoint exception. So it is possible to ignore these exceptions with the help of Structured Exception Handling (SEH). For instance, the following code ignores debug break:

_try {
    DebugBreak();
} _except(EXCEPTION_EXECUTE_HANDLER) {
}

(of course, _except block can be located anywhere in call stack).

How to launch the Debugger Automatically when the application with the specified name starts.

It is possible to automatically debug an application of the specified name (for instance make "my_test.exe" always run under debugger). For details, see http://msdn.microsoft.com/en-us/library/a329t4ed%28v=vs.80%29.aspx

Thursday, November 17, 2011

Useful GVIM Tips

The things that I didn't know about GVIM editor.

How to prepare _vimrc file (i.e. the file with the default settings)

Windows:
1. Copy "C:\Program Files (x86)\Vim\_vimrc" to $HOME/_vimrc.
If you don't have $HOME variable, you may see it in Gvim with the help
:e $HOME/_vimrc

2. Edit $HOME/_vimrc, add commands there.

Linux:
vim $HOME/.vimrc
add commands there.

For instance, my favorite tab stop options:
:set tabstop=2
:set shiftwidth=2
:set expandtab
:set backspace=indent,eol,start

How to make the 'Backsapce' key work properly in Edit mode:
:set backspace=indent,eol,start
(more info here: http://vim.wikia.com/wiki/Backspace_and_delete_problems)


How to start Gvim maximized under Windows:
(taken from http://vim.wikia.com/wiki/Maximize_or_set_initial_window_size)
Add the following line to _vimrc:
au GUIEnter * simalt ~x "x on an English Windows version. n on a French one

It is possible to have only one Gvim running:

Edit "file.txt" in server "FILES" if it exists, become server "FILES"
otherwise:
    gvim --servername FILES --remote-silent file.txt

This means that you'll have only one Gvim running. New files will be opened in already running Gvim.

More information here:
http://vimdoc.sourceforge.net/htmldoc/remote.html

Hidden characters in GVIM

Display hidden characters: :set invlist
(taken from http://dinomite.net/2007/vim-tip-show-hidden-characters) 

Learn the code of symbol under the cursor: ga

Find the symbol with code (for instance, Tab symbol with hex code 09):
/\%x09
Replace: the same, for instance :s/\%x09/  /gc
(taken from http://durgaprasad.wordpress.com/2007/09/25/find-replace-non-printable-characters-in-vim/)

How to show line numbers:
To turn line numbers on  :set nu
To turn line numbers off :set nu!  

How to convert the file from Windows to Unix format using GVIM
(i.e. replace \r\n to just \n)
1. Open file in GVIM.
2. :set ff=unix
3. Save the file and exit


How to remove empty lines in GVIM

:,$s/^\s*\n/
(more tips here: http://www.rayninfo.co.uk/vimtips.html, great source of GVIM info) 

How to make arrow keys work properly in edit mode in Vi on Linux term

Problem: It seems that when I am using VI through putty when I am in insert mode I get escape characters, instead of the cursor moving when I use the arrow keys.

Solution: 1. use vim.
2. Create a .vimrc file in your home directory:
echo syntax enable > ~/.vimrc

Read here: http://www.bluehostforum.com/archive/index.php/t-6700.html


To be continued...