segunda-feira, março 17, 2008

How to load debug symbols with GDB - Another Approach

I wrote in the post How to load debug symbols with GDB one way do debug a stripped version of an application with full access to debug symbols.

In this post I will explain another way you can do it.

We are going to load debuging information from a file that was generated by our executable just before it was stripped off..

I am going to use the same source and environment settings that I used in my earlier post:
  • released.c: source code of the program we wish to debug (listing 1).
  • ~/estudo/: Source code of our program will be put here.
  • ~/local/bin: The stripped off version of binary program will stay here.
  • ~/local/symbols: In this place are all files that contain debugging information.
#include <stdio.h>
#include <stdlib.h>

int division(int a, int b);

int m;

int main(void)
{
int i;
int j;

printf("vou setar i\n");
i = 10;

printf("vou setar j\n");
j = 1;

printf ("i = %d, j = %d\n", i, j);
m = division(i, j);

printf("m = %d / %d = %d\n", i, j, m);

return 0;

int division(int a, int b)
{
return a / b;
}

Listing 1 - sample program source code

Let's start:

1 - Create your program with debug information. In our sample:
gcc -g -o release release.c <ENTER>

2 - Now we will generate a file that will contain only debug informations. You generate this file by issuing this command:
objcopy --only-keep-debug <ENTER>
In our sample:
objcopy --only-keep-debug release release.sym <ENTER>

The choice of .sym as an extension for the debug info file is totally arbitrary. You can use whatever you wish to.

3 - You remove debugging information:
strip -s release <ENTER>

4 - Move file release to ~/local/bin/:
mv release ~/local/bin <ENTER>

5 - Move file released.sym to ~/local/symbols/
mv release.sym ~/local/symbols <ENTER>

6 - Go to directory ~/local/bin
cd ~/local/bin <ENTER>

7 - Run GDB:
gdb ./release <ENTER>

8 - Try list command to see that release executable file doesn't have symbols in it.

Figure 1 shows us what I said.

Figure 1 - executable file named release is loaded by GDB.

9 - Let GDB to load symbols from symbols file named release.sym. This file has all symbols that we need to debug. You achieve this by issuing the following command:
add-symbol-file ~/local/symbols/release.sym <ENTER>

From now on you can debug your program as usual.

Figure 2 shows us that debugging symbols where imported successfully and that now the list command shows us the program source code.

Figure 2 - now our GDB session has debuging symbols

As you can see in figure 3, I set a break point at line 17 and I ran the program that stopped there. Then I printed i variable. It is possible just because symbols were loaded.

Figure 3 - debugging session.

You can see that this method to load debug symbols is easier than the previous one presented in the post How to load debug symbols with GDB.

My friend Jumpi complained that it is not the unix way to debug applications that just don't have debug information by loading a separated file. We have core files to help us to debug the application in our host.

I agree with him that it is unusual to debug this way, but it may be useful.

The idea behind this method (and behind the previous one) is similar to that used by MS with .pdb files.

It will allow you to save disk space on your host because you can keep only stripped versions of your applications and libraries in it. It is especially important to embedded systems.

At the same time it let you have a collection of symbol files stored at some place (say, a DVD disc or another server). When (and if) you need to do a debug session

I hope this post will make your life easier.

domingo, março 16, 2008

Precision Resistors

A lot of hobbyists want to make their own circuits but they face a problem: precision resistors.

There are many projects where the ratio between resistances is more important than the actual values. In these case we can measure our resistors to select the most appropriated.

Let me show an example. Suppose we have an inverter amplifier as shown in figure 1.

Figure 1 - Inverter Amplifier

Gain is determined by equation

We can see that the circuit's gain is determined by the ratio between Rf and Ri.

Suppose we want a gain of X.

If Rf = 10,000 ohms and Ri = 5,000 ohms the gain is -2.

If Rf = 20,000 ohms and Ri = 10,000 ohms the gain is -2 too.

If we use resistors with tolerance (precision) of 5% the gain could vary between -1.81and -2.21 depending on real values of resistors Rf and Ri.

If we use resistors with tolerance (precision) of 2% the gain could vary between -1.92 e -2.08 what is much better.

What if we don't have precision resistors? What can we do?

We can use our ordinary resistors (tolerance of 5%). Take a bunch of them and measure each one until you find two resistors with a resistance ratio as near as possible of the value we wish (It is 2 in our sample).

Let me illustrate with an example. Say we take a bunch of resistors of 20K and 10K ohms (nominal values) to measure.

Suppose we found some resistors of 20,900 and 10,400 ohms. So we could do Rf = 20,900 ohms and Ri = 10,400. With these values, the gain would be -2.01 that is a better result than estimated with 2% tolerance resistors.

If we found Rf = 21,000 and Ri = 10,500 than the gain would be exactly 2.

The method, presented in this post, to use ordinary resistors instead of precision resistors is suitable only in prototype development. In commercial scale it is not feasible and the use of precision resistors is mandatory.

Note: As Maurício de Oliveira wrote in his answer to the brazilian portuguese version of this article, precision resistors are manufactured in a way that they take in account changes in their resistance by changes in temperature and manufacturers to their best to minimize it.

So, there are differences between precision resistors and ordinary resistors.

In this article (that I wrote to hobbyists), I am not taken this in account because hobbyists don't design professional circuits and then it will not cause too much trouble. Then it is a valid approuch for a experimental circuit.

sábado, março 08, 2008

How to load debug symbols with GDB

My friend Wanderley asked me if it is possible to tell GDB to load debuging symbols from some file and use it to help debuging a program that doesn't have them.

Yes. It is.

There are two solutions to this question.

I going to explain the first solution in this post. The other solution I will explain in the next post.

You can load debuging information from an debug enabled version of executable file.

In order to better explain the first solution, I will setup my sample environment as follows:
  • released.c: source code of the program we wish to debug (listing 1).
  • ~/estudo/: Source code of our program will be put here.
  • ~/local/bin: The stripped off version of binary program will stay here.
  • ~/local/symbols: In this place are all files that contain debuging information.
#include <stdio.h>
#include <stdlib.h>

int division(int a, int b);

int m;

int main(void)
{
int i;
int j;

printf("vou setar i\n");
i = 10;

printf("vou setar j\n");
j = 1;

printf ("i = %d, j = %d\n", i, j);
m = division(i, j);

printf("m = %d / %d = %d\n", i, j, m);

return 0;
}

int division(int a, int b)
{
return a / b;
}
Listing 1 - sample program source code

I have two versions of the program: with and without debuging information.

1 - You compile your program with debug information. In our sample:
gcc -Wall -g -release release.c <ENTER>

2 - You make a copy of your program. In our sample:
cp release release.full <ENTER>

3 - You strip off debuging information:
strip -s release <ENTER>

As you can see on Figure 1, we have two programs. released.full has debuging symbols but release doesn't have them.

Figure 1

4 - Move file release to ~/local/bin/:
mv release ~/local/bin <ENTER>

5 - Move file released.full to ~/local/symbols/
mv release.full ~/local/symbols <ENTER>

6 - Go to directory ~/local/bin
cd ~/local/bin <ENTER>

7 - Run GDB:
gdb ./release <ENTER>

8 - Try list command to see that release executable file doesn't have symbols in it.

Note: if the program was already running you could get its PID then attach GDB to it.

Figure 2 shows us two windows. The first one shows that our executable file has no debug information. In the other window we can see that release is not yet loaded.

Figure 2 - executable file named release is loaded by GDB but it is not yet running.

9 - Let GDB to load symbols from executable file named release.full. This binary version of our program has all symbols that we need to debug.

Please notice that GDB will not replace the release executable by release.full version of our program. It will just import symbols from release.full into release debugging session.

But GDB needs to know in advance where it must put the symbols it will load. How can you determine the correct memory address?

It is quite simple. You issue command maint inside GDB:
maint info sections

Then you look for .text section. The address that is in the first column is what you want. In our sample, it is 0x08048320. See figure 3.

Figure 3 - looking for .text section address

10 - The next step is to instruct GDB to load debug symbols into .text section. To achieve it you do this:
add-symbol-file ~/local/symbols/release.full <.text section address>

In our sample it means to type:
add-symbol-file ~/local/symbols/release.full 0x08048320

From now on you can debug your program as usual.

Figure 4 shows us that debugging symbols where imported successfully and that now the list command (abbreviated as l) shows us the program source code.

Figure 4 - now our GDB session has debuging symbols

As you can see in figure 5, I set a break point at line 17 and I ran the program that stopped there. Then I printed i variable.

In the other terminal I issued ps command. It was done just to show you that the only program running was release executable. There is no instance of release.full program.

Figure 5 - debugging session.

I hope this post will make your life easier. In the next time I will teach you another way to import debugging symbols.