vscode-go语言插件,调试器协议分析(二)

版本信息

Server: {
  "Commands": [
    "gopls.add_dependency",
    "gopls.add_import",
    "gopls.add_telemetry_counters",
    "gopls.apply_fix",
    "gopls.change_signature",
    "gopls.check_upgrades",
    "gopls.edit_go_directive",
    "gopls.fetch_vulncheck_result",
    "gopls.gc_details",
    "gopls.generate",
    "gopls.go_get_package",
    "gopls.list_imports",
    "gopls.list_known_packages",
    "gopls.maybe_prompt_for_telemetry",
    "gopls.mem_stats",
    "gopls.regenerate_cgo",
    "gopls.remove_dependency",
    "gopls.reset_go_mod_diagnostics",
    "gopls.run_go_work_command",
    "gopls.run_govulncheck",
    "gopls.run_tests",
    "gopls.start_debugging",
    "gopls.start_profile",
    "gopls.stop_profile",
    "gopls.test",
    "gopls.tidy",
    "gopls.toggle_gc_details",
    "gopls.update_go_sum",
    "gopls.upgrade_dependency",
    "gopls.vendor",
    "gopls.workspace_stats"
  ],
  "Name": "gopls",
  "Version": "v0.14.2",
  "GoVersion": "go1.20.8"
}

协议rpc-json

调试器,发出消息类型

  • event 事件,通知vscode
  • response 应答,对vscode请求的应答
  • request 请求,vscode请求调试器应答

程序调试过程分析

  • 初始化
c--> {"command":"initialize","arguments":{"clientID":"vscode","clientName":"Visual Studio Code","adapterID":"go","pathFormat":"path","linesStartAt1":true,"columnsStartAt1":true,"supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"locale":"zh-cn","supportsProgressReporting":true,"supportsInvalidatedEvent":true,"supportsMemoryReferences":true,"supportsArgsCanBeInterpretedByShell":true,"supportsMemoryEvent":true,"supportsStartDebuggingRequest":true},"type":"request","seq":1}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"Starting: /data/repo/golang/gopath/bin/dlv dap --listen=127.0.0.1:38087 --log-dest=3 from /home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace\n"}}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"DAP server listening at: 127.0.0.1:38087\n"}}
s--> {"seq":0,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsFunctionBreakpoints":true,"supportsConditionalBreakpoints":true,"supportsEvaluateForHovers":true,"supportsSetVariable":true,"supportsExceptionInfoRequest":true,"supportsDelayedStackTraceLoading":true,"supportsLogPoints":true,"supportsDisassembleRequest":true,"supportsClipboardContext":true,"supportsSteppingGranularity":true,"supportsInstructionBreakpoints":true}}

运行被调试程序

c--> {"command":"launch","arguments":{"name":"Launch Package","type":"go","request":"launch","mode":"debug","program":".","__configurationTarget":6,"packagePathToGoModPathMap":{"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace"},"debugAdapter":"dlv-dap","showRegisters":false,"showGlobalVariables":false,"substitutePath":[],"showLog":false,"logOutput":"debugger","dlvFlags":[],"hideSystemGoroutines":false,"dlvToolPath":"/data/repo/golang/gopath/bin/dlv","env":{"GOPATH":"/data/repo/golang/gopath"},"__buildDir":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace","__sessionId":"56640cfe-504d-4f89-9050-c63dfc306961"},"type":"request","seq":2}
s--> {"seq":0,"type":"event","event":"initialized"}
s--> {"seq":0,"type":"response","request_seq":2,"success":true,"command":"launch"}

设置断点

c--> {"command":"setBreakpoints","arguments":{"source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"lines":[6,7,8,10],"breakpoints":[{"line":6},{"line":7},{"line":8},{"line":10}],"sourceModified":false},"type":"request","seq":3}

设置函数断点

c--> {"command":"setFunctionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":4}

设置指令断点,汇编指令

c--> {"command":"setInstructionBreakpoints","arguments":{"breakpoints":[]},"type":"request","seq":5}
s--> {"seq":0,"type":"response","request_seq":3,"success":true,"command":"setBreakpoints","body":{"breakpoints":[{"id":1,"verified":true,"source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":6},{"id":2,"verified":true,"source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":7},{"id":3,"verified":true,"source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":8},{"id":4,"verified":true,"source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":10}]}}
s--> {"seq":0,"type":"response","request_seq":4,"success":true,"command":"setFunctionBreakpoints","body":{"breakpoints":[]}}
s--> {"seq":0,"type":"response","request_seq":5,"success":true,"command":"setInstructionBreakpoints","body":{"breakpoints":[]}}

配置完成

c--> {"command":"configurationDone","type":"request","seq":6}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"Type 'dlv help' for list of commands.\n","source":{}}}
s--> {"seq":0,"type":"response","request_seq":6,"success":true,"command":"configurationDone"}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"breakpoint","threadId":1,"allThreadsStopped":true,"hitBreakpointIds":[1]}}

线程

c--> {"command":"threads","type":"request","seq":7}
c--> {"command":"threads","type":"request","seq":8}
s--> {"seq":0,"type":"response","request_seq":7,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.runfinq"}]}}
s--> {"seq":0,"type":"response","request_seq":8,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.runfinq"}]}}

堆栈

c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":9}
s--> {"seq":0,"type":"response","request_seq":9,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"main.main","source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":6,"column":0,"instructionPointerReference":"0x49d126"}],"totalFrames":51}}

作用域

c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":10}
s--> {"seq":0,"type":"response","request_seq":10,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false,"source":{}}]}}

