You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

z/OS平台PL/I远程调试VSCode调试扩展开发方案咨询

z/OS PL/I VSCode远程调试扩展实现指南

1. VSCode调试能力初始化

VSCode调试能力基于Debug Adapter Protocol(DAP)实现,不需要自行开发调试UI,所有界面渲染由VSCode内置完成,初始化只需要完成3项注册工作:

  • 在扩展package.json中声明自定义调试类型,定义调试启动所需的配置项,包括z/OS主机地址、调试端口、源数据集名、作业名等参数,同时关联PL/I语言,让PL/I文件的调试菜单自动识别该调试类型
  • 实现DebugConfigurationProvider,负责处理launch.json的配置补全、默认值填充、参数合法性校验,比如提前校验用户填写的数据集路径格式、作业参数是否缺失
  • 实现DebugAdapterDescriptorFactory,负责创建调试适配器实例:如果TCP通信逻辑量不大,可以直接用内联模式在扩展宿主进程里跑适配逻辑;如果通信逻辑复杂,建议单独启动独立适配进程跑TCP通信,避免阻塞扩展主线程

最小配置注册示例:

{
  "contributes": {
    "debuggers": [
      {
        "type": "zos-pli-remote",
        "label": "z/OS PL/I 远程调试",
        "languages": ["pli"],
        "configurationAttributes": {
          "launch": {
            "required": ["host", "debugPort", "sourceDataset", "jobName"],
            "properties": {
              "host": {"type": "string", "description": "z/OS主机IP/域名"},
              "debugPort": {"type": "number", "description": "大型机侧调试服务端口"},
              "sourceDataset": {"type": "string", "description": "PL/I源数据集路径"},
              "jobName": {"type": "string", "description": "待提交调试的作业名"}
            }
          }
        }
      }
    ]
  }
}

扩展激活阶段的注册代码示例(TypeScript):

import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
  // 注册调试配置提供器
  const configProvider = new PLIDebugConfigProvider();
  context.subscriptions.push(
    vscode.debug.registerDebugConfigurationProvider('zos-pli-remote', configProvider)
  );
  // 注册调试适配器工厂
  const adapterFactory = new PLIDebugAdapterFactory();
  context.subscriptions.push(
    vscode.debug.registerDebugAdapterDescriptorFactory('zos-pli-remote', adapterFactory)
  );
}

2. TCP调试启动指令发送

这部分可以直接复用你已经通过抓包得到的IBM z/OS Explorer通信报文格式,结合现有扩展已经实现的z/OS操作能力完成:

  • 调试会话触发后,优先复用现有能力完成数据集写入、作业提交两个前置步骤,不需要重复开发这部分逻辑
  • 作业提交后增加端口轮询逻辑,等大型机侧作业初始化完成、调试端口进入监听状态后再建立TCP长连接,避免连接被拒
  • 注意z/OS侧默认使用IBM-1047(EBCDIC)编码,所有发送的文本类报文需要做UTF-8到EBCDIC的编码转换,不要直接发送UTF-8编码内容,否则会出现指令解析失败
  • 启动指令发送后增加10-15秒的超时校验,超时未收到就绪响应直接终止会话,返回明确的错误提示,比如“调试作业启动超时,请检查大型机侧JES日志”

TCP连接与启动指令发送示例:

import * as net from 'net';
import * as iconv from 'iconv-lite';
const client = new net.Socket();
// 轮询端口就绪后再连接
waitForPortReady(host, debugPort, 15000).then(() => {
  client.connect(debugPort, host, () => {
    // 按抓包得到的报文结构拼装启动指令,替换对应作业、用户标识字段
    const startCmdRaw = buildStartCommand(jobName, userToken);
    // 编码转换后发送
    const startCmdBuf = iconv.encode(startCmdRaw, 'IBM1047');
    client.write(startCmdBuf);
  });
});

3. TCP返回信息接收与界面渲染

核心逻辑是将大型机返回的原始调试报文转换为标准DAP事件推送给VSCode,所有界面渲染由VSCode自动完成:

  • TCP数据接收时必须做拆包粘包处理:z/OS侧的调试报文一般采用固定4字节长度头+报文体的结构,不要直接按单次data事件触发就解析报文,避免拿到半截数据解析失败,需要维护接收缓冲区,按报文长度切割完整报文后再处理
  • 解析得到的调试事件(命中断点、程序输出、变量值、调用栈)对应转换为DAP标准事件结构发送给VSCode
  • 提前做好路径映射:大型机侧返回的源位置是「数据集+成员名」格式,需要映射为本地工作区对应的PL/I文件路径,否则VSCode无法正确打开源文件、显示断点命中位置
  • 普通程序运行输出转换为DAP的output事件发送,会自动展示在VSCode调试控制台

