IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> VScode c++用gdb单步调试和异常捕获绕过标准库文件 -> 正文阅读

[开发工具]VScode c++用gdb单步调试和异常捕获绕过标准库文件

这个最主要的目的我原本还是用于竞赛的(如果出异常的话),可惜中文网站如果按照这个标题查根本找不到相关内容。
下面我说一下操作方法,首先C/C++如果要想调试,必须自己写launch.json和tasks.json。使用Coderun插件的请考虑自己通过加输出调试。
这里我简单讲讲,但不细致介绍。
首先是launch.json:
在configurations数组中的所有项其实是会被vscode识别成vscode调试
其中的一个选项。
一般直接在同一目录下编译一个文件.exe(tasks.json配置)
所以最终的launch.json的一个C++用G++编译的configurations可以这样配置:

		{
            "name": "G++",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": true,
            "internalConsoleOptions": "neverOpen",
            "MIMode": "gdb",
            "miDebuggerPath": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "G++"
        }

其中,miDebuggerPath是配置gdb程序的关键,这里我直接把MinGW的bin文件塞到了Path环境变量里,所以这样是肯定能访问到的。
接下来去配置preLaunchTask项的任务。直接在.vscode文件夹里(即这个launch.json的文件夹)新建一个tasks.json:

{
    "tasks": [
        {
            "type": "shell",
            "label": "G++",
            "command": "g++",
            "args": [
                "-g",
                "${file}",
                "-o",
                "${fileDirname}\\${fileBasenameNoExtension}.exe",
                "-Wall",
                "-Wno-unused-but-set-variable",
                "-DDEBUG"
            ],
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": false,
                "clear": false
            }
        },
        {
            "type": "shell",
            "label": "G++ Masm",
            "command": "g++",
            "args": [
                "-S",
                "${file}",
                "-o",
                "${fileDirname}\\${fileBasenameNoExtension}.s",
                "-masm=intel",
                "-Wno-unused-but-set-variable",
                "-DDEBUG"
            ],
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared",
                "showReuseMessage": true,
                "clear": false
            }
        }
    ],
    "version": "2.0.0"
}

同理,此处的command是shell命令,可以理解为type是shell时,相当于用cmd执行command的命令,然后后面的args串就是编译。
这种方案的编译+调试过程是单文件的,而且每次启动都会执行。做增量编译的话,不建议用这种方案,可以考虑cmake,或者自己写一个编译代理控制台程序:先检查是否有配置文件,没有则编译,然后配置文件的编译时间是否跟进程的创建时间一致,如果不一致也编译。都一致的话就跳过。这种方案可以设计成非常粗陋的增量编译方案。增量编译主要是最开始那个时间而已,我对此没有太大的需求,我甚至自己都懒得这么写。

接下来是关键,如果使用调试了之后,vscode采用的是step,所以单步调试只要gdb带有文件输出,就会定位到那个头文件上(如果自己设调试控制台里-exec next的话也就是说执行gdb的next是不会跳到文件的)。所以会打开标准库的文件,咋一看好像没啥问题,但是对于比赛来说就非常容易判断为作弊。而且,如果你采用vscode的intellisense的话,专门针对于c++配置编译器路径实现补全也必须要先标定位置,无论如何,把include之类的删了是非常危险的,最好的办法还是防止它打开。

这里我通过翻阅大量的资料得出的结论是必须配置gdb的skip(可能还有防止gdb导入符号表的),而且还要关闭一个vscode的配置(这个配置是会影响是否捕获发生在标准库内部的常规异常)

回到launch.json:
在setupCommands数组里配置成如此:

"setupCommands": [
    {
        "description": "为 gdb 启用整齐打印",
        "text": "-enable-pretty-printing",
        "ignoreFailures": true
    },
    {
        "description": "防止gdb打开标准库函数",
        "text": "-interpreter-exec console \"skip -rfu std::.*\"",
        "ignoreFailures": false
    }
]

其中-interpreter-exec console是在进程进入调试阶段配置一条命令,该字符串只能包含一个命令行(即\"\"内部的\n不会被分隔为多个语句执行只会执行最后一个),如果要输入多个行的话,要在\"\"外面写上\n再套一串-interpreter-exec console \"...\"
skip -rfu std::.*是gdb的skip命令,它的作用是使用正则串的方法绕过标准库名称空间的所有函数(这个指令可以直接百度搜到)。因为函数才是运行流程的本质,因此这样就可以绕过所有标准库发生的step(单步调试)。当然,这个的gdb至少要7.3以上。直接下载8.1的应该没这个问题。如果采用DevC++弄的mingw可能就用不了(不支持skip -rfu)。
这里配置完了单步调试的防止进入,差不多让step功能等价于next,对于非标准库名称空间可能还会有问题,比如boost,可以考虑再补个这个名称空间的。

但是即使这样还是无法完全避免打开文件,比如完成以上配置后,在标准库内部执行上发生的异常就会被捕获并打开标准库文件,还有一个必须要加的就是vscode不加载符号表的作用。
还是launch.json:

"symbolLoadInfo": {
    "loadAll": false,
    "exceptionList": ""
}

在configurations的该块中加入symbolLoadInfo并将loadAll配置为false。
这样可以避免gdb捕获异常到某个内部的符号表时打开相应的文件。
没有加loadAllfalse的
以上是没有配置为false的情况,段错误发生在内部时必然打开。
loadAll为true
可以看见不会打开erase一个end时出现的错误的stl_algobase.h
但有问题的是,如此也定位不到了具体在哪个行发生问题了(目前我还没有更好的解决方案)。你必须自行在关键位置加断点,如果此处的单步调试出问题exception了,那就说明这里有问题。

同时,只配置其中一个都是不行的,比如skip只能防止单步调试的打开,而异常照样打开,而配置loadAll看起来的意思是不加载符号表,但事实上单步调试一样会开,它仅有防止异常打开外部符号表的功能。

提供一个完整的launch.json参考:

{
    "version": "0.2.0",
    "configurations": [

        {
            "name": "G++",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": true,
            "internalConsoleOptions": "neverOpen",
            "MIMode": "gdb",
            "miDebuggerPath": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },{
                    "description": "防止gdb打开标准库函数",
                    "text": "-interpreter-exec console \"skip -rfu std::.*\"",
                    "ignoreFailures": false
                }
            ],
            "symbolLoadInfo": {
                "loadAll": false,
                "exceptionList": ""
            },
            "preLaunchTask": "G++"
        }
    ]
}
  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-04-24 09:38:44  更:2022-04-24 09:39:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/14 15:02:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码