堆栈

c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":11}
s--> {"seq":0,"type":"response","request_seq":11,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":250,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"},{"id":1002,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":3}}

变量

c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":12}
s--> {"seq":0,"type":"response","request_seq":12,"success":true,"command":"variables","body":{"variables":[]}}

===================》运行一行 a := 1
下一步

c--> {"command":"next","arguments":{"threadId":1},"type":"request","seq":13}
s--> {"seq":0,"type":"event","event":"continued","body":{"threadId":1,"allThreadsContinued":true}}
s--> {"seq":0,"type":"response","request_seq":13,"success":true,"command":"next"}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"step","threadId":1,"allThreadsStopped":true}}

线程

c--> {"command":"threads","type":"request","seq":14}
s--> {"seq":0,"type":"response","request_seq":14,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.gopark"}]}}

堆栈

c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":15}
s--> {"seq":0,"type":"response","request_seq":15,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"main.main","source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":7,"column":0,"instructionPointerReference":"0x49d12f"}],"totalFrames":51}}

作用域

c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":16}
s--> {"seq":0,"type":"response","request_seq":16,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false,"source":{}}]}}

变量

c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":17}
s--> {"seq":0,"type":"response","request_seq":17,"success":true,"command":"variables","body":{"variables":[{"name":"a","value":"1","type":"int","presentationHint":{},"evaluateName":"a","variablesReference":0}]}}

堆栈

c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":18}
s--> {"seq":0,"type":"response","request_seq":18,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":250,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"},{"id":1002,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":3}}

fmt.Println("结果: ", a)
goto end
===============================>
下一步

c--> {"command":"next","arguments":{"threadId":1},"type":"request","seq":19}
s--> {"seq":0,"type":"event","event":"continued","body":{"threadId":1,"allThreadsContinued":true}}
s--> {"seq":0,"type":"response","request_seq":19,"success":true,"command":"next"}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"stdout","output":"结果:  1\n"}}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"step","threadId":1,"allThreadsStopped":true}}

线程

c--> {"command":"threads","type":"request","seq":20}
s--> {"seq":0,"type":"response","request_seq":20,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.gopark"}]}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":21}
s--> {"seq":0,"type":"response","request_seq":21,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"main.main","source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":8,"column":0,"instructionPointerReference":"0x49d1d4"}],"totalFrames":51}}

作用域
c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":22}
s--> {"seq":0,"type":"response","request_seq":22,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false,"source":{}}]}}

变量
c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":23}
s--> {"seq":0,"type":"response","request_seq":23,"success":true,"command":"variables","body":{"variables":[{"name":"a","value":"1","type":"int","presentationHint":{},"evaluateName":"a","variablesReference":0}]}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":24}
s--> {"seq":0,"type":"response","request_seq":24,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":250,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"},{"id":1002,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":3}}

goto end

end:
fmt.Println("end")
=============================>
下一步
c--> {"command":"next","arguments":{"threadId":1},"type":"request","seq":25}
s--> {"seq":0,"type":"event","event":"continued","body":{"threadId":1,"allThreadsContinued":true}}
s--> {"seq":0,"type":"response","request_seq":25,"success":true,"command":"next"}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"step","threadId":1,"allThreadsStopped":true}}

线程
c--> {"command":"threads","type":"request","seq":26}
s--> {"seq":0,"type":"response","request_seq":26,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.gopark"}]}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":27}
s--> {"seq":0,"type":"response","request_seq":27,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"main.main","source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":10,"column":0,"instructionPointerReference":"0x49d1d6"}],"totalFrames":51}}

作用域
c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":28}
s--> {"seq":0,"type":"response","request_seq":28,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false,"source":{}}]}}

