news 2026/9/28 8:43:46

JerryScript 远程调试器(Debugger)完全指南:从构建配置到 C-API 集成

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JerryScript 远程调试器(Debugger)完全指南:从构建配置到 C-API 集成
  • 语言运行时
  • 嵌入式
  • 物联网
  • 编译器

【免费下载链接】jerryscript

Ultra-lightweight JavaScript engine for the Internet of Things.

项目地址:https://gitcode.com/gh_mirrors/je/jerryscript
点击查看免费下载

本文以 docs/07.DEBUGGER.md 为主线,系统讲解 JerryScript 远程调试器的整体架构、构建与启动方式、命令行工具用法,以及宿主应用中可用的全部调试器 C-API 与扩展传输层实现。读完本文,你将掌握如何在 IoT 设备上为 JerryScript 启用 WebSocket/串口调试服务、如何用 Python 客户端控制执行流程,以及如何在自己的应用程序中嵌入调试支持。

调试器架构:Server 与 Client 的双组件模型

JerryScript 提供一套远程调试器(remote debugger),用于调试运行在设备上的 JavaScript 程序。整套系统由两个主要组件构成:

  • 服务端(Server):内置于 JerryScript 二进制/库中,随目标应用运行在设备端;
  • 客户端(Client):独立的调试器应用,运行在开发机等资源更充裕的系统上。

当前仓库内置一个基于 Python 的调试器客户端,位于 jerry-debugger 子目录,入口脚本为 jerry-debugger/jerry_client.py。该客户端实现了完整的交互式命令行界面,可展示客户端与服务端之间的通信协议细节,因此既可以直接用于调试,也可以作为参考实现,被集成开发环境(IDE)复用。

jerry-debugger/README.md 中列出了官方提供的三类调试工具:仓库内的jerry_client.py控制台客户端、IoT.js Code,以及 JerryScript 调试器 Chrome Web 工具。

协议版本:核心头文件 jerry-core/include/jerryscript-debugger.h 中定义了JERRY_DEBUGGER_VERSION (9),客户端与服务端通过该版本号协商协议兼容性。

可插拔的传输层设计

通信协议的传输层(transport layer)是可插拔的。目前仓库以 JerryScript 扩展(jerry-ext)的形式提供了一套基于 WebSocket 的实现,通过 TCP/IP 网络传输调试消息(源码见 jerry-ext/debugger/debugger-ws.c)。此外仓库还实现了:

  • Raw Packet 传输:jerryx_debugger_rp_create (),见 jerry-ext/debugger/debugger-rp.c;
  • 串口(Serial)传输:jerryx_debugger_serial_create (const char *config),见 jerry-ext/debugger/debugger-serial.c;
  • TCP 传输:jerryx_debugger_tcp_create (uint16_t port),见 jerry-ext/debugger/debugger-tcp.c。

从源码结构看,只要实现对应的传输接口,任何可靠的流式(stream)或数据报(datagram)协议都可以用来承载调试消息,这为连接 UART、蓝牙、CAN 等物理通道提供了扩展空间。

构建调试器服务端

要让目标二进制包含调试器支持,必须显式开启该特性。在仓库根目录执行构建脚本时传入:

--jerry-debugger=on

例如:

python tools/build.py --jerry-debugger=on

未开启该选项时,调试器相关代码不会编入产物;这也解释了为什么 jerry-main/arguments/options.c 中的check_feature逻辑会在特性被禁用时输出Ignoring ... option because this feature is disabled!的警告。

启动与连接:调试服务端命令行参数

JerryScript 桌面主程序(jerry-main/main-desktop.c)解析命令行参数并在引擎初始化后启动调试服务。以下是文档给出的三个核心参数:

参数作用
--start-debug-server启动调试服务端,等待客户端连接
--debugger-wait-source启动后等待客户端下发源代码
--log-level 2提升日志级别,以看到Waiting for client connection提示信息

组合使用示例:

