drizzle
Profile
Search
 
Powered by SoftLayer
Debugging Drizzle with GDB

This is a demonstration of debugging procedure using GDB (GNU Debugger)


Contents

Building the server with debugging symbols:

$> cd /repos/drizzle/mybranch/
$> ./config/autorun.sh && ./configure --with-debug && make -j2

(Note: Building without the --with-debug and -j2 options may produce strange results with line numbers in source files) Now you have the choice to start the server for debugging with or without standard testing suite.

better to fist test the build by executing the standard test suite. like:

$>make test

Start Server and GDB with test suite

Go to the tests directory and start Drizzle in GDB. (dtr is a perl script part of test suite. it wrapps GDB also).

$> cd tests
$> ./dtr --start-and-exit --gdb

This will pop open a GDB instance for the server process, and it will be waiting for client connections. (remember that drizzle's default port is 4427. but dtr uses 9306


Start Server and GDB without test suite

alternatively you can use gdb without dtr (the testing suit)

$cd drizzled/
$gdb drizzled

now you will be inside GDB where you can set arguments and run the code.

(gdb) set args --console-enable --drizzle-protocol-port=9306 --datadir=/home/jpipes/repos/drizzle/working/drizzled/
(gdb) run


Important Note: --console-enable simplfies debugging procedure by providing a server console. so no need to have a separate client connection and you can execute commands on server console itself.

You can create one client session like:

$> ../client/drizzle --user=root --port=9306

Tracing the code using GDB

You will notice that the client seems to just "hang". Switch back the GDB session. you will notice that GDB (actually the test suite) has set a breakpoint at the mysql_parse() function. You'll see something like this:

[Switching to Thread 0xb317fb90 (LWP 11710)]

Breakpoint 1, mysql_parse (thd=0x8878c18),
     inBuf=0x8882290 "select @@version_comment limit 1", length=32,
     found_semicolon=0xb317f040) at sql_parse.cc:2870
2870                          const char ** found_semicolon)
(gdb)

The above is basically showing you the function call stack and argument addresses being passed to the mysql_parse() function, located in drizzled/sql_parse.cc at line 2870.

To see the full call stack, do:

(gdb) where

You'll see that the call stack goes from the thread scheduler (libevent_thread_proc()) to the parser (do_command(), then dispatch_command(), then mysql_parse()).

To step into the server process, do:

(gdb) step

This will run to the next function call. Simply hit enter to repeat the step. To see what a variable contains at any time, simple do:

(gdb) print name_of_variable

For instance

(gdb) print thd

shows

$1 = (class THD*) 0x8878c18

You can also grab a pointer's member variables, such as the thread's current query ID:

(gdb) print thd->query_id
$2 = 1

You can set another break point (for instance, a function you are interested in) by doing:

(gdb) break function_name

for instance, if I look through the source code, I see that once a SELECT query is issued by the client, the function mysql_select() is called

so I could do:

(gdb) break mysql_select

GDB will inform you a breakpoint has been set, and the line number of the file, like so:

Breakpoint 2 at 0x814ea09: file sql_select.cc, line 2618.

To continue until that breakpoint, do:

(gdb) continue

And you are now at mysql_select()...

If you continue again, and you switch back to your terminal with the drizzle client in it. You should see a drizzle client at the command prompt, like so:

[503][jpipes@serialcoder: /tmp/trunk/client]$ ./drizzle --user=root --port=9306
Welcome to the Drizzle client..  Commands end with ; or \g.
Your Drizzle connection id is 1
Server version: 7.0.0-log Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

drizzle>>

Keep this client open, since you will be executing commands through it.

In the GDB session, type:

(gdb) break mysql_parse
(gdb) continue

Then the client, do:

drizzle> SELECT * FROM INFORMATION_SCHEMA.TABLES;

and switch back to the server GDB session. You will see that GDB has broken once more at mysql_parse() and that the inBuf is the "SELECT *FROM INFORMATION_SCHEMA.TABLES"

if a server crash/SEGFAULT occurs, GDB will be interrupted and you will see the fault. At this point, you can get the backtrace (function stack) of where the fault occurred by using the "bt" command:

you can see the code being executed with the "list" command:

(gdb) list
744	    - mysql_reset_session_for_next_command()
745	    So, initializing the lexical analyser *before* using the query cache
746	    is required for the cache to work properly.
747	    FIXME: cleanup the dependencies in the code to simplify this.
748	  */
749	  lex_start(session);
750	  session->reset_for_next_command();
751	
752	  {
753	    LEX *lex= session->lex;

you can Step though the code (single instruction at a time) by pressing s or (single line at a time, next line) by pressing n

(gdb) s
lex_start (session=0x20128d0) at sql_lex.cc:205(gdb) n
210	  lex->unit.init_query();
(gdb) n
211	  lex->unit.init_select();
205	  LEX *lex= session->lex;
(gdb) s
207	  lex->session= lex->unit.session= session;
(gdb) s
209	  lex->context_stack.empty();


For helping development works, please log all debug info in bug tracker.

Courtesy for the content: Jay Pipes

Last Update : --Jobinau 07:00, 22 October 2009 (UTC)

Site generously hosted by SoftLayer Technologies