变量
c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":29}
s--> {"seq":0,"type":"response","request_seq":29,"success":true,"command":"variables","body":{"variables":[{"name":"a","value":"1","type":"int","presentationHint":{},"evaluateName":"a","variablesReference":0}]}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":30}
s--> {"seq":0,"type":"response","request_seq":30,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":250,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"},{"id":1002,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":3}}

fmt.Println("end")

}
======================>

c--> {"command":"next","arguments":{"threadId":1},"type":"request","seq":31}
s--> {"seq":0,"type":"event","event":"continued","body":{"threadId":1,"allThreadsContinued":true}}
s--> {"seq":0,"type":"response","request_seq":31,"success":true,"command":"next"}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"stdout","output":"end\n"}}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"step","threadId":1,"allThreadsStopped":true}}
c--> {"command":"threads","type":"request","seq":32}
s--> {"seq":0,"type":"response","request_seq":32,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] main.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.gopark"}]}}
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":33}
s--> {"seq":0,"type":"response","request_seq":33,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"main.main","source":{"name":"main.go","path":"/home/john/wsp/vscodewp/vscode-go-review/sampleWorkspace/main.go"},"line":11,"column":0,"instructionPointerReference":"0x49d228"}],"totalFrames":51}}
c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":34}
s--> {"seq":0,"type":"response","request_seq":34,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals","variablesReference":1000,"expensive":false,"source":{}}]}}
c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":35}
s--> {"seq":0,"type":"response","request_seq":35,"success":true,"command":"variables","body":{"variables":[{"name":"a","value":"1","type":"int","presentationHint":{},"evaluateName":"a","variablesReference":0}]}}
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":36}
s--> {"seq":0,"type":"response","request_seq":36,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":250,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"},{"id":1002,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":3}}

最后一行,结束
=====================>
下一步

c--> {"command":"next","arguments":{"threadId":1},"type":"request","seq":37}
s--> {"seq":0,"type":"event","event":"continued","body":{"threadId":1,"allThreadsContinued":true}}
s--> {"seq":0,"type":"response","request_seq":37,"success":true,"command":"next"}
s--> {"seq":0,"type":"event","event":"stopped","body":{"reason":"step","threadId":1,"allThreadsStopped":true}}

线程

c--> {"command":"threads","type":"request","seq":38}
s--> {"seq":0,"type":"response","request_seq":38,"success":true,"command":"threads","body":{"threads":[{"id":1,"name":"* [Go 1] runtime.main (Thread 1837310)"},{"id":2,"name":"[Go 2] runtime.gopark"},{"id":3,"name":"[Go 3] runtime.gopark"},{"id":4,"name":"[Go 4] runtime.gopark"},{"id":5,"name":"[Go 5] runtime.gopark"}]}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1},"type":"request","seq":39}
s--> {"seq":0,"type":"response","request_seq":39,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1000,"name":"runtime.main","source":{"name":"proc.go","path":"/opt/my-apps/go/src/runtime/proc.go"},"line":260,"column":0,"instructionPointerReference":"0x43a253","presentationHint":"subtle"}],"totalFrames":51}}

堆栈
c--> {"command":"stackTrace","arguments":{"threadId":1,"startFrame":1,"levels":19},"type":"request","seq":40}
s--> {"seq":0,"type":"response","request_seq":40,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1001,"name":"runtime.goexit","source":{"name":"asm_amd64.s","path":"/opt/my-apps/go/src/runtime/asm_amd64.s"},"line":1598,"column":0,"instructionPointerReference":"0x466d61","presentationHint":"subtle"}],"totalFrames":2}}

作用域
c--> {"command":"scopes","arguments":{"frameId":1000},"type":"request","seq":41}
s--> {"seq":0,"type":"response","request_seq":41,"success":true,"command":"scopes","body":{"scopes":[{"name":"Locals (warning: optimized function)","variablesReference":1000,"expensive":false,"source":{}}]}}

变量
c--> {"command":"variables","arguments":{"variablesReference":1000},"type":"request","seq":42}
s--> {"seq":0,"type":"response","request_seq":42,"success":true,"command":"variables","body":{"variables":[{"name":"mp","value":"*runtime.m {g0: runtime.g {stack: (runtime.stack)(0x53c7c0), stackguard0: 140727443070984, stackguard1: 140727443070984, _panic: runtime._panic nil, _defer: runtime._defer nil, m: (runtime.m)(0x53cb60), sched: (runtime.gobuf)(0x53c7f8), syscallsp: 0...","type":"runtime.m","presentationHint":{},"evaluateName":"mp","variablesReference":1001},{"name":"needUnlock","value":"(unreadable empty OP stack)","type":"bool","presentationHint":{},"evaluateName":"needUnlock","variablesReference":0},{"name":"fn","value":"(unreadable empty OP stack)","type":"func()","presentationHint":{},"evaluateName":"fn","variablesReference":0}]}}

继续
c--> {"command":"continue","arguments":{"threadId":1},"type":"request","seq":43}
s--> {"seq":0,"type":"response","request_seq":43,"success":true,"command":"continue","body":{"allThreadsContinued":true}}
s--> {"seq":0,"type":"event","event":"terminated","body":{}}

断开连接

c--> {"command":"disconnect","arguments":{"restart":false},"type":"request","seq":44}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"Process 1837310 has exited with status 0\n","source":{}}}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"Detaching\n","source":{}}}
s--> {"seq":0,"type":"response","request_seq":44,"success":true,"command":"disconnect"}
s--> {"seq":0,"type":"event","event":"terminated","body":{}}
s--> {"seq":0,"type":"event","event":"output","body":{"category":"console","output":"dlv dap (1837175) exited with code: 0\n"}}
posted @ 2023-12-07 14:45  jiftle  阅读(97)  评论(0编辑  收藏  举报