./build/bin/jerry --start-debug-server --debugger-wait-source --log-level 2

除文档列出的参数外,jerry-main/arguments/options.c 还定义了以下可选参数,便于针对不同物理链路定制调试通道:

参数默认值说明
--debug-port NUM5001调试服务端口
--debug-channel [websocket\|rawpacket]websocket调试消息编码通道
--debug-protocol PROTOCOLtcp底层传输协议(tcp或serial)
--serial-config OPTIONS_STRING/dev/ttyS0,115200,8,N,1串口配置(设备、波特率、数据位、校验、停止位)

这些参数最终在 jerry-main/main-desktop.c 的main_init_debugger中按“协议→通道”两级组合完成初始化:先按debug_protocol选择 TCP 或串口传输,再按debug_channel叠加 WebSocket 或 Raw Packet 编码层,最后统一交给jerryx_debugger_after_connect挂接引擎。

客户端连接方式

Python 客户端通过命令行指定服务端地址进行连接:

python jerry-debugger/jerry_client.py <IP地址>:<端口>

若服务端与客户端运行在同一台机器上,地址可写为localhost:5001(即默认参数,见 jerry-debugger/jerry_client_main.py 中的parser.add_argument("address", ...)定义)。

连接时序要求:客户端必须在 JavaScript 应用运行之前连上服务端;对于多文件场景,Python 客户端还支持在引擎初始化完成后立即动态挂接(on-the-fly attachment)。

调试信息的内存策略

JerryScript 本身不保留调试信息(例如每个可能断点位置对应的行号索引)。这些信息由资源更充裕的客户端负责存储——客户端在收到调试信息后自行缓存,而 JerryScript 在把调试信息传给客户端后立即释放,以节省设备端宝贵的内存。因此调试能力(如断点行号解析)实际由客户端侧的数据维护能力决定。

断点行为与 help 命令

连接建立后,执行流程受调试器控制。调试器总是停在第一个可能的断点位置,效果等同于执行了stop命令——这允许你在真正有意义的代码执行开始之前,先插入断点。

客户端支持的所有命令可用help命令查询。仓库自带测试用例 tests/debugger 目录下的.cmd/.expected/.js三件套(如 do_break.cmd)覆盖了 break、continue、next、step、backtrace、scope、variables、eval、throw、restart 等交互场景,可作为命令用法的直接参考。

在宿主应用中集成调试支持

当使用扩展提供的 WebSocket 传输层时,宿主应用在调用jerry_init ()之后,通过如下方式启用调试器并阻塞等待客户端连接:

jerryx_debugger_after_connect (jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ());
  • jerryx_debugger_tcp_create (debug_port):创建指定端口的 TCP 服务;
  • jerryx_debugger_ws_create ():在 TCP 之上叠加 WebSocket 消息编码;
  • jerryx_debugger_after_connect (success):挂接调试器并等待连接(参数为前述调用的逻辑与结果)。

自定义传输层可以按相同模式实现并初始化。当前扩展还提供:

  • jerryx_debugger_rp_create ():Raw Packet 传输层;
  • jerryx_debugger_serial_create (const char* config):串口协议,config形如/dev/ttyS0,115200,8,N,1。

上述接口均在扩展头文件 jerry-ext/include/jerryscript-ext/debugger.h 中声明。

源代码名的传递:传递给jerry_parse ()的源名称(source name)会被客户端用于标识源代码来源,通常就是文件名。调试信息与断点位置的对应关系依赖该名称,因此宿主在解析脚本时应传入有意义的文件名而非空串。

JerryScript 调试器 C-API 接口

本节按 docs/07.DEBUGGER.md 的 API 参考框架,完整介绍调试器类型与全部 6 个引擎级函数。这些函数由核心头文件 jerry-core/include/jerryscript-debugger.h 声明,示例代码需同时包含:

#include "jerryscript.h" #include "jerryscript-ext/debugger.h"

类型:jerry_debugger_wait_for_source_callback_t