报文接收与事件推送示例:

let recvBuffer = Buffer.alloc(0);
client.on('data', (chunk) => {
  recvBuffer = Buffer.concat([recvBuffer, chunk]);
  // 按固定长度头拆包
  while (recvBuffer.length >= 4) {
    const msgLen = recvBuffer.readUInt32BE(0);
    if (recvBuffer.length < msgLen + 4) break;
    const rawMsg = recvBuffer.subarray(4, 4 + msgLen);
    recvBuffer = recvBuffer.subarray(4 + msgLen);
    // 解码并解析原始z/OS调试报文
    const msgText = iconv.decode(rawMsg, 'IBM1047');
    const debugEvent = parseZOSDebugMessage(msgText);
    // 转换为DAP事件推送给VSCode
    switch(debugEvent.type) {
      case 'stopped':
        session.sendEvent(new StoppedEvent('breakpoint', debugEvent.threadId));
        break;
      case 'output':
        session.sendEvent(new OutputEvent(debugEvent.content + '\n', 'stdout'));
        break;
      case 'initialized':
        session.sendEvent(new InitializedEvent());
        break;
    }
  }
});

4. 核心调试交互功能实现

所有调试交互都是双向请求响应模式:VSCode将用户操作转换为DAP请求发给调试适配器,适配器将请求转换为对应TCP报文发给大型机,拿到响应后再转回DAP格式回传给VSCode即可,核心需要实现4类请求处理:

  • 执行控制:处理continue(继续)、next(单步跳过)、stepIn(单步进入)、stepOut(单步跳出)请求,按抓包得到的报文格式拼装对应控制指令发给大型机,收到线程暂停响应后回传DAP响应,VSCode会自动刷新调用栈、变量面板
  • 会话终止:处理disconnect(停止调试)请求,先给大型机发送调试退出指令,主动关闭TCP连接,再调用现有扩展的作业取消能力清理大型机侧残留进程,最后回传断开响应
  • 断点管理:处理setBreakpoints(行断点)、setExceptionBreakpoints(异常断点)请求,将VSCode传入的本地文件路径、行号转换为大型机识别的「数据集+成员+行号」格式,发送断点设置指令,将大型机返回的断点生效结果回传给VSCode,VSCode会自动将未生效的断点置灰
  • 信息查询:处理stackTrace(调用栈)、scopes(变量作用域)、variables(变量值)请求,发送对应查询指令给大型机,将返回结果转换为DAP格式回传,VSCode会自动渲染到左侧调试面板

断点设置请求处理示例:

protected async setBreakPointsRequest(
  response: DebugProtocol.SetBreakpointsResponse,
  args: DebugProtocol.SetBreakpointsArguments
): Promise<void> {
  const localPath = args.source.path;
  // 本地路径转z/OS数据集名
  const datasetName = mapLocalPathToDataset(localPath);
  const reqBreakpoints = args.breakpoints || [];
  const verifiedBps = [];
  for (const bp of reqBreakpoints) {
    // 发送断点设置指令到大型机
    const result = await sendSetBreakpointCmd(client, datasetName, bp.line);
    verifiedBps.push({
      line: bp.line,
      verified: result.success,
      id: result.bpId
    });
  }
  response.body = { breakpoints: verifiedBps };
  this.sendResponse(response);
}

开发注意事项

  • 不需要从头实现DAP协议的序列化、基础通信逻辑,直接使用官方维护的@vscode/debugadapter依赖包,里面已经封装了所有标准DAP类型和基础处理逻辑,只需要重写对应请求的处理方法即可
  • 联调阶段可以先在本地写一个简单的TCP mock服务,模拟大型机侧的调试响应,先把DAP交互流程跑通,再对接真实大型机环境,减少联调成本
  • 所有涉及z/OS文本内容的收发都要做编码校验,避免因为编码不兼容导致指令失败、乱码问题

内容的提问来源于stack exchange,提问作者Klaus Raab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 19:18:46