Monday, November 15, 2010

UNIX tools during C++ coding

GCC

1. gcc/g++ useful tips and tricks: See current C++ settings:
gcc -v -x c++ /dev/null -fsyntax-only
See all preprocessor defines:
gcc -dM -E - < /dev/null
See what you have after pre-processing:
g++ -E -I.. -o _file_name_.ii _file_name_.cpp
See exactly where is defined something that you use it (e.g. for_each algorithm):
grep --color=auto for_each -C10 _file_name_.ii
NOTE: set alias for colored grep because you will use it a lot See what files the linker opens and in what order:
g++ -Wl,-t _parameters_for_compilation_
See all includes, even those on the system path, so you can check if it is taken from the right place:
g++ -M _file_name_
2. Use "strace" (man strace) when program running to see what is opened.

A system call, or syscall, is where a program crosses the boundary between user code and the kernel. Fortunately for us using strace, that boundary is where almost everything interesting happens in a typical program.

It logs all accesses to the OS, such as memory allocation, file I/O, system calls and launching sub-processes
strace -f -o strace.log ./_program_ _program_parameters_
You just want to see what files the program touches, or when it reads and writes data, or some other subset.
strace -f -e trace=process,file,desc sh -c \
'for d in _some_directory_/*; do ls $d >/dev/null; done'
3. Use "ldd" (man ldd) to see what is needed and how is loaded
ldd ./_program_
4. Use command "nm" (man nm) that lists symbols contained in the object file or shared library
nm -D libhelp.package.so

This command lists symbol names from object files. These symbol names can be either functions, global variables, or static variables. For each symbol, the value, symbol type, and symbol name are displayed. Lower case symbol types mean the symbol is local, while upper case means the symbol is global or external.

In combination you can use c++filt(see additional tools) for demangling of symbols:
nm libhelp.package.so | grep <searched symbol> | c++filt
NOTE: install c++filt from here 5. For quick console code search skipping test directory ('ack' installed)
find . -name \*.cpp | grep -v test/ | xargs ack -C 3 -w '_your_search_'
NOTE: I have this in my .ackrc:
# Add CMake files
--type-set=cmake=.txt,.cmake
ack will automatically skips .svn .CVS etc. 6. Use "pc" to see snapshot of current processes
ps -efwH
7. For complex declaration use "cdecl" For:
typedef void(Number:: *Action)(int &);
Returns: "declare Action as pointer to member of class Number function (reference to int) returning void"

Decoding Rule-set:

Rule 1:  Read from left to right looking for an identifier
Rule 2:  If the identifier is with parentheses, then evaluate inside the parentheses first
Rule 3:   look right for postfix operators ( ) or [ ]. If [] then it is an array, else if ()
          then it is a function.
Rule 4:   look left for prefix pointer asterisk '*'. If found the identifier is a pointer.

Rule 5a: If a const and/or volatile is next to a type specifier (int, long, etc.) it applies
         to that specifier
Rule 5b: if a const and/or volatile is not next to a type then it applies to the pointer asterisk on its
         immediate left
8. Problems with network, see mtr mtr is something like combination for traceroute and ping 9. See disassembly output use following script
#!/bin/sh
gcc -S -fverbose-asm -g -O0 test_program.c -o test_program.s
as -alhnd test_program.s > test_program.1st

GDB

The Fundamental Law of Debugging: avoid bugs when you’re coding, but plan for bugs in your code.

One factor that often distinguishes an experienced programmer from a novice is his or her debugging skills. 1. Compile-Time Debug Mode

You can use preprocessor #ifdefs to selectively compile the debug code into your program. The advantage of this method is that your debug code is not compiled into the "release" binary, and so does not increase its size. The disadvantages are that there is no way to enable debugging at a customer site for testing or following the discovery of a bug, and your code starts to look cluttered and indecipherable.