概要

该回调函数由jerry_debugger_wait_for_client_source在成功收到一段源代码时调用。

原型

typedef jerry_value_t (*jerry_debugger_wait_for_source_callback_t) (const jerry_char_t *source_name_p, size_t source_name_size, const jerry_char_t *source_p, size_t source_size, void *user_p);

参数

  • source_name_p- 源代码的源名称(通常为文件名)
  • source_name_size- 源名称的字节大小
  • source_p- 源代码字符数据
  • source_size- 源代码大小
  • user_p- 透传给jerry_debugger_wait_for_client_source的自定义指针

回调的返回值会被jerry_debugger_wait_for_client_source原样回传(存入其return_value输出参数)。

类型:jerry_debugger_wait_for_source_status_t

该枚举定义在 jerry-core/include/jerryscript-debugger.h 中,是jerry_debugger_wait_for_client_source的返回值类型:

枚举值含义
JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED源代码接收失败(如连接中断)
JERRY_DEBUGGER_SOURCE_RECEIVED已成功收到一段源代码
JERRY_DEBUGGER_SOURCE_END收到“无更多源代码”的信号
JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED收到客户端发来的上下文重置(context reset)请求

其中SOURCE_END与CONTEXT_RESET_RECEIVED正是文档所描述的“客户端可能请求上下文重置或通知无更多源码”两类带外通知。

jerry_debugger_is_connected

概要

返回当前是否已有远程调试器客户端连接。

原型

bool jerry_debugger_is_connected (void);

示例

#include <stdio.h> #include "jerryscript.h" #include "jerryscript-ext/debugger.h" int main (void) { jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); if (jerry_debugger_is_connected ()) { printf ("A remote debugger client is connected."); } jerry_cleanup (); }

jerry_debugger_stop

概要

若远程调试器已连接且引擎当前未停在断点上,则在下一个可用断点处停止执行。无论该断点是否启用,引擎都会停住。

原型

void jerry_debugger_stop (void)

示例

#include "jerryscript.h" #include "jerryscript-ext/debugger.h" int main (void) { jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); jerry_debugger_stop (); jerry_cleanup (); }

参见

  • jerry_debugger_continue

jerry_debugger_continue

概要

若引擎本会在下一个可用断点处停下,此函数可取消该停靠效果;引擎仍会在已启用的断点处停止。该函数实质上是jerry_debugger_stop ()调用或客户端发出的 stop 请求的“反向操作”。

原型

void jerry_debugger_continue (void)

示例

#include "jerryscript.h" #include "jerryscript-ext/debugger.h" int main (void) { jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); jerry_debugger_continue (); jerry_cleanup (); }

参见

  • jerry_debugger_stop

jerry_debugger_stop_at_breakpoint

概要

启用或禁用“在断点处停止”。当停止被禁用时,所有断点(包括用户启用的断点)都会被忽略,从而实现 ECMAScript 代码的“隐藏执行”(hidden execution)——例如宿主希望不受调试器干扰地运行一段内部逻辑。

原型

void jerry_debugger_stop_at_breakpoint (bool enable_stop_at_breakpoint)

参数

  • enable_stop_at_breakpoint- 传true启用断点停靠,传false禁用

示例

#include "jerryscript.h" #include "jerryscript-ext/debugger.h" int main (void) { jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); jerry_debugger_stop_at_breakpoint (true); // Protected execution of JavaScript code. const jerry_char_t script[] = "42"; jerry_eval (script, sizeof (script) - 1, JERRY_PARSE_NO_OPTS); jerry_debugger_stop_at_breakpoint (false); jerry_cleanup (); }

jerry_debugger_wait_for_client_source

概要

请求客户端提供下一段源代码,函数会一直等待直到整段源码接收完毕。作为回复,客户端可能请求上下文重置或通知没有更多源码,这些通知通过函数返回值回传。

原型

