Showing posts with label gdb. Show all posts
Showing posts with label gdb. Show all posts

Debugging a C child process using Eclipse

When we are debugging an application that uses C forks in Eclipse, by default the debugger is not configured to follow into the forked child process. Entering set follow-fork-mode child into the console has no effect.

A workaround for this is to create a .gdbinit file that contains set follow-fork-mode child in the project root folder. In the Eclipse gdb preferences, ensure that this is referenced by the setting for "GDB command file".

Note: A more flexible option (as it should ask at each fork) is: set follow-fork-mode ask. I have not tried this out in Eclipse though, and unfortunately not all gdb command line instructions work in Eclipse.

What is the reason for SIGSEGV Bad permissions for mapped region at address ...

Short explanation

Ensure the value the pointer is pointing to is not in non-modifiable memory.

/* Reserves local storage for the array just like any other mutable variable
 * initialises it to the value of the string literal.
 */
char arr[] = “literal”;

/* Reserves local storage for the pointer and initialises it to point at 
 * the address of the string literal within the executable image in memory. 
 * This address is usually in a non-modifiable page.
 */
char ptr* = “literal”;

Long Explanation


This is mostly based on a post at http://panicsoftware.co.uk/index.php/Valgrind:_Bad_permissions_for_mapped_region_at_address_...

Solution: Declare string parameter as char s[] = "1234567"; not char* s = "12345";

This error is very hard to spot when using a C (as opposed to C++) compiler. On the face of it, it can appear that perfectly fine code produces a random segfault that seems to have no good reason for happening. Segfaults are the arch enemy of any C programmer, and usually indicate feeble, insignificant human error; and, like this case, it is often true.

Take the following simple code:

void changeLetter(char* theWord)
{
   if (theWord)
      theWord[0] = 'H';
}
I pass this method the char string "hello!", which should change the 'h' at the start of the string to 'H', and it produces a segfault. Why? I've passed it a valid pointer-to-char string, otherwise the IF statement would have failed. When running using GDB, I can see the following:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400480 in changeLetter ()

Not very descriptive. Compiling the program giving extra debugging symbols using -g3:

gcc -g3 -o problem problem.c

This enables debuggers to give us more meaningful output than what we have already have. GDB now tells us:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400487 in changeLetter (theWord=0x4005a8 "hello!") at problem.c:4
4           theWord[0] = 'H';

We can see that we are passing a non-null pointer, but we still have a problem. In this situation, unfortunately, it means we have defined the char string incorrectly. If you saw my main method, you'd see:

int main()
{
   char* hello = "hello!";

   changeLetter(hello);

   return 0;
}

Unfortunately, the C standard says that this use will result in undefined behaviour. This is where valgrind comes in useful, because it can give more useful feedback than GDB. Valgrind says:
==4927== Process terminating with default action of signal 11 (SIGSEGV)
==4927==  Bad permissions for mapped region at address 0x4005A8
==4927==    at 0x400487: changeLetter (ro_mem.c:4)
==4927==    by 0x4004A7: main (ro_mem.c:10)

If we wish to modify the string we created, we need to declare it like so:

/* 
 * Reserves local storage for the array just like any other mutable variable
 * initialises it to the value of the string literal.
 */
char hello[] = "hello!";