1. 为什么我把硬件调试的底气押在这三招上
接触OpenHarmony硬件调试这几年,几乎每隔几天就会在技术群里看到同一个问题冒出来:“RK3568有那么多设备树,到底选哪个?”紧跟着的往往是“串口没输出”“启动到一半卡死”“网口怎么都不通”。这些问题看起来八竿子打不着,可归根到底,都是缺了一个硬件调试的抓手。OpenHarmony跟普通单片机开发完全是两个路子,你面对的是从Bootloader到内核再到分布式服务的完整系统,任何一个环节出问题,表象都可能只是一句“黑屏”“卡住”“没反应”,靠肉眼和万用表根本无从下手。
所以我一直把OpenHarmony硬件调试提炼成三板斧:串口日志、设备树核查、系统状态捕获。这套方法适用面很广。无论你刚拿到一块RK3568评估板,还是自己画板子做OpenHarmony适配,又或者只是在x86虚拟机里跑OpenHarmony做应用开发,三板斧都能帮你把问题从“玄学”变成“证据链”。这期教程就围绕这三板斧展开,我会把每一招的具体用法、背后原理、常见坑一次说清楚,顺便把社区里关于设备树选型和串口连接的高频疑问一并拆掉。
需要说明一下,我这边的板子以RK3568系列为主,但方法本身是通用的。无论是海思、瑞芯微,还是全志平台,只要跑的是OpenHarmony标准系统,串口、设备树、崩溃日志这套排查逻辑都成立。下面直接进入第一板斧。
2. 第一板斧:串口日志,启动全过程都在这根线上
2.1 调试串口在RK3568上的接线与波特率
先说最基础也最容易被卡住的一步:怎么把串口接出来。OpenHarmony标准系统在RK3568平台上默认的调试串口是UART0,就是通常在核心板/底板丝印上标记为DEBUG、UART_DBG或者DBG_TX/DBG_RX的那组引脚。配套的调试小板一般是USB转串口模块,常见的芯片是CH340、CP2102或者FT232,这类模块在Windows和Linux下都有现成驱动,插上之后在设备管理器里能看到对应的COM口。
接线规则不复杂,交叉接:调试板的TX接开发板的RX,调试板的RX接开发板的TX,然后共地GND。很多新手第一次接串口没输出,超过一半的原因是TX/RX接成了直连,两根线对调一下就好了。电平上,RK3568核心板的调试串口通常是1.8V或者3.3V电平,和USB转串口模块的电平不完全匹配时,建议用带电平转换的模块,但绝大多数评估板已经在底板做了电平匹配,直接连模块就能用。
接下来是波特率。OpenHarmony标准系统在RK3568上默认调试串口波特率是1500000,也就是1.5Mbps。这一点跟很多传统嵌入式设备默认115200的习惯完全不同,我刚接触时也在这上面栽过跟头,拿着115200去连,屏幕上全是乱码。但也有部分厂商的建议方案文档里写的是115200,所以正确做法是:先查你手头板卡的官方文档确认波特率;确认不了就直接试1500000,如果乱码再换115200。像MobaXterm、SecureCRT、PuTTY都能自定义波特率,Linux下用minicom/picocom,macOS直接用screen命令也能连。
我平时在Windows下用得最多的是MobaXterm,新建Session选Serial,填上COM口号和波特率,回车就能看到开机日志。Linux下推荐picocom,一条命令就够:
sudo picocom -b 1500000 /dev/ttyUSB0如果你用的是虚拟机作为日常工作环境,记得把USB转串口设备直通到虚拟机里,否则宿主机能看到串口、虚拟机看不到。
2.2 串口终端里的两类日志:内核的dmesg与系统的hilog
串口接通之后,按一下开发板的复位键或者重新上电,你会看到一整屏日志从眼前滚过去。很多人看到日志就晕,不知道该看哪一段。这里有一个基本的分层概念,对后续定位问题至关重要。
第一类是内核日志,包括U-Boot阶段和Linux内核阶段的输出。U-Boot阶段会打印SoC信息、DDR初始化结果、启动介质和环境变量等信息;内核阶段会打印各个驱动的probe情况、设备树加载情况、内存布局等。这类日志在OpenHarmony系统起来之后,可以通过dmesg命令重新查看。
第二类是系统级日志,也就是HiLog。OpenHarmony的应用框架、系统服务、分布式软总线、传感器、电源管理等模块都会通过HiLog体系记录日志。HiLog日志会通过系统的hilogd服务同时输出到串口控制台,所以串口上看到的彩色日志(如果没有关闭颜色的话)大多数属于这一类。
这两类日志的分工可以简单理解为:内核日志告诉你“硬件层跑没跑通”,HiLog告诉你“系统服务和应用层发生了什么”。排查启动问题,通常先把内核日志和系统日志的分界时间点找到:当你看到类似[OHOS]或者#开头的shell提示符出现时,说明内核已经启动完毕,init和后续系统服务开始运行,后面打印的就是系统级日志了。
在实际排查中,我会同时开两个窗口,一个窗口用MobaXterm盯着串口实时日志,另一个窗口在板子上执行dmesg | grep -i "fail\|error"过滤内核报错。串口日志是实时流水,适合看现场;dmesg则是事后翻记录,适合找线索。
2.3 通过日志级别过滤,快速锁定异常模块
串口日志刷屏是一个很现实的问题。尤其是OpenHarmony标准系统,开机后各种系统服务、分布式能力组件都会打日志,一屏一屏往外滚,你根本来不及看。这时候用过滤就很关键了。
在串口控制台上,如果系统已经正常起来并且能进入shell(通过串口进入的shell),你可以用hilog命令做级别过滤和关键字过滤。hilog的基本用法是:
hilog # 持续实时输出系统日志 hilog -e "ERROR" # 只输出包含ERROR的日志 hilog -e "FATAL" # 只看致命错误 hilog -w # 清空当前日志缓冲区 hilog -x # 退出hilog实时输出这套命令在调试阶段非常实用。我遇到系统服务反复重启或者某个应用崩溃时,会先把实时日志停下来,然后执行:
hilog -w # 复现一次问题操作 hilog -e "FATAL"清空缓冲区之后再做一次问题复现,随后只查看FATAL级别的日志,这样做的好处是把无关信息全部过滤掉,问题的“第一现场”会非常干净。如果是内核驱动级别的问题,dmesg里的fail、error、timeout就是重点对象,配合时间戳或者驱动的名字一起grep,比如网口驱动是gmac,就执行:
dmesg | grep -i "gmac\|stmmac\|eth"内核日志里的报错信息和HiLog里的FATAL信息往往能互相印证。串口不是只看一遍就完事的东西,它是整台设备的“飞行记录仪”,把关键节点日志保存下来,后续排查设备树或者服务状态时会反复用到。
2.4 真机经验:串口连不上、乱码、刷屏的排查方向
串口部分最后集中说三个高频问题,都是我实际踩过或者看别人踩过的。
第一个是完全没有输出。按复位键后串口终端一片空白。优先检查:接线是否交叉、GND是否共地、波特率是否与板卡文档一致、USB转串口模块是否被系统识别(Windows下设备管理器有没有多出COM口)。如果模块识别了但没输出,再检查是不是接错了引脚,有些底板上有好几组排针,标注为GPIO的并不一定是调试串口。
第二个是乱码。乱码意味着波特率不匹配,或者电平逻辑有问题。先换波特率试(1500000、115200、921600这几个都试一遍),还是乱码的话检查USB转串口模块和板卡之间的电平,特别是需要外接供电的模块,看看有没有共地。还有一种情况是板卡上的调试串口被系统复用成其他功能了,这个在OpenHarmony里可以通过设备树重新配置,后面第二板斧会讲到。
第三个是日志狂刷导致卡顿。系统起来后日志量太大,串口工具都拖不动。这本身可以通过配置HiLog的输出级别来解决,但更快的临时办法是在串口终端里按Ctrl+C中断当前的hilog输出,回到shell提示符下再按需查看日志。商用调试中,也有人直接在系统起来后把串口日志级别调低,让串口只输出ERROR和FATAL。
3. 第二板斧:设备树,先把“板子是谁”告诉内核
3.1 为什么RK3568的设备树文件多到让人发懵
热搜词里“openharmony的rk3568有许多设备树到底咋选”这个问题,我几乎每天都能看到。根本原因在于,OpenHarmony官方、芯片原厂、以及各开发板厂商会基于同一颗RK3568芯片维护多套设备树文件。RK3568是一颗通用SoC,它本身只有芯片级的能力定义,比如CPU核心、GPU、内存控制器、各类接口控制器;但一块具体的板子上,用的DDR是DDR3还是DDR4还是LPDDR4,走的是哪个PHY地址,网口用的是千兆还是百兆,LCD屏幕的分辨率和时序参数,触摸屏走I2C还是SPI,这些全部由板级设备树来描述。
所以你在内核源码的arch/arm64/boot/dts/rockchip/目录下会看到一大堆rk3568开头的dts文件和dtsi文件,比如:
rk3568-evb1-ddr4-v10.dtsrk3568-evb2-lpddr4-v10.dtsrk3568-evb4-ddr4-v10.dtsrk3568-evb5-lpddr3-v10.dtsrk3568-nvr-demo-v10.dts
这还只是原厂内核的一部分。各开发板厂商拿到源码后,会基于这些文件复制一份,改改名、改改外设配置,就成了自己板卡的设备树。所以“设备树多”不是因为内核在有意制造困惑,而是因为硬件组合本身太多。理解了这一点,你的心态就会从“选哪个”变成“我的板子硬件到底是什么样”,这个思路转变很关键。
3.2 从dtsi到dts:设备树的覆盖机制
要理解设备树为什么可以一个套一个,得先明白dtsi和dts的关系。dtsi是“include文件”,类似于C语言的头文件,定义的是可以被复用的设备树片段;dts是最终编译成dtb的源文件。一个典型的RK3568工程,会有这么几层:
rk3568.dtsi:SoC级定义。描述CPU、中断控制器、I2C控制器、UART控制器、GMAC控制器等所有芯片内部IP的默认状态。注意,这里多数节点默认status = "disabled",具体用不用由板级决定。rk3568-evb.dtsi:板级公共定义。这块板子上有哪些外设、哪些IO被复用了,通常会写在这里。rk3568-evb1-ddr4-v10.dts:具体型号定义。DDR类型、屏幕型号、触摸IC这些更“个性”的东西写在这里。
各个文件通过#include一层层组合,后包含的文件可以覆盖前面文件里的节点属性。这就是设备树最核心的机制:继承加覆盖。你在某个具体的dts里看到一个&gmac1节点,它不是凭空出现的,而是先在rk3568.dtsi里把gmac1控制器定义好,再在这个文件里把status改成"okay",并补上PHY地址、复位引脚等信息。
所以在改设备树之前,必须知道自己正在操作的是哪一层。最常见的问题是在某个dtsi里改了外设配置,结果编译出来的dtb根本没包含这个文件,改了等于白改。正确做法是先追#include链,确认当前dts确实引用了你改的文件。
3.3 日常开发中如何锁定当前板卡对应的dts
现在回答那个高频问题:RK3568设备树到底咋选。我的做法是按下面几步来,基本能锁定正确目标。
第一步看外观丝印。大部分开发板会在PCB上标注型号,比如EVB1、EVB2、V10等,这些代号与设备树文件名字直接相关。找到丝印之后再到源码目录里找匹配的dts文件。
第二步看内存颗粒类型和容量。DDR3、DDR4、LPDDR4在设备树里是不同的文件后缀(ddr3、ddr4、lpddr4)。如果你用的是6GB的LPDDR4板子,结果选了ddr4的dts,大概率识别出的内存容量不对,系统起来之后动不动就出问题。确定内存类型最直接的办法是看板卡规格书,或者拆开散热片看颗粒丝印。
第三步看官方资料。OpenHarmony官方在文档中心的“标准系统入门”里,对不同的开发板(如RK3568 EVB系列)都会列出对应的内核源码分支和设备树名称。很多厂商的README里也会写“本SDK基于rk3568-evb1-ddr4-v10.dts适配”。
第四步看U-Boot日志。这一步非常有用。板子上电时,U-Boot会打印出它读取的板级信息,有些版本会直接显示Board: Rockchip Linux Board,甚至包含具体的dts名称。串口日志里能看到一行类似Device Tree: rk3568-evb1-ddr4-v10.dtb的信息,那就是U-Boot实际加载的设备树。
第五步系统起来之后验证。这是最稳妥的兜底方案。板子能进系统后,读取设备树中的model属性:
cat /sys/firmware/devicetree/base/model正常会输出类似"Rockchip RK3568 EVB1 DDR4 V10 Board"的字符串,如果你手上板子明明是EVB2,但输出的是EVB1,那就说明当前加载的设备树和硬件不匹配,烧录时需要重新打包正确的dtb。
3.4 设备树编译、打包与加载验证
在OpenHarmony工程里,设备树的编译和打包不是单独执行的,而是集成在内核编译链路中。你通常需要在板级目录下的配置文件中指定设备树名称。以RK3568为例,在device/board或者vendor下相应板卡目录的config.gni或BUILD.gn中,会有一个变量指定内核设备树文件名,我这边常见的配置项类似kernel_device_tree_name或dts_name,值就是rk3568-evb1-ddr4-v10.dts去掉“_dts”后缀的名字。
配置好之后,执行OpenHarmony的编译命令,比如:
./build.sh --product-name rk3568 --ccache编译完成之后,生成的dtb会被打包到boot分区镜像里。烧录时,boot分区被写进板子,U-Boot从boot分区读取dtb并传递给内核。也就是说,设备树选错,往往是在内核启动那一刻就错了。很多时候你在源码里改了dts,重新编译后也烧录了,但启动后没效果,先去查一下编译产物里的dtb是不是你改的那个——这能省掉大量的无效排查时间。
我习惯在拿到一个OpenHarmony内核源码树之后,先找到目标dts,然后用下面的命令快速查看它最终包含哪些关键配置:
grep -n "gmac\|lcd\|touch\|i2c" rk3568-evb1-ddr4-v10.dts | head -50这个操作能让你在一分钟之内对这个板卡的外设配置有个整体印象。
3.5 选错设备树的典型现象与快速识别
选错设备树的症状通常不是“完全不能开机”,而是“带病运行”,这一点特别容易坑人。我列一个自己遇到过的对照表,方便你快速自查:
| 现象 | 很可能的原因 |
|---|---|
| 开机卡在U-Boot阶段,根本进不了内核 | 内存类型/容量参数不匹配,DDR初始化失败 |
| 内核启动过程中反复panic | 外设地址或中断冲突,常见于引脚复用重叠 |
| 系统能起来但网络不通,eth0不存在 | GMAC节点未打开,或者PHY地址/复位引脚不对 |
| 屏幕有背光但无显示,或颜色错乱 | LCD时序/分辨率参数不匹配 |
| 触摸没反应 | 触摸IC的I2C地址或中断脚配置不对 |
| USB设备不识别 | USB控制器或PHY配置错误 |
快速识别当前设备树是不是匹配,有几条捷径。第一是前面说的cat /sys/firmware/devicetree/base/model。第二是看dmesg里的DDR信息,对比实际板卡的内存容量和类型:
dmesg | grep -i "memory\|DDR"第三是看外设驱动的probe日志。以网口为例,如果设备树正确,内核日志里会出现stmmaceth相关的成功绑定信息;如果找不到PHY,会报类似cannot attach to PHY的错误。这串日志往往比任何文档都诚实。
4. 第三板斧:崩溃与服务状态捕获,让现场证据说话
4.1 hdc通路的建立与日常命令
串口日志负责看过程,设备树负责看配置,但有些问题发生得太快、复现太随机,光靠串口抓不到。这时候就要用第三板斧——通过hdc工具进到系统内部,抓崩溃现场和系统状态。
hdc是OpenHarmony的设备连接工具,功能类似Android调试里的adb。它支持USB连接和网络连接两种方式。USB连接时,先确保设备上开启了开发者模式(系统设置里连续点击版本号),然后用USB线连接开发板的OTG口和电脑:
hdc list targets如果列出了设备序列号,说明通路建立成功。网络连接用于远程设备或者虚拟机里跑OpenHarmony的场景,需要在设备上开启网络调试后,在主机侧执行:
hdc tconn 192.168.1.100:5555我经常用一个命令组合来确认系统核心状态:
hdc shell "param get | grep -i version" hdc shell "hilog -e \"FATAL\"" hdc shell "dmesg | tail -100"hdc出现连接不上的问题,先检查USB线是不是数据线(很多线只能充电不能传数据),再检查设备开发者模式有没有打开,最后看hdc服务是否需要重启:
hdc kill hdc start4.2 faultlogger:崩溃后自动留下的案底
OpenHarmony系统里有一个叫faultlogger的组件,专门负责记录系统和应用的崩溃信息。当某个进程发生崩溃(比如空指针、段错误、非法指令),faultlogger会自动把崩溃现场保存到日志目录。这是排查“偶现崩溃”最重要的证据来源,比你在串口屏幕前干等强一百倍。
查看崩溃日志的路径非常固定:
hdc shell "ls -lt /data/log/faultlog/faultlogger/" | head -20文件命名一般包含模块名、进程名、进程ID和时间戳。拿到最新的崩溃文件后,我用下面的命令把内容拉到本地仔细看:
hdc shell "cat /data/log/faultlog/faultlogger/xxx_faultlog.log"崩溃日志里重点看三块:异常类型(比如SIGSEGV、SIGABRT)、寄存器现场、调用栈回溯。调用栈能直接告诉你崩在哪个函数里,配合源码定位通常半小时内就能找到问题。很多开发者遇到崩溃第一反应是“重新编译试试”,我的建议是先看faultlog,往往比重编快得多。
4.3 hidumper:不重启系统也能拿系统状态
有时候问题不是崩溃,而是某个外设或服务状态不对,比如LCD不亮、WiFi连不上、传感器没有数据。这时候用hidumper把系统内部状态“dump”出来,比猜靠谱得多。
hidumper是OpenHarmony自带的系统信息导出工具,能输出CPU、内存、系统服务等多个维度的状态。它的参数比较多,不同版本略有差异,我习惯先执行:
hdc shell hidumper -h查看当前版本的帮助,确认参数后再执行对应的dump操作。比如查看系统整体配置和负载,可以用--cpuusage和--memory;查看服务列表和状态,用-s加服务名;如果某个服务是你要调试的对象,直接调用该服务的dump接口输出内部状态。
hidumper的核心价值在于:不需要重启,不需要打断现场,就能拿到系统运行时的内部视图。比如说你怀疑某个系统服务挂了,通过hidumper查看它能发现服务其实还活着,只是某个内部状态不对,这时候问题就收敛到了该服务的日志上,排查范围一下子缩小很多。
4.4 开启coredump并解读最小线索
崩溃日志(faultlog)记录的是异常发生时的寄存器信息和调用栈,但有时候栈回溯不够深,或者问题出在内存被写坏,看不到直接原因。这时候就需要coredump,也就是把进程崩溃瞬间的完整内存镜像保存下来,离线用调试器分析。
OpenHarmony的coredump功能默认不一定开启,需要用系统参数控制。我常用下面这条命令查看当前状态:
hdc shell "param get coredump.filter"如果返回0或者不在预期的开启范围内,就按官方文档把过滤等级调到合适值再复现一次问题。开启coredump之后,崩溃瞬间会把核心转储文件写到指定目录,通常是/data/core或/data/log/faultlog/temp下面。拿到coredump文件后,配合对应版本的符号表,用调试工具(比如llvm或gdb)就能还原出完整的调用堆栈。
有一点要提醒:coredump文件体积很大,低内存设备开启后要留意存储空间。我一般只在需要深挖某个疑难崩溃时临时开启,定位完就关掉,不让设备长期处于这个状态。
4.5 跑x86版OpenHarmony的调试补充
热搜词里有一条“电脑版x86 openharmony”,很多人用虚拟机跑OpenHarmony做应用开发和分布式调试。x86版本和RK3568这类真机的调试套路基本一致,差别主要在串口和hdc的连接方式上。
如果你用的是QEMU跑OpenHarmony x86镜像,串口可以通过QEMU的启动参数映射出来。一个常见的做法是把串口重定向到pty设备:
qemu-system-x86_64 -serial pty -display gtk启动后QEMU会提示char device redirected to /dev/pts/3,然后用minicom或picocom连接这个pts设备就能看到串口日志。如果想把串口输出直接放到终端里,可以加参数:
qemu-system-x86_64 -nographic这样QEMU把虚拟串口和标准输入输出绑定,所有串口日志直接打在当前终端上,对快速启动和观察日志来说非常方便。
hdc连接虚拟机里的OpenHarmony,则可以通过QEMU的端口转发功能。把设备侧的hdc监听端口映射到宿主机,比如:
qemu-system-x86_64 -netdev user,id=net0,hostfwd=tcp::5555-:5555 -device e1000,netdev=net0然后在宿主机执行hdc tconn 127.0.0.1:5555就能连上。x86虚拟环境的硬件外设跟真机不一样,设备树的概念相对弱化,但崩溃日志、hidumper、hilog这套排查思路完全通用。
5. 用一个真实场景串起来:板子起来了,但网口不通
5.1 串口日志先定位“挂在哪一层”
前面三招分开讲,很多人还是不知道怎么组合。我拿一个实际案例完整走一遍:一块RK3568开发板,烧录OpenHarmony标准系统后,系统能正常启动,屏幕也亮了,但网口插上网线后怎么都不通,ifconfig看不到eth0。
第一步,我先看串口日志。在串口终端里执行dmesg | grep -i "eth\|gmac\|stmmac\|phy",如果日志里完全搜不到GMAC驱动的初始化信息,说明设备树里GMAC节点没有打开,或者PHY没有成功探测。如果日志里能看到stmmac相关信息但报错cannot attach to PHY,说明驱动起来了但PHY(物理层芯片)没挂上,问题通常在PHY的地址配置或者复位引脚上。
这里有个判断技巧:系统能进入shell,说明内核整体没崩,问题大概率是板级配置层面的,优先怀疑设备树;如果连内核都进不去,那就回到DDR、启动介质、引脚复用这些更底层的问题。
5.2 设备树核查确认“板子身份”
第二步,我执行:
cat /sys/firmware/devicetree/base/model结果打印出来的是Rockchip RK3568 EVB1 DDR4 V10 Board。但看板卡丝印和规格书,手上这块是EVB2、LPDDR4的板子。到这里,问题已经很明显:烧录的boot分区里打包的设备树是EVB1版本,和硬件不匹配。
结合之前看的dmesg日志,GMAC节点在EVB1和EVB2设备树里配置的PHY地址、复位GPIO都不一样,所以驱动起来后找不到正确的外部PHY,网口自然不通。定位到这一步,后面就是标准的设备树修正流程:在内核源码里找到EVB2对应的dts文件(比如rk3568-evb2-lpddr4-v10.dts),确认板级配置文件里要编译的dtb名称,重新编译boot分区镜像,再烧录验证。
5.3 崩溃与服务状态dump进一步收口
如果修改设备树重新烧录后网口还是不通,就需要第三板斧上场。先用hdc shell连进系统,执行:
hdc shell "ifconfig -a" hdc shell "dmesg | grep -i \"gmac\|stmmac\" | tail -50"看接口是否存在。如果eth0出现了但没拿到IP,检查DHCP或者手动配置IP,这时候需要用网络层的排查手段去解决,比如ping网关、检查路由表,这部分就是另一个话题了。
如果在日志里看到网口驱动反复报错,但没有明显的设备树问题,那就打开faultlog和历史日志:
hdc shell "ls -lt /data/log/faultlog/faultlogger/" hdc shell "hilog -e \"DHCP\|wifi\|netmanager\""以此判断是系统网络管理服务的问题,还是硬件驱动的问题。一个网口不通的问题,通过三板斧一层层排查下来,基本不会出现“无从下手”的情况。
6. 三板斧之后的习惯,才是真正值钱的东西
方法讲完了,最后说几句掏心窝的话。三板斧本质上不是在教你三个孤立技巧,而是在帮你建立一套闭环:串口看过程、设备树看身份、状态捕获看现场。很多同学拿到板子第一件事是急着烧录、急着跑应用,但我建议把顺序反过来:先确认串口能通,再确认设备树匹配,最后再开始功能开发。这三件事如果没做扎实,后续排查成本会成倍增加。
我自己的习惯清单大概是这样:新板子到手,先花十分钟接线开串口,把启动日志完整存一份;再读一下设备树的model属性确认板卡身份,顺便看一眼DDR配置;系统正常运行之后,做一次faultlog目录的基线记录,这样后面出问题就知道哪些日志是新产生的。这些习惯看起来不起眼,但在真正遇到疑难问题的时候,它们能帮你省下一整天的排查时间。
另外,OpenHarmony版本迭代很快,不同版本之间串口默认行为、hdc命令参数、faultlog路径可能都有细微差异。遇到和教程对不上的地方,先查你当前版本文档,再结合串口日志里实际打印的报错信息去判断,这个能力比记住任何具体命令都更值钱。