jerry_debugger_wait_for_source_status_t jerry_debugger_wait_for_client_source (jerry_debugger_wait_for_source_callback_t callback_p, void *user_p, jerry_value_t *return_value)

示例(完整的“接收源码→解析→运行→处理重置”循环)

#include "jerryscript.h" #include "jerryscript-ext/debugger.h" /** * Runs the source code received by jerry_debugger_wait_for_client_source. */ static jerry_value_t wait_for_source_callback (const jerry_char_t *source_name_p, /**< source name */ size_t source_name_size, /**< size of source name */ const jerry_char_t *source_p, /**< source code */ size_t source_size, /**< source code size */ void *user_p /**< user pointer */) { (void) user_p; jerry_parse_options_t parse_options; parse_options.options = JERRY_PARSE_HAS_SOURCE_NAME; parse_options.source_name = jerry_string ((const jerry_char_t *) source_name_p, (jerry_size_t) source_name_size, JERRY_ENCODING_UTF8); jerry_value_t ret_val = jerry_parse (source_p, source_size, &parse_options); jerry_value_free (parse_options.source_name); if (!jerry_value_is_exception (ret_val)) { jerry_value_t func_val = ret_val; ret_val = jerry_run (func_val); jerry_value_free (func_val); } return ret_val; } /* wait_for_source_callback */ int main (void) { jerry_debugger_wait_for_source_status_t receive_status; do { /* Create a new JerryScript instance when a context reset is * received. Applications usually registers their core bindings * here as well (e.g. print, setTimeout). */ jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); do { jerry_value_t run_result; receive_status = jerry_debugger_wait_for_client_source (wait_for_source_callback, NULL, &run_result); jerry_value_free (run_result); } while (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVED); jerry_cleanup (); } while (receive_status == JERRY_DEBUGGER_CONTEXT_RESET_RECEIVED); if (receive_status == JERRY_DEBUGGER_SOURCE_RECEIVE_FAILED) { // Handle the failure (e.g. display an error). } return 0; }

实现佐证:桌面主程序在--debugger-wait-source模式下以完全相同的方式循环调用该函数(见 jerry-main/main-desktop.c):SOURCE_RECEIVE_FAILED直接报错退出,SOURCE_END结束循环,CONTEXT_RESET_RECEIVED则执行jerry_cleanup ()后goto restart重新初始化引擎。该示例同时演示了如何把客户端传来的源名称通过JERRY_PARSE_HAS_SOURCE_NAME选项传给jerry_parse (),与文档前述“source name 用于标识源代码来源”的说明相印证。

jerry_debugger_send_output

概要

将程序的输出发送给调试器客户端(例如替代print的输出通道,便于在调试界面中统一展示)。

原型

void jerry_debugger_send_output (const jerry_char_t *buffer, jerry_size_t str_size)

示例

#include "jerryscript.h" #include "jerryscript-ext/debugger.h" int main (void) { jerry_init (JERRY_INIT_EMPTY); jerryx_debugger_after_connect (jerryx_debugger_tcp_create (5001) && jerryx_debugger_ws_create ()); jerry_char_t my_output[] = "Hey, this should be sent too!"; jerry_size_t my_output_size = sizeof (my_output); jerry_debugger_send_output (my_output, my_output_size); jerry_cleanup (); }

快速上手:从构建到断点调试

综合以上内容,一次完整的调试会话可按下述步骤复现:

  1. 构建带调试器的二进制:python tools/build.py --jerry-debugger=on;
  2. 启动服务端:./build/bin/jerry --start-debug-server --debugger-wait-source --log-level 2,等待Waiting for client connection日志出现;
  3. 连接客户端:python jerry-debugger/jerry_client.py localhost:5001;
  4. 下发源码并调试:在客户端中使用break设置断点、continue/next/step控制执行、backtrace/scope检视状态、eval求值表达式,全程可随时用help查询命令;--client-source参数可一次携带多个源码文件,配合--debugger-wait-source实现多文件动态挂接。

