Debugging: Difference between revisions

From miki
Jump to navigation Jump to search
 
(19 intermediate revisions by the same user not shown)
Line 1: Line 1:
This is a general page on debugging tools, techniques, tips, etc.
This is a general page on debugging tools, techniques, tips, etc.

== Debuggers environment ==

=== [http://www.ollydbg.de/ OllyDbg] ===
OllyDbg is a 32-bit assembler level analysing debugger for Microsoft® Windows®.

=== IDAPro ===

=== SoftIce ===

=== [http://www.hopperapp.com/ Hopper Disassembler] ===
Hopper is a reverse engineering tool for OS X and Linux, that lets you disassemble, decompile and debug your 32/64bits Intel Mac, Linux, Windows and iOS executables.



== Linux tools ==
== Linux tools ==
Line 5: Line 18:
See [[Linux Commands#addr2line|addr2line]] page.
See [[Linux Commands#addr2line|addr2line]] page.


=== gdb ===
=== GDB and GDB front-ends ===
See [[gdb]] page.
See [[gdb|GDB]] page.

== Profiling ==
* http://poormansprofiler.org/
* https://github.com/yoshinorim/quickstack
* https://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

=== ftrace ===
* https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/


== C/C++ - Debugging with gcc ==
== C/C++ - Debugging with gcc ==
Line 17: Line 38:
</source>
</source>


Object and executables need to build with '''<tt>gcc -g -rdynamic</tt>'''!
Object and executables need to be built (i.e. compiled and <u>linked</u>) with '''<tt>gcc -g -rdynamic</tt>''' (also '''<tt>-fvisibility</tt>''' must either be ''default'', ''protected'' or not set at all)!
<source lang="bash">
<source lang="bash">
gcc -O0 -g -rdynamic main.c -o myprogram
gcc -O0 -g -rdynamic main.c -o myprogram
Line 28: Line 49:
#include <signal.h>
#include <signal.h>
#include <stdlib.h>
#include <stdlib.h>



void handler(int sig) {
void handler(int sig) {
Line 34: Line 54:
int size;
int size;


// get void*'s for all entries on the stack
size = backtrace(array, 10); // get void*'s for all entries on the stack
size = backtrace(array, 10);


// print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig); // print out all the frames to stderr
fprintf(stderr, "Error: signal %d:\n", sig);
backtrace_symbols_fd(array, size, 2);
backtrace_symbols_fd(array, size, 2);
exit(1);
exit(1);
Line 44: Line 62:


void baz() {
void baz() {
int *foo = (int*)-1; // make a bad pointer
int *foo = (int*)-1; // make a bad pointer
printf("%d\n", *foo); // causes segfault
printf("%d\n", *foo); // causes segfault
}
}


void bar() { baz(); }
void bar() { baz(); }
void foo() { bar(); }
void foo() { bar(); }



int main(int argc, char **argv) {
int main(int argc, char **argv) {
signal(SIGSEGV, handler); // install our handler
signal(SIGSEGV, handler); // install our handler
foo(); // this will call foo, bar, and baz. baz segfaults.
foo(); // this will call foo, bar, and baz. baz segfaults.
return 0;
return 0;
}
}
</source>
</source>

It can also be used to print the symbol name of any function of which we know the address (a bit like <code>[http://msdn.microsoft.com/en-us/library/ms681323(VS.85).aspx SymFromAddr]</code> on windows):
<source lang="c">
#include <stdio.h>
#include <execinfo.h>

void foo(void) {
printf("foo\n");
}

int main(int argc, char *argv[]) {
void *funptr = &foo;

backtrace_symbols_fd(&funptr, 1, 1);

return 0;
}
</source>





Line 63: Line 99:


* Using <tt>backtrace</tt>:
* Using <tt>backtrace</tt>:
{{pl2|
{{hidden|<tt>main.c</tt>
([{{#filelink: main.c}} download])|{{#fileanchor: main.c}}
<source lang="c">
<source lang="c">
#ifndef _GNU_SOURCE
#ifndef _GNU_SOURCE
Line 173: Line 212:
exit(EXIT_SUCCESS);
exit(EXIT_SUCCESS);
}
}
</source>|headerstyle=background:#ccccff;text-align:left;}} }}
</source>


* Demangling symbols in C++ by calling <tt>__cxa_demangle</tt> (like is done in tool <tt>c++filt</tt>):
* Demangling symbols in C++ by calling <tt>__cxa_demangle</tt> (like is done in tool <tt>c++filt</tt>):
{{pl2|
{{hidden|<tt>main.c</tt>
([{{#filelink: main.c}} download])|{{#fileanchor: main.c}}
<source lang="cpp">
<source lang="cpp">
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
Line 258: Line 300:
exit(EXIT_FAILURE);
exit(EXIT_FAILURE);
}
}
</source>|headerstyle=background:#ccccff;text-align:left;}} }}

=== Getting function name from its address ===
* {{red|'''TODO:'''}} There is maybe an alternate solution using <code>dlopen</code>, which would let an application to browse its own symbols.
* {{red|'''TODO:'''}} Check whether we can force export of (debug) symbols even if declared static.

The following program show how to use the <tt>backtrace_symbols</tt> function to get the name of a function given its address.

The program must be compiled (and <u>linked</u>) with gcc options '''-g -rdynamic''' (also option '''<tt>-fvisibility</tt>''' must either be ''default'', ''protected'' or not set at all):

<source lang="bash">
gcc -g -rdynamic -O0 main.c -o symfromaddr
</source>
</source>

{{pl2|
{{hidden|<tt>main.c</tt>
([{{#filelink: main.c}} download])|{{#fileanchor: main.c}}
<source lang="c">
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#include <assert.h>

typedef void (*f_ptr)(void);


void callbackfunction(void)
{
printf("callbackfunction\n");
}

void symfromaddr(char **sym, void * fptr, void **buftofree)
{
char * p;

(*buftofree)=backtrace_symbols(&fptr, 1);
assert(*buftofree!=NULL);

//Isolate fctname in './path/with/(parens)/pgm(fctname+0) [0x1234abcd]'
(*sym)=p=((char **)buftofree)[0];
while( (*p) && ('+' != (*p)) )
{
if( '(' == *(p++) )
{
(*sym)=p;
}
}
if(!*p)
(*sym)=p;
*p = 0;
}


int main(int argc, char **argv) {
char *sym;
void *buftofree;

symfromaddr(&sym,callbackfunction,&buftofree);
printf("func symbol is '%s'\n",sym);
free(buftofree);

return 0;
}
</source>|headerstyle=background:#ccccff;text-align:left;}} }}

A less efficient but more convenient version:
{{pl2|
{{hidden|<tt>main.c</tt>
([{{#filelink: main.c}} download])|{{#fileanchor: main.c}}
<source lang="c">
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

typedef void (*f_ptr)(void);


void callbackfunction(void)
{
printf("callbackfunction\n");
}

char * symfromaddr(char *sym, void * fptr, unsigned n)
{
char *beg,*end;
char ** strings;

strings=backtrace_symbols(&fptr, 1);
assert(strings!=NULL);

beg=end=strings[0];
while( (*end) && ('+' != (*end)) )
{
if( '(' == *(end++) )
{
beg=end;
}
}

sym[0]=0;
if(*end) {
*end = 0;
strncpy(sym,beg,n);
if (n>0)
sym[n-1]=0;
}

free(strings);

return sym;
}


int main(int argc, char **argv) {
char sym[20];

printf("func symbol is '%s'\n",symfromaddr(sym,callbackfunction,sizeof(sym)));

return 0;
}
</source>|headerstyle=background:#ccccff;text-align:left;}} }}


=== libunwind (non-gnu) ===
=== libunwind (non-gnu) ===
* See http://www.nongnu.org/libunwind/docs.html
* See http://www.nongnu.org/libunwind/docs.html (see also [http://codingrelic.geekhold.com/2009/05/pre-mortem-backtracing.html here for example])

== Debugging pthreads ==
'''GDB''':
* [http://www.sourceware.org/gdb/current/onlinedocs/gdb/Threads.html#Threads Debugging Programs with Multiple Threads]
* [http://sources.redhat.com/gdb/current/onlinedocs/gdb/Thread-Stops.html#Thread-Stops GDB: Stopping and starting multi-thread programs]
* [http://sources.redhat.com/gdb/current/onlinedocs/gdb/GDB_002fMI-Thread-Commands.html#GDB_002fMI-Thread-Commands GDB/MI: Threads commands]
'''DDD''':
* [http://www.gnu.org/software/ddd/manual/html_mono/ddd.html#Threads Examining Threads]

Latest revision as of 11:23, 26 August 2024

This is a general page on debugging tools, techniques, tips, etc.

Debuggers environment

OllyDbg

OllyDbg is a 32-bit assembler level analysing debugger for Microsoft® Windows®.

IDAPro

SoftIce

Hopper Disassembler

Hopper is a reverse engineering tool for OS X and Linux, that lets you disassemble, decompile and debug your 32/64bits Intel Mac, Linux, Windows and iOS executables.


Linux tools

addr2line

See addr2line page.

GDB and GDB front-ends

See GDB page.

Profiling

ftrace

C/C++ - Debugging with gcc

backtrace, backtrace_symbols, backtrace_symbols_fd

See manual page, or gcc manual.

int     backtrace            (void **      buffer, int size)
char ** backtrace_symbols    (void *const *buffer, int size)
void    backtrace_symbols_fd (void *const *buffer, int size, int fd)

Object and executables need to be built (i.e. compiled and linked) with gcc -g -rdynamic (also -fvisibility must either be default, protected or not set at all)!

gcc -O0 -g -rdynamic main.c -o myprogram

Short example:

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>

void handler(int sig) {
  void *array[10];
  int size;

  size = backtrace(array, 10);                  // get void*'s for all entries on the stack

  fprintf(stderr, "Error: signal %d:\n", sig);  // print out all the frames to stderr
  backtrace_symbols_fd(array, size, 2);
  exit(1);
}

void baz() {
  int *foo = (int*)-1;                          // make a bad pointer
  printf("%d\n", *foo);                         // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }

int main(int argc, char **argv) {
  signal(SIGSEGV, handler);                     // install our handler
  foo();                                        // this will call foo, bar, and baz.  baz segfaults.
  return 0;
}

It can also be used to print the symbol name of any function of which we know the address (a bit like SymFromAddr on windows):

#include <stdio.h>
#include <execinfo.h>

void foo(void) {
    printf("foo\n");
}

int main(int argc, char *argv[]) {
    void    *funptr = &foo;

    backtrace_symbols_fd(&funptr, 1, 1);

    return 0;
}


A very extensive answer on StackOverflow:

  • Using backtrace:
  • Demangling symbols in C++ by calling __cxa_demangle (like is done in tool c++filt):

Getting function name from its address

  • TODO: There is maybe an alternate solution using dlopen, which would let an application to browse its own symbols.
  • TODO: Check whether we can force export of (debug) symbols even if declared static.

The following program show how to use the backtrace_symbols function to get the name of a function given its address.

The program must be compiled (and linked) with gcc options -g -rdynamic (also option -fvisibility must either be default, protected or not set at all):

gcc -g -rdynamic -O0 main.c -o symfromaddr

A less efficient but more convenient version:

libunwind (non-gnu)

Debugging pthreads

GDB:

DDD: