Optimization can make debugging a bit more difficult, e.g. by changing the
execution order of statements. To disable optimization, set the
build type to Debug
.
Conversely, the Release
or MinSizeRel
build types can be used to optimize
further for speed or size, but do not include debug symbols for use with
debuggers, and completely disable lower level logging
and asserts, optimizing away the code path. Ensure that you have not built with
one of those types before attempting debugging.
Wireshark has a flexible logging system to assist in development and troubleshooting. Logging configuration takes into account what, when and where to output diagnostic messages.
The details to configure and use the logging system are explained in the following sections.
Any part of Wireshark can be assigned a logging domain. This is already done for most of the internals of Wireshark,
e.g., "Main", "Capture", "Epan", "GUI". The domains are defined in the ws_log_defs.h
header but dissectors should
define their own logging domain. Any string can be used as ID for a logging domain.
The following logging levels are defined from highest to lowest:
By default logging output is generated for logging level "message" and above. If the logging level is lowered or raised
all log output generated at or above this level is sent to the log output.
Note that if the build type is set to Release
or
MinSizeRel
, then by default all log output for the logging levels "debug" and
"noisy" will be optimized away by the compiler and cannot be sent to the log
output, regardless of the logging setings. To enable debugging for all build
types, set the CMake variable -DENABLE_DEBUG=ON
.
There is also a special "echo" logging level used exclusively for temporary debugging print outs (usually
via the WS_DEBUG_HERE
macro).
By default logging output is sent to stderr. In addition to that it is possible to configure a log file. This collects all log output to the file, besides the normal output streams. The output can then be read in a text editor or used with other text processing tools.
A program can also register its own log writer when the standard facilities are insufficient or special handling is required.
Logging can be configured through either environment variables or command line parameters.
The following environment variables and command line parameters are used by the logging system:
Multiple domains can be concatenated using commas or semicolons. The match can be inverted by prefixing the domain(s) list with an exclamation mark.
Sometimes it can be helpful to abort the program right after a log message of a certain level or a certain domain is output.
The following environment variables are used to configure a trap by the logging system:
The logging API can be found in wsutil/wslog.h
.
To use the logging API for your code add the definition of the ID of your logging domain right after including config.h
. For example:
/* My code doing something awesome */ #include "config.h" #define WS_LOG_DOMAIN "MyCode" #include <wireshark.h> ...
Populate your code with the applicable function calls to generate log messages when enabled. The following convenience macros are provided:
ws_error()
ws_critical()
ws_warning()
ws_message()
ws_info()
ws_debug()
ws_noisy()
All these take printf()
style parameters. There is also a WS_DEBUG_HERE
macro that is always active and outputs to a special "echo"
domain for temporary debug print outs. WS_DEBUG_HERE
should be used for development purposes only and not appear in final delivery of the code.
You can debug using command-line debuggers such as gdb, dbx, or lldb. If you prefer a graphic debugger, you can use an IDE or debugging frontend such as Qt Creator, CLion, or Eclipse.
Additional traps can be set on Wireshark, see Section 3.8.2, “Traps Set By Logging”
Wireshark’s wmem memory management framework makes it easy to allocate
memory in pools with a certain scope that is freed automatically at
a certain point (such as the end of dissecting a packet or when closing
a file), even if a dissector raises an exception after allocating the
memory. Memory in a pool is also freed collectively, which can be
considerably faster than calling free()
individually on each individual
allocation. Proper use of wmem makes a dissector faster and less prone
to memory leaks with unexpected data, which happens frequently with
capture files.
However, wmem’s block allocation can obscure issues that memory checkers
might otherwise catch. Fortunately, the WIRESHARK_DEBUG_WMEM_OVERRIDE
environment variable can be set at runtime to instruct wmem to use a specific
memory allocator for all allocations, some of which are more compatible with
memory checkers:
simple
- Uses malloc()
only, no block allocation, compatible with Valgrind
strict
- Finds invalid memory via canaries and scrubbing freed memory
block
- Standard block allocator for file and epan scopes
block_fast
- Block allocator for short-lived scope, e.g. packet, (free()
is a no-op)
The simple
allocator produces the most accurate results with tools like
Valgrind and can be enabled as follows:
$ export WIRESHARK_DEBUG_WMEM_OVERRIDE=simple
For memory allocated without wmem but with GLib’s GSlice memory allocator,
there is a similar G_SLICE
environment variable that can be set to
always-malloc
(similar to simple
) or debug-blocks
(similar to strict
).
See https://developer-old.gnome.org/glib/stable/glib-running.html for details.
If you’re encountering memory safety bugs, you might want to build with Address Sanitizer (ASAN) so that Wireshark will immediately alert you to any detected issues. It works with GCC or Clang, provided that the appropriate libraries are installed.
$ cmake .. -G Ninja -DENABLE_ASAN=1
Tip | |
---|---|
ASAN slows things down by a factor of 2 (or more), so having a different build directory for an ASAN build can be useful. |
ASAN will catch more errors when run with either the simple
or strict
wmem allocator than with the defaults. (It is more compatible with the
strict
allocator and the analogous GSlice debug-blocks
option than
Valgrind is.)
For additional instrumentation, ASAN supports a number of options.
For further investigating memory leaks, the following can be useful:
# This slows things down a lot more but results in more precise backtraces, # especially when calling third party libraries (such as the C++ standard # library): $ export ASAN_OPTIONS=fast_unwind_on_malloc=0 # This causes LeakSanitizer to print the addresses of leaked objects for # inspection in a debugger: $ export LSAN_OPTIONS=report_objects=1
LeakSanitizer and AddressSanitizer can detect issues in third-party libraries
that you cannot do anything about. For example, internal Qt library calls to
the fontconfig library can produce leaks. To ignore them, create a
suppressions file with an appropriate entry, e.g. leak:libfontconfig
.
If you are just interested in memory safety checking, but not memory leak debugging, disable the included LeakSanitizer with:
$ export ASAN_OPTIONS=detect_leaks=0
You can debug using the Visual Studio Debugger or WinDbg. See the section on using the Debugger Tools.