延伸阅读

  • 调试器协议与命令的测试基线:tests/debugger(do_*.cmd命令脚本与do_*.expected期望输出一一对应);
  • 传输层扩展实现:jerry-ext/debugger(debugger-tcp.c、debugger-ws.c、debugger-rp.c、debugger-serial.c、debugger-common.c);
  • 调试器核心状态机与等待逻辑:jerry-core/debugger/debugger.c 与 jerry-core/debugger/debugger.h;
  • 官方调试器工具清单:jerry-debugger/README.md。
  • 语言运行时
  • 嵌入式
  • 物联网
  • 编译器

【免费下载链接】jerryscript

Ultra-lightweight JavaScript engine for the Internet of Things.

项目地址:https://gitcode.com/gh_mirrors/je/jerryscript
点击查看免费下载

相关推荐

上一篇:为什么你的洛雪音乐总是播放失败?3步解决音源配置难题
下一篇:MobaXterm中文版:一体化远程管理终端的技术架构与实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 8:43:41

重庆公司核名在哪个网站看这3步完整流程

重庆公司核名在哪个网站看这3步完整流程 网站被黑挂马不知道怎么办?别慌,先检查后台日志和服务器文件,再核对域名解析记录,最后确认SSL证书有效期。很多老板一看到浏览器弹出“不安全”警告,第一反应是换服务器,其实这往往是网站SEO结构被恶意篡改或代码注入导致的。解决这类问题,需要一套从底层安全到前端展…

作者头像 李华
网站建设 2026/9/28 8:43:33

3招搞定wordpress设计幻灯片,拒绝免费工具坑

3招搞定wordpress设计幻灯片,拒绝免费工具坑 改个需求建站公司拖一周,这种憋屈谁受得了?明明只是个首页轮播图,改个文字位置、调个过渡动画,对方非说要排期,还要加钱。其实,搞定 wordpress设计幻灯片 根本不用求人,市面上大把 免费工具 和开源插件能搞定,自己动手半小时就能上线。…

作者头像 李华
网站建设 2026/9/28 8:43:30

LangChain与RAG工程实践:从面试真题看AI应用开发核心能力

1. 那些结课时觉得“不过如此”的项目&#xff0c;两年后在面试间里全变成了考题两年前&#xff0c;我坐在电脑前&#xff0c;敲完知乎知学堂AI应用开发课最后一行代码——一个用LangChain搭的简易RAG知识库问答系统&#xff0c;支持上传PDF、自动切片、向量检索、大模型生成答…

作者头像 李华
网站建设 2026/9/28 8:43:28

AgentOps:给Agent配一套可运营的运行时,从能跑到能管能量化

我昨天凌晨两点还在盯一个Agent任务。它在一个工具调用环节反复重试了四十多分钟&#xff0c;Token烧掉一大把&#xff0c;最后返回了一句“agent execution terminated due to error”。我压根不知道它在那段时间里到底做了什么决策、为什么一直重试、哪一步的上下文开始跑偏。…

作者头像 李华
网站建设 2026/9/28 8:43:28

图论入门到实战:建模、最短路径与拓扑排序核心解析

图论这门课&#xff0c;我在大学的时候学得晕晕乎乎&#xff0c;课本上的定理一个接一个&#xff0c;总觉得它就是一堆“点和线”的抽象游戏。直到工作以后&#xff0c;在一次业务改造里被图狠狠地救了一回&#xff0c;我才真正意识到&#xff1a;图论不是数学课的专利&#xf…

作者头像 李华
网站建设 2026/9/28 8:43:24

3步搞定中国通信建设协会网站搭建最佳实践

3步搞定中国通信建设协会网站搭建最佳实践 别再被那些套皮模板坑了,做出来的页面像十年前的网吧广告,甲方一眼就劝退。做协会类网站,讲究的是稳重、权威和信息层级清晰, 中国通信建设协会网站 的搭建不能只图快,得把 最佳实践…

作者头像 李华