发展周期(三):调试

原文链接:https://developer.chrome.com/native-client/devguide/devcycle/debugging

注意:已针对ChromeOS以外的平台公布了此处所述技术的弃用。
请访问我们的 迁移指南 了解详情。


调试

本文档介绍了可用于调试,监视和测量应用程序性能的工具和技术。

诊断信息

使用任务管理器查看流程统计信息

您可以使用Chrome的任务管理器显示有关Native Client应用程序的信息:

  1. 单击菜单图标菜单图标并选择“ 工具”>“任务管理器”,打开“任务管理器”
  2. 出现“任务管理器”窗口时,请验证显示内存信息的列是否可见。如果不是,请右键单击标题行,然后从显示的弹出菜单中选择内存项。

运行Native Client应用程序的浏览器窗口至少有两个与之关联的进程:应用程序顶层的进程(管理页面的呈现进程,包括其HTML和JavaScript)以及Native Client模块的每个实例的一个或多个进程嵌入在页面中(每个进程从一个nexe或pexe文件运行本机代码)。顶级进程随应用程序的图标一起显示,并以文本“Tab:”开头。将显示一个Native Client进程,其中包含Chrome扩展程序图标(拼图游戏部分难题),并以文本“Native Client module:”开头,后跟其清单文件的URL。

从任务管理器中,您可以查看与Native Client应用程序关联的所有进程的更改内存分配。每个进程都有自己的内存占用。您还可以看到渲染率显示为每秒帧数(FPS)。请注意,渲染帧的计算可以在任何过程中执行,但渲染本身总是在顶级应用程序进程中完成,因此请在那里查找渲染率。

控制Native Client错误和警告消息的级别

Native Client将警告和错误消息输出到stdout和stderr。您可以通过设置以下环境变量来增加Native Client的诊断输出

  • NACL_PLUGIN_DEBUG=1
  • NACL_SRPC_DEBUG=[1-255] (使用更高的数字以获得更详细的调试输出)
  • NACLVERBOSITY=[1-255]

基本调试

将消息写入JavaScript控制台

您可以使用Pepper消息传递系统中PostMessage()调用将C / C ++代码中的消息发送到JavaScript 。当JavaScript代码收到消息时,其消息事件处理程序可以调用console.log()将消息写入Chrome的Developer Tools中的JavaScript 控制台

使用printf进行调试

您的C / C ++代码可以通过直接调用fprintf()或使用这样的封面函数对stdout和stderr执行内联printf调试:

#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);
}

使用Chrome的stdout和stderr Streams

默认情况下,stdout和stderr将出现在Chrome的stdout和stderr流中,但它们也可以重定向到日志文件。(请参阅下一节。)在Mac和Linux上,从终端启动Chrome会使stderr和stdout出现在该终端中。如果您以这种方式启动Chrome,请确保它不会附加到现有实例。一种简单的方法是将新目录作为用户数据目录(chrome --user-data-dir=<newdir>)传递给chrome 。

将输出重定向到日志文件

您可以通过设置以下环境变量将stdout和stderr重定向到输出文件:

  • NACL_EXE_STDOUT=c:\nacl_stdout.log
  • NACL_EXE_STDERR=c:\nacl_stderr.log

还有另一个变量,NACLLOG可用于重定向Native Client的内部生成的消息。默认情况下,此变量设置为stderr; 您可以通过设置变量将这些消息重定向到输出文件,如下所示:

  • NACLLOG=c:\nacl.log

注意:如果你设置的NACL_EXE_STDOUTNACL_EXE_STDERR或 NACLLOG变量输出重定向到一个文件,你必须与运行Chrome的--no-sandbox标志。您还必须小心每个变量指向不同的文件。

记录对Pepper接口的调用

您可以通过在启动时将以下标志传递给Chrome来记录模块所做的所有Pepper调用:

--vmodule=ppb*=4 --enable-logging=stderr

vmodule标志告诉Chrome记录对以“ppb”开头的C Pepper接口的所有调用(即,浏览器实现的接口以及模块调用的接口)。该enable-logging标志告诉Chrome将调用记录到stderr。

使用Visual Studio进行调试