In order to generate a debug version of the program, it should be compiled with the symbol DEBUG_MODE defined. Your compiler should allow you to specify symbols to define during compilation. For example, g++ allows you to specify –Dsymbol on the compile command. 2. Start-Time Debug Mode

Start-time debug mode is an alternative to #ifdefs that is just as simple to implement. A command-line argument to the program can specify whether it should run in debug mode. Unlike compile-time debug mode, this strategy includes the debug code in the "release" binary, and allows debug mode to be enabled at a customer site. However, it still requires users to restart the program in order to run it in debug mode, which is not always an attractive alternative for customers, and which may prevent you from obtaining useful information about bugs.

bool isDebugSet(int argc, char** argv) {
for (int i = 0; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      return (true);
    }
  }
  return (false);
}
3. Run-Time Debug Mode The most flexible way to provide a debug mode is to allow it to be enabled or disabled at run time. One way to provide this feature is to supply an asynchronous interface that controls debug mode on the fly. 4. Ring Buffers

Debug mode is useful for debugging reproducible problems and for running tests. However, bugs often appear when the program is running in nondebug mode, and by the time you or the customer enables debug mode, it is too late to gain any information about the bug. One solution to this problem is to enable tracing in your program at all times. You usually need only the most recent traces to debug a program, so you should store only the most recent traces at any point in a program’s execution. One way to provide this limitation is through careful use of log file rotations.

5. GDB session example
r[un]                        Run to next breakpoint or to end
s[tep]                       Single-step, descending into functions
n[ext]                       Single-step without descending into functions
fin[ish]                     Finish current function, loop, etc. (useful!)
c[ontinue]                   Continue to next breakpoint or end
bt                           displays a stack frame for each active subroutine
up                           Go up one context level on stack (to caller)
                             Move to the function that called the present function
