.. _devcycle-debugging:
.. include:: /migration/deprecation.inc
#########
Debugging
#########
This document describes tools and techniques you can use to debug, monitor,
and measure your application's performance.
.. contents:: Table Of Contents
:local:
:backlinks: none
:depth: 3
Diagnostic information
======================
Viewing process statistics with the task manager
------------------------------------------------
You can use Chrome's Task Manager to display information about a Native Client
application:
#. Open the Task Manager by clicking the menu icon |menu-icon| and choosing
**Tools > Task manager**.
#. When the Task Manager window appears, verify that the columns displaying
memory information are visible. If they are not, right click in the header
row and select the memory items from the popup menu that appears.
A browser window running a Native Client application has at least two processes
associated with it: a process for the app's top level (the render process
managing the page including its HTML and JavaScript) and one or more
processes for each instance of a Native Client module embedded in the page
(each process running native code from one nexe or pexe file). The top-level
process appears with the application's icon and begins with the text "Tab:".
A Native Client process appears with a Chrome extension icon (a jigsaw puzzle
piece |puzzle|) and begins with the text "Native Client module:" followed by the
URL of its manifest file.
From the Task Manager you can view the changing memory allocations of all the
processes associated with a Native Client application. Each process has its own
memory footprint. You can also see the rendering rate displayed as frames per
second (FPS). Note that the computation of render frames can be performed in
any process, but the rendering itself is always done in the top level
application process, so look for the rendering rate there.
Controlling the level of Native Client error and warning messages
-----------------------------------------------------------------
Native Client prints warning and error messages to stdout and stderr. You can
increase the amount of Native Client's diagnostic output by setting the
following `environment variables
<http://en.wikipedia.org/wiki/Environment_variable>`_:
* ``NACL_PLUGIN_DEBUG=1``
* ``NACL_SRPC_DEBUG=[1-255]`` (use a higher number for more verbose debug
output)
* ``NACLVERBOSITY=[1-255]``
Basic debugging
===============
Writing messages to the JavaScript console
------------------------------------------
You can send messages from your C/C++ code to JavaScript using the
``PostMessage()`` call in the :doc:`Pepper messaging system
<../coding/message-system>`. When the JavaScript code receives a message, its
message event handler can call `console.log()
<https://developer.mozilla.org/en/DOM/console.log>`_ to write the message to the
JavaScript `console </devtools/docs/console-api>`_ in Chrome's Developer Tools.
Debugging with printf
---------------------
Your C/C++ code can perform inline printf debugging to stdout and stderr by
calling fprintf() directly, or by using cover functions like these:
.. naclcode::
#include <stdio.h>
void logmsg(const char* pMsg){
fprintf(stdout,"logmsg: %s\n",pMsg);
}
void errormsg(const char* pMsg){
fprintf(stderr,"logerr: %s\n",pMsg);
}
.. _using-chromes-stdout-and-stderr:
Using Chrome's stdout and stderr Streams
----------------------------------------
By default stdout and stderr will appear in Chrome's stdout and stderr stream
but they can also be redirected to log files. (See the next section.) On Mac and
Linux, launching Chrome from a terminal makes stderr and stdout appear in that
terminal. If you launch Chrome this way, be sure it doesn't attach to an existing
instance. One simple way to do this is to pass a new directory to chrome as your
user data directory (``chrome --user-data-dir=<newdir>``).
.. _redirecting-output-to-log:
Redirecting output to log files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can redirect stdout and stderr to output files by setting these environment
variables:
* ``NACL_EXE_STDOUT=c:\nacl_stdout.log``
* ``NACL_EXE_STDERR=c:\nacl_stderr.log``
There is another variable, ``NACLLOG``, that you can use to redirect Native
Client's internally-generated messages. This variable is set to stderr by
default; you can redirect these messages to an output file by setting the
variable as follows:
* ``NACLLOG=c:\nacl.log``
.. Note::
:class: note
**Note:** If you set the ``NACL_EXE_STDOUT``, ``NACL_EXE_STDERR``, or
``NACLLOG`` variables to redirect output to a file, you must run Chrome with
the ``--no-sandbox`` flag. You must also be careful that each variable points
to a different file.
Logging calls to Pepper interfaces
----------------------------------
You can log all Pepper calls your module makes by passing the following flags
to Chrome on startup::
--vmodule=ppb*=4 --enable-logging=stderr
The ``vmodule`` flag tells Chrome to log all calls to C Pepper interfaces that
begin with "ppb" (that is, the interfaces that are implemented by the browser
and that your module calls). The ``enable-logging`` flag tells Chrome to log
the calls to stderr.
.. _visual_studio:
Debugging with Visual Studio
----------------------------
If you develop on a Windows platform you can use the :doc:`Native Client Visual
Studio add-in <vs-addin>` to write and debug your code. The add-in defines new
project platforms that let you run your module in two different modes: As a
Pepper plugin and as a Native Client module. When running as a Pepper plugin
you can use the built-in Visual Studio debugger. When running as a Native
Client module Visual Studio will launch an instance of nacl-gdb for you and
link it to the running code.
.. _using_gdb:
Debugging with nacl-gdb
-----------------------
The Native Client SDK includes a command-line debugger that you can use to
debug Native Client modules. The debugger is based on the GNU debugger `gdb
<http://www.gnu.org/software/gdb/>`_, and is located at
``pepper_<version>/toolchain/<platform>_x86_newlib/bin/x86_64-nacl-gdb`` (where
*<platform>* is the platform of your development machine: ``win``, ``mac``, or
``linux``).
Note that this same copy of GDB can be used to debug any NaCl program,
whether built using newlib or glibc for x86-32, x86-64 or ARM. In the SDK,
``i686-nacl-gdb`` is an alias for ``x86_64-nacl-gdb``, and the ``newlib``
and ``glibc`` toolchains both contain the same version of GDB.
.. _debugging_pnacl_pexes:
Debugging PNaCl pexes (Pepper 35 or later)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use GDB to debug a program that is compiled with the PNaCl
toolchain, you must have a copy of the pexe from **before** running
``pnacl-finalize``. The ``pnacl-finalize`` tool converts LLVM bitcode
to the stable PNaCl bitcode format, but it also strips out debug
metadata, which we need for debugging. In this section we'll give the
LLVM bitcode file a ``.bc`` file extension, and the PNaCl bitcode file
a ``.pexe`` file extension. The actual extension should not matter, but
it helps distinguish between the two types of files.
**Note** unlike the finalized copy of the pexe, the non-finalized debug copy
is not considered stable. This means that a debug copy of the PNaCl
application created by a Pepper N SDK is only guaranteed to run
with a matching Chrome version N. If the version of the debug bitcode pexe
does not match that of Chrome then the translation process may fail, and
you will see an error message in the JavaScript console.
Also, make sure you are passing the ``-g`` :ref:`compile option <compile_flags>`
to ``pnacl-clang`` to enable generating debugging info. You might also want to
omit ``-O2`` from the compile-time and link-time options, otherwise GDB not
might be able to print variables' values when debugging (this is more of a
problem with the PNaCl/LLVM toolchain than with GCC).
Once you have built a non-stable debug copy of the pexe, list the URL of
that copy in your application's manifest file:
.. naclcode::
{
"program": {
"portable": {
"pnacl-translate": {
"url": "release_version.pexe",
"optlevel": 2
},
"pnacl-debug": {
"url": "debug_version.bc",
"optlevel": 0
}
}
}
}
Copy the ``debug_version.bc`` and ``nmf`` files to the location that
your local web server serves files from.
When you run Chrome with ``--enable-nacl-debug``, Chrome will translate
and run the ``debug_version.bc`` instead of ``release_version.pexe``.
Once the debug version is loaded, you are ready to :ref:`run nacl-gdb
<running_nacl_gdb>`
Whether you publish the NMF file containing the debug URL to the
release web server, is up to you. One reason to avoid publishing the
debug URL is that it is only guaranteed to work for the Chrome version
that matches the SDK version. Developers who may have left the
``--enable-nacl-debug`` flag turned on may end up loading the debug
copy of your application (which may or may not work, depending on
their version of Chrome).
.. _debugging_pexes_via_nexes:
Debugging PNaCl pexes (with older Pepper toolchains)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to use GDB to debug a program that is compiled with the PNaCl
toolchain, you must convert the ``pexe`` file to a ``nexe``. (You can skip
this step if you are using the GCC toolchain, or if you are using
pepper 35 or later.)
* Firstly, make sure you are passing the ``-g`` :ref:`compile option
<compile_flags>` to ``pnacl-clang`` to enable generating debugging info.
You might also want to omit ``-O2`` from the compile-time and link-time
options.
* Secondly, use ``pnacl-translate`` to convert your ``pexe`` to one or more
``nexe`` files. For example:
.. naclcode::
:prettyprint: 0
nacl_sdk/pepper_<version>/toolchain/win_pnacl/bin/pnacl-translate \
--allow-llvm-bitcode-input hello_world.pexe -arch x86-32 \
-o hello_world_x86_32.nexe
nacl_sdk/pepper_<version>/toolchain/win_pnacl/bin/pnacl-translate \
--allow-llvm-bitcode-input hello_world.pexe -arch x86-64 \
-o hello_world_x86_64.nexe
For this, use the non-finalized ``pexe`` file produced by
``pnacl-clang``, not the ``pexe`` file produced by ``pnacl-finalize``.
The latter ``pexe`` has debugging info stripped out. The option
``--allow-llvm-bitcode-input`` tells ``pnacl-translate`` to accept a
non-finalized ``pexe``.
* Replace the ``nmf`` :ref:`manifest file <manifest_file>` that points to
your ``pexe`` file with one that points to the ``nexe`` files. For the
example ``nexe`` filenames above, the new ``nmf`` file would contain:
.. naclcode::
:prettyprint: 0
{
"program": {
"x86-32": {"url": "hello_world_x86_32.nexe"},
"x86-64": {"url": "hello_world_x86_64.nexe"},
}
}
* Change the ``<embed>`` HTML element to use
``type="application/x-nacl"`` rather than
``type="application/x-pnacl"``.
* Copy the ``nexe`` and ``nmf`` files to the location that your local web
server serves files from.
.. Note::
:class: note
**Note:** If you know whether Chrome is using the x86-32 or x86-64
version of the NaCl sandbox on your system, you can translate the
``pexe`` once to a single x86-32 or x86-64 ``nexe``. Otherwise, you
might find it easier to translate the ``pexe`` to both ``nexe``
formats as described above.
.. _running_nacl_gdb:
Running nacl-gdb
~~~~~~~~~~~~~~~~
Before you start using nacl-gdb, make sure you can :doc:`build <building>` your
module and :doc:`run <running>` your application normally. This will verify
that you have created all the required :doc:`application parts
<../coding/application-structure>` (.html, .nmf, and .nexe files, shared
libraries, etc.), that your server can access those resources, and that you've
configured Chrome correctly to run your application. The instructions below
assume that you are using a :ref:`local server <web_server>` to run your
application; one benefit of doing it this way is that you can check the web
server output to confirm that your application is loading the correct
resources. However, some people prefer to run their application as an unpacked
extension, as described in :doc:`Running Native Client Applications <running>`.
Follow the instructions below to debug your module with nacl-gdb:
#. Compile your module with the ``-g`` flag so that your .nexe retains symbols
and other debugging information (see the :ref:`recommended compile flags
<compile_flags>`).
#. Launch a local web server (e.g., the :ref:`web server <web_server>` included
in the SDK).
#. Launch Chrome with these three required flags: ``--enable-nacl --enable-nacl-debug --no-sandbox``.
You may also want to use some of the optional flags listed below. A typical
command looks like this::
chrome --enable-nacl --enable-nacl-debug --no-sandbox --disable-hang-monitor localhost:5103
**Required flags:**
``--enable-nacl``
Enables Native Client for all applications, including those that are
launched outside the Chrome Web Store.
``--enable-nacl-debug``
Turns on the Native Client debug stub, opens TCP port 4014, and pauses
Chrome to let the debugger connect.
``--no-sandbox``
Turns off the Chrome sandbox (not the Native Client sandbox). This enables
the stdout and stderr streams, and lets the debugger connect.
**Optional flags:**
``--disable-hang-monitor``
Prevents Chrome from displaying a warning when a tab is unresponsive.
``--user-data-dir=<directory>``
Specifies the `user data directory
<http://www.chromium.org/user-experience/user-data-directory>`_ from which
Chrome should load its state. You can specify a different user data
directory so that changes you make to Chrome in your debugging session do
not affect your personal Chrome data (history, cookies, bookmarks, themes,
and settings).
``--nacl-debug-mask=<nmf_url_mask1,nmf_url_mask2,...>``
Specifies a set of debug mask patterns. This allows you to selectively
choose to debug certain applications and not debug others. For example, if
you only want to debug the NMF files for your applications at
``https://example.com/app``, and no other NaCl applications found on the
web, specify ``--nacl-debug-mask=https://example.com/app/*.nmf``. This
helps prevent accidentally debugging other NaCl applications if you like
to leave the ``--enable-nacl-debug`` flag turned on. The pattern language
for the mask follows `chrome extension match patterns
</extensions/match_patterns>`_. The pattern set can be inverted by
prefixing the pattern set with the ``!`` character.
``<URL>``
Specifies the URL Chrome should open when it launches. The local server
that comes with the SDK listens on port 5103 by default, so the URL when
you're debugging is typically ``localhost:5103`` (assuming that your
application's page is called index.html and that you run the local server
in the directory where that page is located).
#. Navigate to your application's page in Chrome. (You don't need to do this if
you specified a URL when you launched Chrome in the previous step.) Chrome
will start loading the application, then pause and wait until you start
nacl-gdb and run the ``continue`` command.
#. Go to the directory with your source code, and run nacl-gdb from there. For
example::
cd nacl_sdk/pepper_<version>/examples/demo/drive
nacl_sdk/pepper_<version>/toolchain/win_x86_newlib/bin/x86_64-nacl-gdb
The debugger will start and show you a gdb prompt::
(gdb)
#. Run the debugging command lines.
**For PNaCl**::
(gdb) target remote localhost:4014
(gdb) remote get nexe <path-to-save-translated-nexe-with-debug-info>
(gdb) file <path-to-save-translated-nexe-with-debug-info>
(gdb) remote get irt <path-to-save-NaCl-integrated-runtime>
(gdb) nacl-irt <path-to-saved-NaCl-integrated-runtime>
**For NaCl**::
(gdb) target remote localhost:4014
(gdb) nacl-manifest <path-to-your-.nmf-file>
(gdb) remote get irt <path-to-save-NaCl-integrated-runtime>
(gdb) nacl-irt <path-to-saved-NaCl-integrated-runtime>
#. The command used for PNaCl and NaCl are described below:
``target remote localhost:4014``
Tells the debugger how to connect to the debug stub in the Native Client
application loader. This connection occurs through TCP port 4014 (note
that this port is distinct from the port which the local web server uses
to listen for incoming requests, typically port 5103). If you are
debugging multiple applications at the same time, the loader may choose
a port that is different from the default 4014 port. See the Chrome
task manager for the debug port.
``remote get nexe <path>``
This saves the application's main executable (nexe) to ``<path>``.
For PNaCl, this provides a convenient way to access the nexe that is
a **result** of translating your pexe. This can then be loaded with
the ``file <path>`` command.
``nacl-manifest <path>``
For NaCl (not PNaCl), this tells the debugger where to find your
application's executable (.nexe) files. The application's manifest
(.nmf) file lists your application's executable files, as well as any
libraries that are linked with the application dynamically.
``remote get irt <path>``
This saves the Native Client Integrated Runtime (IRT). Normally,
the IRT is located in the same directory as the Chrome executable,
or in a subdirectory named after the Chrome version. For example, if
you're running Chrome canary on Windows, the path to the IRT typically
looks something like ``C:/Users/<username>/AppData/Local/Google/Chrome
SxS/Application/23.0.1247.1/nacl_irt_x86_64.nexe``.
The ``remote get irt <path>`` saves that to the current working
directory so that you do not need to find where exactly the IRT
is stored.
``nacl-irt <path>``
Tells the debugger where to find the Native Client Integrated Runtime
(IRT). ``<path>`` can either be the location of the copy saved by
``remote get irt <path>`` or the copy that is installed alongside Chrome.
A couple of notes on how to specify path names in the nacl-gdb commands
above:
* You can use a forward slash to separate directories on Linux, Mac, and
Windows. If you use a backslash to separate directories on Windows, you
must escape the backslash by using a double backslash "\\" between
directories.
* If any directories in the path have spaces in their name, you must put
quotation marks around the path.
As an example, here is a what these nacl-gdb commands might look like on
Windows::
target remote localhost:4014
nacl-manifest "C:/nacl_sdk/pepper_<version>/examples/hello_world_gles/newlib/Debug/hello_world_gles.nmf"
nacl-irt "C:/Users/<username>/AppData/Local/Google/Chrome SxS/Application/23.0.1247.1/nacl_irt_x86_64.nexe"
To save yourself some typing, you can put put these nacl-gdb commands in a
script file, and execute the file when you run nacl-gdb, like so::
nacl_sdk/pepper_<version>/toolchain/win_x86_newlib/bin/x86_64-nacl-gdb -x <nacl-script-file>
If nacl-gdb connects successfully to Chrome, it displays a message such as
the one below, followed by a gdb prompt::
0x000000000fc00200 in _start ()
(gdb)
If nacl-gdb can't connect to Chrome, it displays a message such as
"``localhost:4014: A connection attempt failed``" or "``localhost:4014:
Connection timed out.``" If you see a message like that, make sure that you
have launched a web server, launched Chrome, and navigated to your
application's page before starting nacl-gdb.
Once nacl-gdb connects to Chrome, you can run standard gdb commands to execute
your module and inspect its state. Some commonly used commands are listed
below.
``break <location>``
set a breakpoint at <location>, e.g.::
break hello_world.cc:79
break hello_world::HelloWorldInstance::HandleMessage
break Render
``continue``
resume normal execution of the program
``next``
execute the next source line, stepping over functions
``step``
execute the next source line, stepping into functions
``print <expression>``
print the value of <expression> (e.g., variables)
``backtrace``
print a stack backtrace
``info breakpoints``
print a table of all breakpoints
``delete <breakpoint>``
delete the specified breakpoint (you can use the breakpoint number displayed
by the info command)
``help <command>``
print documentation for the specified gdb <command>
``quit``
quit gdb
See the `gdb documentation
<http://sourceware.org/gdb/current/onlinedocs/gdb/#toc_Top>`_ for a
comprehensive list of gdb commands. Note that you can abbreviate most commands
to just their first letter (``b`` for break, ``c`` for continue, and so on).
To interrupt execution of your module, press <Ctrl-c>. When you're done
debugging, close the Chrome window and type ``q`` to quit gdb.
Debugging with other tools
==========================
If you cannot use the :ref:`Visual Studio add-in <visual_studio>`, or you want
to use a debugger other than nacl-gdb, you must manually build your module as a
Pepper plugin (sometimes referred to as a "`trusted
<http://www.chromium.org/nativeclient/getting-started/getting-started-background-and-basics#TOC-Trusted-vs-Untrusted>`_"
or "in-process" plugin). Pepper plugins (.DLL files on Windows; .so files on
Linux; .bundle files on Mac) are loaded directly in either the Chrome renderer
process or a separate plugin process, rather than in Native Client. Building a
module as a trusted Pepper plugin allows you to use standard debuggers and
development tools on your system, but when you're finished developing the
plugin, you need to port it to Native Client (i.e., build the module with one of
the toolchains in the NaCl SDK so that the module runs in Native Client). For
details on this advanced development technique, see `Debugging a Trusted Plugin
<http://www.chromium.org/nativeclient/how-tos/debugging-documentation/debugging-a-trusted-plugin>`_.
Note that starting with the ``pepper_22`` bundle, the NaCl SDK for Windows
includes pre-built libraries and library source code, making it much easier to
build a module into a .DLL.
.. |menu-icon| image:: /images/menu-icon.png
.. |puzzle| image:: /images/puzzle.png