如果在Windows平台上进行开发,则可以使用Native Client Visual Studio加载项来编写和调试代码。该加载项定义了新的项目平台,使您可以在两种不同的模式下运行模块:作为Pepper插件和Native Client模块。作为Pepper插件运行时,您可以使用内置的Visual Studio调试器。作为Native Client模块运行时,Visual Studio将为您启动nacl-gdb实例并将其链接到正在运行的代码。

使用nacl-gdb进行调试

Native Client SDK包含一个命令行调试器,可用于调试Native Client模块。调试器是基于GNU调试器GDB,并且位于pepper_<version>/toolchain/<platform>_x86_newlib/bin/x86_64-nacl-gdb(其中 <平台>是您的开发机器的平台:winmac,或 linux)。

请注意,相同的GDB副本可用于调试任何NaCl程序,无论是使用newlib还是glibc为x86-32,x86-64或ARM构建。在SDK中, i686-nacl-gdb是别名x86_64-nacl-gdbnewlib 而且glibc工具链都包含相同版本的GDB。

调试PNaCl pexes(Pepper 35或更高版本)

如果要使用GDB调试使用PNaCl工具链编译的程序,则必须运行 之前获得pexe的副本pnacl-finalize。该pnacl-finalize工具将LLVM bitcode转换为稳定的PNaCl bitcode格式,但它也删除了我们调试所需的调试元数据。在本节中,我们将为LLVM bitcode文件提供.bc文件扩展名,并为PNaCl bitcode文件提供.pexe文件扩展名。实际的扩展名无关紧要,但它有助于区分这两种类型的文件。

注意,与pexe的最终副本不同,未最终化的调试副本不被认为是稳定的。这意味着Pepper N SDK创建的PNaCl应用程序的调试副本仅保证与匹配的Chrome版本N一起运行。如果调试bitcode pexe的版本与Chrome的版本不匹配,则翻译过程可能会失败,并且您将在JavaScript控制台中看到错误消息。

此外,请确保您传递的-g 编译选项 ,以pnacl-clang使生成的调试信息。您可能还想省略-O2编译时和链接时选项,否则GDB在调试时可能无法打印变量的值(这对于PNaCl / LLVM工具链而言比GCC更有问题)。

一旦构建了pexe的非稳定调试副本,请在应用程序的清单文件中列出该副本的URL:

{
  "program": {
    "portable": {
      "pnacl-translate": {
        "url": "release_version.pexe",
        "optlevel": 2
      },
      "pnacl-debug": {
        "url": "debug_version.bc",
        "optlevel": 0
      }
    }
  }
}

debug_version.bcnmf文件复制到本地Web服务器提供文件的位置。

当您运行Chrome时--enable-nacl-debug,Chrome会翻译并运行debug_version.bc而不是release_version.pexe。加载调试版本后,即可运行nacl-gdb

是否将包含调试URL的NMF文件发布到发布Web服务器,由您决定。避免发布调试URL的一个原因是,它只能保证适用于与SDK版本匹配的Chrome版本。可能已--enable-nacl-debug打开该标志的开发人员 最终可能会加载您的应用程序的调试副本(可能会也可能不会,这取决于他们的Chrome版本)。

调试PNaCl pexes(使用较旧的Pepper工具链)

如果要使用GDB调试使用PNaCl工具链编译的程序,则必须将pexe文件转换为nexe。(如果您使用的是GCC工具链,或者您使用的是35或更高版本的辣椒,则可以跳过此步骤。)

  • 首先,确保你传递的-g 编译选项,以pnacl-clang使生成的调试信息。您可能还想省略-O2编译时和链接时选项。
  • 其次,用于pnacl-translate将您转换pexe为一个或多个

    nexe文件。例如:

    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

    为此,请使用pexe由其生成的非最终文件 pnacl-clang,而不是pexe由其生成的文件pnacl-finalize。后者pexe调试信息已被删除。该选项 --allow-llvm-bitcode-input告诉pnacl-translate接受未定型pexe

  • 替换nmf 清单文件指向你的pexe文件,一个指向nexe文件。对于nexe上面的示例文件名,新nmf文件将包含:

  • {
      "program": {
        "x86-32": {"url": "hello_world_x86_32.nexe"},
        "x86-64": {"url": "hello_world_x86_64.nexe"},
      }
    }
    更改<embed>要使用的HTML元素 type="application/x-nacl"而不是 type="application/x-pnacl"
  • nexenmf文件复制到本地Web服务器提供文件的位置。