do[wn]                       Go down one level (only possible after up)
p[rint] <name>               Print value of variable called <name>
p/x <name>                   Print value of <name> in HEX format
p <name>@<n>                 Print <n> values starting at <name>
p <chars> (<tab>)            List all variables starting with <chars>
b[reak] <name>               Set a breakpoint at function <name>
b <class>::<name>            Set a breakpoint at <name> in <class>
b <class>::<tab>             List all members in <class>
b <file name>:line number    Set a breakpoint in <file name>
h[elp] b                     Documentation for setting breakpoints
i[nfo] b                     List breakpoints
i                            List all info commands
dis[able] 1                  Disable breakpoint 1
en[able] 1                   Enable breakpoint 1
d[elete] 1                   Delete breakpoint 1
d 1 2                        Delete breakpoints 1 and 2
d                            Delete all breakpoints
cond[ition] 1 <expr>         Stop at breakpoint 1 only if <expr> is true
cond 1                       Make breakpoint 1 unconditional
comm[ands] 1                 Add a list of gdb commands to execute each time breakpoint 1 is hit
(usually just print <var>)
e[xamine]                    Examine memory for a given memory address
Here is example debug session for class "Guitar" with methods "tick". After setting a breakpoint in the "tick" method of the class "Guitar" and continuing to the breakpoint, gdb prints something like:
Breakpoint 2, Guitar::tick (this=0x805cde8) at Guitar.cpp:100
(gdb)
The "this" variable points to the current instance of the "Guitar" object. If an instance variable, say "pluckAmp", cannot be found when you try to print it, try instead
(gdb) p this->pluckAmp
$1 = 0.296875
Also, "this" can be dereferenced to list all instance variables:
(gdb) p *this
$2 = {<plucked3> = {<instrmnt> = {<stk> = {static STK_SINT8 = 1, 
static srate = 22050, _vptr.Stk = 0x8059020}, 
lastOutput = 0}, delayLine = 0x805ce70, delayLine2 = 0x8064f18, 
combDelay = 0x806cfb0, filter = 0x8075040, filter2 = 0x80750f8}
Suppose we're interested in filter2 above:
(gdb) p filter2
$3 = (BiQuad *) 0x80750f8
Very cryptic! What does it mean? It says that "filter2" is an instance of the "BiQuad" class, so it can be dereferenced.
(gdb) p *filter2
$4 = {<filter> = {<stk> = {static STK_SINT8 = 1, 
static srate = 22050, _vptr.Stk = 0x80590e0}, 
gain = 0.60459499999999999, nB = 3, nA = 3, 
b = 0x8075140,  a = 0x8075120, 
outputs = 0x8075180, inputs = 0x8075160}, <no data fields>}
(gdb)
Note that the superclass instance variables are enclosed in curly brackets! (the leaf class instance variables begin with "gain" in this example). Suppose we want to see the "filter2" coefficients:
(gdb) p filter2->b[0] @ 3
$5 = {1, -1.03, 0.21540000000000001}
(gdb) p filter2->a[0] @ 3
$6 = {1, -1.3337300000000001, 0.446191}
(gdb)
and so on. How to set breakpoints in a template?
objdump -t libMyLib.so | c++filt | grep 'BarAbstract.*Baz'
Result is:
0000d2d6 w F .text 0000000a     MY_PLUGIN_A::Foo<MY_PLUGIN_A::BarAbstract>::Baz()
now
(gdb) b MY_PLUGIN_A::Foo<MY_PLUGIN_A::BarAbstract>::Baz()
How to inspecting crashes? When program crash we want to know who called this method and we would like to be able to examine values in the calling methods. So at the gdb prompt, we type backtrace which gives me the following output:
(gdb) bt
#0  Node<int>::next (this=0x0) at main.cc:28
#1  0x2a16c in LinkedList<int>::remove (this=0x40160, 
item_to_remove=@0xffbef014) at main.cc:77
#2  0x1ad10 in main (argc=1, argv=0xffbef0a4) at main.cc:111
(gdb)
So in addition to what we knew about the current method and the local variables, we can now also see what methods called us and what their parameters were. For example, we can see that we were called by LinkedList<int>::remove () where the parameter item_to_remove is at address 0xffbef014. It may help us to understand our bug if we know the value of item_to_remove, so we want to see the value at the address of item_to_remove. This can be done using the gdb x command using the address as a parameter. Here is what happens:
(gdb) x 0xffbef014
0xffbef014: 0x00000001
(gdb)
So the program is crashing while trying to run LinkedList::remove with a parameter of 1. We have now narrowed the problem down to a specific function and a specific value for the parameter.

You can use up command to browse backtrace:

(gdb) up 2
(gdb) list (to source code at this line)

gprof

Have a performance problems? Debugging will not help. Take a look at GNU gprof (Kprof for X addicted). Here is typical gprof session. Let's have a file NameDB.cpp and corresponding NameDBTest.cpp that contains main method: 1. Compile it
g++ -pg -g2 -O2 -lc -o namedb NameDB.cpp NameDBTest.cpp
2. Then you have to run it so the information will be collected. File "gmon.out" will be created by gprof.
./namedb
3. First look at the "flat profile"
gprof namedb gmon.out -p
4. Then you can see call graph
gprof namedb gmon.out -q
5. Finally, you might want to have an "annotated source" listing, which prints out the source code to the application, with notes on how many times each function is called.
gprof namedb gmon.out -A
gprof's biggest limitation: it only profiles user time while the application is running. Typically, applications spend some of their time in user code and some in "system code," such as kernel system calls. You can see spent time:
time ./namedb
Result is:
real    0m15.350s
user    0m15.014s
sys     0m0.017s
"man time" for more information. To measure time spend on certain block of code you can use boost::progress_timer

No comments:

algorithms (1) cpp (3) cv (1) daily (4) emacs (2) freebsd (4) java (3) javascript (1) JSON (1) linux (2) Lisp (7) misc (8) programming (16) Python (4) SICP (1) source control (4) sql (1) думи (8)