注意:如果您知道Chrome是否在系统上使用x86-32或x86-64版本的NaCl沙箱,则可以将 pexe一次转换为单个x86-32或x86-64 nexe。否则,您可能会发现 如上所述pexe将两种nexe格式转换为更容易。

运行nacl-gdb

在开始使用nacl-gdb之前,请确保您可以构建模块并正常运行应用程序。这将验证您是否已创建所有必需的应用程序部件(.html,.nmf和.nexe文件,共享库等),您的服务器可以访问这些资源,以及您是否已正确配置Chrome以运行应用。以下说明假定您使用本地服务器来运行您的应用程序; 这样做的一个好处是,您可以检查Web服务器输出以确认您的应用程序正在加载正确的资源。但是,有些人更喜欢将其应用程序作为解压缩的扩展运行,如运行本机客户端应用程序中所述

按照以下说明使用nacl-gdb调试模块:

  1. 使用-g标志编译模块,以便.nexe保留符号和其他调试信息(请参阅建议的编译标志)。

  2. 启动本地Web服务器(例如,SDK中包含的Web服务器)。

  3. 使用以下三个必需标志启动Chrome : --enable-nacl --enable-nacl-debug --no-sandbox.

    您可能还想使用下面列出的一些可选标志。典型的命令如下所示:

    chrome --enable-nacl --enable-nacl-debug --no-sandbox --disable-hang-monitor localhost:5103

    必需的标志:

    --enable-nacl

    为所有应用程序启用Native Client,包括在Chrome Web Store外部启动的应用程序。

    --enable-nacl-debug

    打开Native Client调试存根,打开TCP端口4014,并暂停Chrome以让调试器连接。

    --no-sandbox

    关闭Chrome沙箱(而不是Native Client沙箱)。这将启用stdout和stderr流,并让调试器连接。

    可选标志:

    --disable-hang-monitor

    当标签无响应时,防止Chrome显示警告。

    --user-data-dir=<directory>

    指定Chrome应从中加载其状态的用户数据目录。您可以指定其他用户数据目录,以便在调试会话中对Chrome所做的更改不会影响您的个人Chrome数据(历史记录,Cookie,书签,主题和设置)。

    --nacl-debug-mask=<nmf_url_mask1,nmf_url_mask2,...>

    指定一组调试掩码模式。这允许您有选择地选择调试某些应用程序而不调试其他应用程序。例如,如果您只想为应用程序调试NMF文件 https://example.com/app,而不是在Web上找到其他NaCl应用程序,请指定--nacl-debug-mask=https://example.com/app/*.nmf。如果您想--enable-nacl-debug打开旗帜,这有助于防止意外调试其他NaCl应用程序。掩码的模式语言遵循chrome扩展匹配模式。可以通过在模式集前加上!字符来反转模式集。

    <URL>

    指定Chrome启动时应打开的网址。SDK附带的本地服务器默认侦听端口5103,因此调试时的URL通常是localhost:5103(假设您的应用程序页面名为index.html,并且您在该页面所在的目录中运行本地服务器)位于)。

  4. 导航到Chrome中的应用程序页面。(如果您在上一步中启动Chrome时指定了网址,则无需执行此操作。)Chrome将开始加载应用程序,然后暂停并等待,直到您启动nacl-gdb并运行continue命令。

  5. 转到包含源代码的目录,然后从那里运行nacl-gdb。例如:

    cd nacl_sdk/pepper_<version>/examples/demo/drive
    nacl_sdk/pepper_<version>/toolchain/win_x86_newlib/bin/x86_64-nacl-gdb

    调试器将启动并显示gdb提示符:

    (gdb)
  1. 运行debugging命令行。

    对于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>

    对于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>
  2. 用于PNaCl和NaCl的命令如下所述:

    target remote localhost:4014

    告诉调试器如何连接到Native Client应用程序加载器中的调试存根。此连接通过TCP端口4014进行(请注意,此端口与本地Web服务器用于侦听传入请求的端口不同,通常是端口5103)。如果您同时调试多个应用程序,则加载程序可能会选择与默认4014端口不同的端口。有关调试端口,请参阅Chrome任务管理器。

    remote get nexe <path>

    这将应用程序的主要可执行文件(nexe)保存到<path>。对于PNaCl,这提供了一种方便的方式来访问由于翻译你的pexe 而导致的nexe。然后可以使用该file <path>命令加载它。

    nacl-manifest <path>

    对于NaCl(不是PNaCl),这告诉调试器在哪里可以找到应用程序的可执行文件(.nexe)。应用程序的清单(.nmf)文件列出了应用程序的可执行文件,以及动态链接到应用程序的任何库。

    remote get irt <path>

    这样可以保存Native Client集成运行时(IRT)。通常,IRT与Chrome可执行文件位于同一目录中,或位于以Chrome版本命名的子目录中。例如,如果您在Windows上运行Chrome canary,则IRT的路径通常类似于C:/Users/<username>/AppData/Local/Google/Chrome SxS/Application/23.0.1247.1/nacl_irt_x86_64.nexe。将其remote get irt <path>保存到当前工作目录,以便您无需查找IRT的存储位置。

    nacl-irt <path>

    告诉调试器在哪里可以找到Native Client集成运行时(IRT)。<path>可以是保存的副本的位置,也可以remote get irt <path>是与Chrome一起安装的副本。

    关于如何在上面的nacl-gdb命令中指定路径名的几点注意事项:

    例如,以下是这些nacl-gdb命令在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"

    为了节省一些输入,您可以将这些nacl-gdb命令放在脚本文件中,并在运行nacl-gdb时执行该文件,如下所示:

    nacl_sdk/pepper_<version>/toolchain/win_x86_newlib/bin/x86_64-nacl-gdb -x <nacl-script-file>

    如果nacl-gdb成功连接到Chrome,它会显示一条消息,如下面的消息,然后是gdb提示符:

    0x000000000fc00200 in _start ()
    (gdb)

    如果nacl-gdb无法连接到Chrome,它会显示一条消息,例如“ localhost:4014: A connection attempt failed”或“ localhost:4014: Connection timed out.”如果您看到类似这样的消息,请确保您已启动网络服务器,启动Chrome并导航到您的应用程序页面之前启动nacl-gdb。

    • 您可以使用正斜杠来分隔Linux,Mac和Windows上的目录。如果使用反斜杠在Windows上分隔目录,则必须在目录之间使用双反斜杠“\”来转义反斜杠。

    • 如果路径中的任何目录名称中包含空格,则必须在路径周围加上引号。

nacl-gdb连接到Chrome后,您可以运行标准gdb命令来执行模块并检查其状态。下面列出了一些常用命令。

break <location>

在<location>设置断点,例如:

break hello_world.cc:79
break hello_world::HelloWorldInstance::HandleMessage
break Render

continue

恢复程序的正常执行

next

执行下一个源代码行,逐步执行函数

step

执行下一个源代码行,进入函数

print <expression>

打印<expression>的值(例如,变量)

backtrace

打印堆栈回溯

info breakpoints

打印所有断点的表

delete <breakpoint>

删除指定的断点(可以使用info命令显示的断点号)

help <command>

打印指定gdb <command>的文档

quit

退出gdb

有关gdb命令的完整列表,请参阅gdb文档。请注意,您可以将大多数命令缩写为它们的第一个字母(b用于中断,c用于继续等)。

要中断模块的执行,请按<Ctrl-c>。完成调试后,关闭Chrome窗口并键入q以退出gdb。

使用其他工具进行调试

如果您不能使用Visual Studio加载项,或者您想使用除nacl-gdb之外的调试器,则必须手动将模块构建为Pepper插件(有时称为“ 受信任 ”或“进程内”插件)。Pepper插件(Windows上的.DLL文件; Linux上的.so文件; Mac上的.bundle文件)直接加载到Chrome渲染器进程或单独的插件进程中,而不是在Native Client中。将模块构建为可信的Pepper插件允许您在系统上使用标准调试器和开发工具,但是当您完成开发插件时,需要将其移植到Native Client(即,使用其中一个工具链构建模块)在NaCl SDK中,以便模块在Native Client中运行)。有关此高级开发技术的详细信息,请参阅调试受信任的插件。请注意,从pepper_22包中开始,NaCl SDK for Windows包含预先构建的库和库源代码,使得将模块构建到.DLL中更加容易。

CC-By 3.0许可下提供的内容

猜你喜欢

转载自blog.csdn.net/y601500359/article/details/81177900