c语言 backtrace

2023-05-16

c语言 backtrace

版权声明:本文为CSDN博主「zhouyuming_hbxt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zym326975/article/details/114270695
原文链接2:https://www.bilibili.com/video/BV11L411A7fC?spm_id_from=333.337.search-card.all.click&vd_source=e00de32c6d84e616df38f2063641aa28

1:函数简介
通常,应用程序使用外部调试程序(比如gdb)进行调试,但有时出于统计、分析等目的,可在程序自身内使用函数backtrace记录应用程序的堆栈轨迹。
应用程序通常使用专用调试器来调试程序,但在有些情况下,调试器可能无法使用。而且,无论怎样,当程序出现问题时,向开发人员提供尽可能多的现场信息终究是有利的

因此,C库中提供了backtrace系列函数,利用这些函数可以记录在错误出现之前应用程序的运行轨迹,帮助开发人员更快地定位问题。
注:backtrace(回溯)指的是线程中当前活跃的函数调用。

backtrack系列函数包括以下三个:
1.函数backtrace的声明位于头文件execinfo.h,函数原型是:

int backtrace(void **buffer, int size);

函数backtrace返回调用程序的堆栈回溯,结果保存在参数buffer中,buffer指向数组中的每一项都是void *类型,它们是堆栈中的返回地址。参数size指定buffer中可以存放的最大数目,如果返回地址的数量多于size,则返回最近的size个地址。因此,要想获取完整的返回地址列表,buffer必须足够大。
注:返回地址的数量正常情况下不会很大,即使大型软件,也很少有超过50层嵌套。

当函数成功返回时,返回值是buffer中实际的地址数量,这个值小于等于size;如果返回值=size,那么buffer中的返回地址可能不是全部。

2.函数backtrace_symbols的声明位于头文件execinfo.h,函数原型是

char **backtrace_symbols(void *const *buffer, int size)

函数backtrace_symbols将给定buffer中的返回地址转换为符号化的地址字符串。参数size指定buffer中的地址数量。每个地址的符号表示包括:函数名称(如果能够解析)、函数内的偏移量(十六进制)以及实际的返回地址(十六进制)。该函数的结果是字符串指针数组的地址,并且由backtrace_symbols用malloc分配存储空间,使用者负责用free释放内存(数组成员无需也不能用free释放)

注:只有使用ELF格式的二进制程序和库才能获得函数名称,并且可能还需要向连接器传输特殊选项(比如GNU ld,要传递-rdynamic)

当函数成功完成时,返回值是字符串数组的地址;否则,返回NULL

3.函数backtrace_symbols_fd原型是:

void backtrace_symbols_fd(void *const *buffer, int size, int fd);

与前面不同的是,其不会返回字符串数组,而是将字符串写入fd所代表的文件,一行一个,还有一个不同的是,它不使用malloc,因此在malloc可能会失败的某些场合,可以使用这个函数来代替。

使用它们的时候有一下几点需要我们注意的地方:

A:backtrace的实现依赖于栈指针(fp寄存器),在gcc编译过程中任何非零的优化等级(-On参数)或加入了栈指针优化参数-fomit-frame-pointer后多将不能正确得到程序栈信息;
B:backtrace_symbols的实现需要符号名称的支持,在gcc编译过程中需要加入-rdynamic参数;
C:内联函数没有栈帧,它在编译过程中被展开在调用的位置;
D:尾调用优化(Tail-call Optimization)将复用当前函数栈,而不再生成新的函数栈,这将导致栈信息不能正确被获取。

2 :捕获系统异常信号输出调用栈
当程序出现异常时通常伴随着会收到一个由内核发过来的异常信号,如当对内存出现非法访问时将收到段错误信号SIGSEGV,然后才退出。利用这一点,当我们在收到异常信号后将程序的调用栈进行输出,它通常是利用signal()函数,关于系统信号的总结可以参考另外一篇文章:
https://zhouyuming.blog.csdn.net/article/details/114437653

3:从backtrace信息分析定位问题

3.1 测试程序
为了更好的说明和分析问题,我这里将举例一个小程序,它有三个文件组成分别是backtrace.c、dump.c、add.c,其中add.c提供了对一个数值进行加一的方法,我们在它的执行过程中故意使用了一个空指针并为其赋值,这样人为的造成段错误的发生;dump.c中主要用于输出backtrace信息,backtrace.c则包含了我们的main函数,它会先注册段错误信号的处理函数然后去调用add.c提供的接口从而导致发生段错误退出。它们的源程序分别如下:

/* 
 *   add.c 
 */  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
  
int add1(int num)  
{  
    int ret = 0x00;  
    int *pTemp = NULL;  
      
    *pTemp = 0x01;  /* 这将导致一个段错误,致使程序崩溃退出 */  
      
    ret = num + *pTemp;  
      
    return ret;  
}  
  
int add(int num)  
{  
    int ret = 0x00;  
  
    ret = add1(num);  
      
    return ret;  
}  
/* 
 *   dump.c 
 */  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <signal.h>       /* for signal */  
#include <execinfo.h>     /* for backtrace() */  
  
#define BACKTRACE_SIZE   16  
  
void dump(void)  
{  
    int j, nptrs;  
    void *buffer[BACKTRACE_SIZE];  
    char **strings;  
      
    nptrs = backtrace(buffer, BACKTRACE_SIZE);  
      
    printf("backtrace() returned %d addresses\n", nptrs);  
  
    strings = backtrace_symbols(buffer, nptrs);  
    if (strings == NULL) {  
        perror("backtrace_symbols");  
        exit(EXIT_FAILURE);  
    }  
  
    for (j = 0; j < nptrs; j++)  
        printf("  [%02d] %s\n", j, strings[j]);  
  
    free(strings);  
}  
  
void signal_handler(int signo)  
{  
      
#if 0     
    char buff[64] = {0x00};  
          
    sprintf(buff,"cat /proc/%d/maps", getpid());  
          
    system((const char*) buff);  
#endif    
  
    printf("\n=========>>>catch signal %d <<<=========\n", signo);  
      
    printf("Dump stack start...\n");  
    dump();  
    printf("Dump stack end...\n");  
  
    signal(signo, SIG_DFL); /* 恢复信号默认处理 */  
    raise(signo);           /* 重新发送信号 */  
}  
/* 
 *   backtrace.c 
 */  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <signal.h>       /* for signal */  
#include <execinfo.h>     /* for backtrace() */  
  
extern void dump(void);  
extern void signal_handler(int signo);  
extern int add(int num);  
  
int main(int argc, char *argv[])  
{  
    int sum = 0x00;  
      
    signal(SIGSEGV, signal_handler);  /* 为SIGSEGV信号安装新的处理函数 */  
      
    sum = add(sum);  
      
    printf(" sum = %d \n", sum);  
      
    return 0x00;  
} 

3.2 静态链接情况下的错误信息分析定位

我们首先将用最基本的编译方式将他们编译成一个可执行文件并执行,如下:

gcc -g -rdynamic backtrace.c add.c dump.c -o backtrace
./backtrace  

=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 8 addresses
  [00] ./backtrace(dump+0x1f) [0x400a9b]
  [01] ./backtrace(signal_handler+0x31) [0x400b63]
  [02] /lib/x86_64-linux-gnu/libc.so.6(+0x36150) [0x7f86afc7e150]
  [03] ./backtrace(add1+0x1a) [0x400a3e]
  [04] ./backtrace(add+0x1c) [0x400a71]
  [05] ./backtrace(main+0x2f) [0x400a03]
  [06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f86afc6976d]
  [07] ./backtrace() [0x400919]
Dump stack end...
段错误 (核心已转储)

由此可见在调用完函数add1后就开始调用段错误信号处理函数了,所以问题是出在函数add1中。这似乎还不够,更准确的位置应该是在地址0x400a3e处,但这到底是哪一行呢,我们使用addr2line命令来得到,执行如下:

addr2line -e backtrace 0x400a3e

/home/share/work/backtrace/add.c:13

3.3 动态链接情况下的错误信息分析定位

然而我们通常调试的程序往往没有这么简单,通常会加载用到各种各样的动态链接库。如果错误是发生在动态链接库中那么处理将变得困难一些。下面我们将上述程序中的add.c编译成动态链接库libadd.so,然后再编译执行backtrace看会得到什么结果呢。

/* 编译生成libadd.so */
gcc -g -rdynamic add.c -fPIC -shared -o libadd.so

/* 编译生成backtrace可执行文件 */
gcc -g -rdynamic backtrace.c dump.c -L. -ladd -Wl,-rpath=. -o backtrace

其中参数 -L. -ladd为编译时链接当前目录的libadd.so;参数-Wl,-rpath=.为指定程序执行时动态链接库搜索路径为当前目录,否则会出现执行找不到libadd.so的错误。然后执行backtrace程序结果如下:

./backtrace

=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 8 addresses
  [00] ./backtrace(dump+0x1f) [0x400a53]
  [01] ./backtrace(signal_handler+0x31) [0x400b1b]
  [02] /lib/x86_64-linux-gnu/libc.so.6(+0x36150) [0x7f8583672150]
  [03] ./libadd.so(add1+0x1a) [0x7f85839fa5c6]
  [04] ./libadd.so(add+0x1c) [0x7f85839fa5f9]
  [05] ./backtrace(main+0x2f) [0x400a13]
  [06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f858365d76d]
  [07] ./backtrace() [0x400929]
Dump stack end...
段错误 (核心已转储)

此时我们再用前面的方法将得不到任何信息,如下:

addr2line -e libadd.so 0x7f85839fa5c6

??:0

出现这种情况是由于动态链接库是程序运行时动态加载的而其加载地址也是每次可能多不一样的,可见0x7f85839fa5c6是一个非常大的地址,和能得到正常信息的地址如0x400a13相差甚远,其也不是一个实际的物理地址(用户空间的程序无法直接访问物理地址),而是经过MMU(内存管理单元)映射过的。
有上面的认识后那我们就只需要得到此次libadd.so的加载地址然后用0x7f85839fa5c6这个地址减去libadd.so的加载地址得到的结果再利用addr2line命令就可以正确的得到出错的地方;另外我们注意到(add1+0x1a)其实也是在描述出错的地方,这里表示的是发生在符号add1偏移0x1a处的地方,也就是说如果我们能得到符号add1也就是函数add1在程序中的入口地址再加上偏移量0x1a也能得到正常的出错地址。
我们先利用第一种方法即试图得到libadd.so的加载地址来解决这个问题。我们可以通过查看进程的maps文件来了解进程的内存使用情况和动态链接库的加载情况,所以我们在打印栈信息前再把进程的maps文件也打印出来,加入如下代码:

char buff[64] = {0x00};  
      
sprintf(buff,"cat /proc/%d/maps", getpid());  
      
system((const char*) buff); 

然后编译执行得到如下结果(打印比较多这里摘取关键部分):

....................................................
7f0962fb3000-7f0962fb4000 r-xp 00000000 08:01 2895572                    /home/share/work/backtrace/libadd.so
7f0962fb4000-7f09631b3000 ---p 00001000 08:01 2895572                    /home/share/work/backtrace/libadd.so
7f09631b3000-7f09631b4000 r--p 00000000 08:01 2895572                    /home/share/work/backtrace/libadd.so
7f09631b4000-7f09631b5000 rw-p 00001000 08:01 2895572                    /home/share/work/backtrace/libadd.so
.....................................................
=========>>>catch signal 11 <<<=========
Dump stack start...
backtrace() returned 8 addresses
  [00] ./backtrace(dump+0x1f) [0x400b7f]
  [01] ./backtrace(signal_handler+0x83) [0x400c99]
  [02] /lib/x86_64-linux-gnu/libc.so.6(+0x36150) [0x7f0962c2b150]
  [03] ./libadd.so(add1+0x1a) [0x7f0962fb35c6]
  [04] ./libadd.so(add+0x1c) [0x7f0962fb35f9]
  [05] ./backtrace(main+0x2f) [0x400b53]
  [06] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed) [0x7f0962c1676d]
  [07] ./backtrace() [0x400a69]
Dump stack end...
段错误 (核心已转储)

Maps信息第一项表示的为地址范围如第一条记录中的7f0962fb3000-7f0962fb4000,第二项r-xp分别表示只读、可执行、私有的,由此可知这里存放的为libadd.so的.text段即代码段,后面的栈信息0x7f0962fb35c6也正好是落在了这个区间。所有我们正确的地址应为0x7f0962fb35c6 - 7f0962fb3000 = 0x5c6,将这个地址利用addr2line命令得到如下结果:

addr2line -e libadd.so 0x5c6
/home/share/work/backtrace/add.c:13

可见也得到了正确的出错行号。

接下来我们再用提到的第二种方法即想办法得到函数add的入口地址再上偏移量来得到正确的地址。要得到一个函数的入口地址我们多种途径和方法,比如生成查看程序的map文件;使用gcc的nm、readelif等命令直接对libadd.so分析等。在这里我们只介绍生成查看程序的map文件的方法,其他方法可通过查看gcc手册和google找到。
利用gcc编译生成的map文件,用如下命令我们将编译生成libadd.so对应的map文件如下:

gcc -g -rdynamic add.c -fPIC -shared -o libadd.so -Wl,-Map,add.map

Map文件中将包含关于libadd.so的丰富信息,我们搜索函数名add1就可以找到其在.text段的地址如下:

................................... 
.text          0x00000000000005ac       0x55 /tmp/ccCP0hNf.o
                0x00000000000005ac                add1
                0x00000000000005dd                add
...................................

由此可知我们的add1的地址为0x5ac,然后加上偏移地址0x1a即0x5ac + 0x1a = 0x5c6,由前面可知这个地址是正确的。

#/bin/bash
# assembler2c.sh
#帮助函数
function help
{
    echo ""
    echo $1
    echo ""
    echo "Usage: $0 libXXX.dbg FunctionName Offset"
    echo ""
    echo "          libXXX.dbg    --  The dbg file of the exception dymanic library."
    echo "          FunctionName  --  Exception function name in callstack."
    echo "          Offset        --  Exception instruction offset in exception function. It must be start with 0x."
    echo ""
}

#检查参数
if [ $# != 3 ]; then
    help "Error : Argu must be 3!"
    exit 1
fi

#检查文件是否存在
if [ ! -f $1 ]; then
    help "File $1 not Found!"
    exit 1
fi

#检查文件格式是否是ELF格式
type=`file $1 | grep ELF | wc -l`
if [ $type == 0 ]; then
    help "$1 :file type is not ELF!"
    exit 1
fi

#检查函数是否包含在dbg文件中
containflag=`objdump -t $1 | grep " $2$" | wc -l`
if [ $containflag == 0 ]; then
    help "$1 :Function not in this dbg file!"
    exit 1
fi

#获取函数基地址
baseaddr=`objdump -t $1 | grep " $2$" | grep .text | awk {'print $1'}`

#获取指令最终地址
destaddr=`printf "%x" $[0x$baseaddr+$3]`
if [ $? != 0 ]; then
    help "please check argu!"
    exit 1
fi

#打印输出
addr2line -e $1 0x$destaddr
echo ""

使用方法:
sh assembler2c.sh libxx.dbg function_name offset_of_function

1、根据程序异常栈查找出错代码
2、gdb *.so

3、file *.gdb

4、l *(func_name+0xxxx) 0xxxx为接口func_name的偏移地址

objdump相关符号表查找:

objdump -t xxx.dbg | grep xxx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言 backtrace 的相关文章

  • Backtrace 分析

    xfeff xfeff 1 Java Backtrace 从Java Backtrace 我们可以知道当时Process 的虚拟机执行状态 Java Backtrace 依靠SignalCatcher 来抓取 Google default
  • Backtrace in Android

    Backtrace in Android 96 Tsing2015 0 7 2016 02 28 23 03 字数 33 阅读 2491评论 8喜欢 4 libscorkscrew so在android 5 0之后已经没有了 xff0c 之
  • android backtrace实现

    前景 backtrace 文档 说明 通过数组获取调用栈 一般获取的是内存地址 借助dladdr获取地址信息 计算可执行文件中的偏移地址 实现 有的没有实现backtrace但是大多都支持unwind 利用unwind实现类似 backtr
  • c语言 backtrace

    c语言 backtrace 版权声明 xff1a 本文为CSDN博主 zhouyuming hbxt 的原创文章 xff0c 遵循CC 4 0 BY SA版权协议 xff0c 转载请附上原文出处链接及本声明 原文链接 xff1a https
  • Android打印调用堆栈(dump backtrace)的方法

    1 为什么要打印函数调用堆栈 xff1f 打印调用堆栈可以直接把问题发生时的函数调用关系打出来 xff0c 非常有利于理解函数调用关系 比如函数A可能被B C D调用 xff0c 如果只看代码 xff0c B C D谁调用A都有可能 xff
  • esp32 freertos backtrace问题定位

    log xff1a 17 42 41 320 收 TRAN OpenDataBusRequest ok TRAN Trans Srv Recv Data ret 0 TRAN TransDelSessionConnById channelI
  • 导轨回溯消音器不起作用,而过滤器起作用

    新的 Rails 4 2 设置 我想抑制长错误回溯 在下面的回溯日志中 第一行对我来说就足够了 接下来的 4 行可以删除 ActionController RoutingError No route matches GET user act
  • 从 SQL 查询到应用程序代码的回溯?

    有没有办法在 Rails 开发日志中找到哪一行代码生成了 MySQL 语句 为了进行一些性能优化 我想找到我的应用程序的哪个部分正在创建哪些 MySQL 查询 当我查看日志时 我看到我所做的每个网络请求上都会闪烁数百个查询 我需要找出它们来
  • Linux 上 backtrace() 的替代方案,可以查找静态函数的符号

    在手册页中 backtrace Linux 上的函数说 请注意 静态 函数的名称 没有暴露 并且在回溯中不可用 但是 启用调试符号后 g 像这样的程序addr2line and gdb仍然可以获得静态函数的名称 有没有办法从进程本身中以编程
  • Win32 - 从 C 代码回溯

    我目前正在寻找一种在 Windows 下从 C 代码 非 C 获取回溯信息的方法 我正在构建一个跨平台 C 库 具有引用计数内存管理功能 它还具有集成的内存调试器 可提供有关内存错误的信息 XEOS C 基础库 当发生故障时 启动调试器 提
  • 如何让 PHP 在出现错误时生成回溯?

    尝试使用 PHP 的默认仅当前行错误消息来调试 PHP 是可怕的 当产生错误时 如何让 PHP 产生回溯 堆栈跟踪 我的用于安装生成回溯的错误处理程序的脚本
  • 在每个 PHP 回溯级别获取范围内的变量?

    有没有办法在回溯中查看每个堆栈帧中设置的变量 我可以通过组合来非常接近debug backtrace true 来获取对象 get object vars在每个对象上获取 this vars args每个回溯帧中的键 以及get defin
  • 如何在内核模块代码中包含 C 回溯?

    所以我试图找出哪些内核进程正在调用块驱动程序中的某些函数 我认为在 C 库中包含 backtrace 会让事情变得容易 但我在加载回溯时遇到问题 我复制了这个示例函数来显示回溯 http www linuxjournal com files
  • x86_64 调用约定和堆栈帧

    我试图理解 GCC 4 4 3 为 Ubuntu Linux 下运行的 x86 64 机器生成的可执行代码 特别是 我不明白代码如何跟踪堆栈帧 过去 在 32 位代码中 我习惯于在几乎每个函数中看到这个 序言 push ebp movl e
  • ARM 平台上的 SIGABRT 信号没有回溯?

    我在用着 回溯 and backtrace symbols fd 信号处理程序中的函数 用于生成用于调试的回溯 GDB 不可用 它们在 x86 桌面 Ubuntu 上运行良好 但是在目标设备 基于 ARM 上 Abort 信号的回溯 由于双
  • 在 Linux 64 位上从信号处理程序进行回溯,并在调用堆栈上使用 malloc/free

    下面是我想在运行 Red Hat Enterprise Linux 5 5 Tikanga Kernel 2 6 18 194 el5xen x86 64 操作系统的计算机上使用的源示例 总体思路是 我想要某个线程的回溯 因此我为该线程发出
  • GDB无法显示堆栈并显示“#1 0x0000000000000000 in ?? ()”

    我有一个多线程 C 程序 在极少数情况下会死锁 这个问题很难重现 我只能在远程机器上重现它 我想用来解决这个问题的方法是 运行程序 等待死锁 向其发送中止信号以生成核心转储 将转储复制回我的本地计算机 使用gdb来调试它 我在远程计算机上没
  • 获取linux可执行文件加载地址(__builtin_return_address和addr2line)

    我正在编写一些代码来存储每个内存分配的回溯 然后 我将这些列表写入文件以进行离线分析 在win32中我使用 AddressOfReturnAddress然后手动创建回溯 由于我使用的每次运行的地址都是随机的GetModuleInformat
  • 有没有比使用 backtrace() 更便宜的方法来查找调用堆栈的深度?

    我的日志记录代码使用的返回值回溯 http linux die net man 3 backtrace确定当前堆栈深度 出于漂亮的打印目的 但我可以从分析中看到这是一个相当昂贵的调用 我不认为有更便宜的方法吗 请注意 我不关心帧地址 只关心
  • Ruby 解释器出现段错误后,是否可以从 corefile 中获取 Ruby 回溯?

    Note 我使用了在使用 libxml ruby gem 时遇到的段错误来说明问题 但我已经用所述 gem 解决了我的问题 这个问题真正涉及的是从 gdb 使用 corefile 查看 Ruby 回溯 即解释器在 Ruby 代码无法处理异常

随机推荐

  • 从头到尾彻底理解KMP(2014年8月22日版)

    从头到尾彻底理解KMP 作者 xff1a July 时间 xff1a 最初写于2011年12月 xff0c 2014年7月21日晚10点 全部删除重写成此文 xff0c 随后的半个多月不断反复改进 后收录于新书 编程之法 xff1a 面试和
  • 基于HAL的嵌入式学习(STM32F407)——点亮你的LED

    前言 本人通过自身的一些学习 xff0c 通过使用CubeMX来完成嵌入式学习过程中的硬件配置 xff0c 结合使用Keil5来进行程序编写 xff0c 进而完成对于工程目标的编程问题 硬件介绍 xff1a 本人使用的是一款芯片为STM32
  • Docker入门(二) - 容器内访问宿主机硬件资源

    https blog csdn net tianhuanqingyun article details 91580778 边缘设备而言 xff0c 在支持容器化运行的条件下 xff0c 需要在容器内获取宿主机的硬件资源 xff0c 完成与宿
  • jQuery使用prop属性全选与取消全选

    jQuery使用prop属性全选与取消全选 在使用jQuery开发全选或取消全选时 xff0c 用 attr 34 checked 34 获取 checkbox 的 checked属性时 如果是选中状态可以取到值 但是在未选中的时候获取值就
  • angularjs笔记

    基础概念 ng app 指令告诉 AngularJS xff0c 元素是 AngularJS 应用程序 的 34 所有者 34 ng model 指令把输入域的值绑定到应用程序变量 name ng bind 指令把应用程序变量 name 绑
  • virtualbox已有虚拟硬盘扩容(不修改原有数据)

    virtualbox为ubuntu添加虚拟硬盘 大概的步骤如下 xff1a 在virtualbox上注册一个虚拟硬盘使用fdisk对硬盘进行分区mkfs ext4格式化硬盘修改uuid VBoxManage internalcommands
  • react资源

    MUI The React UI library for faster and easier web development React Table Lightweight and extensible data tables for Re
  • gitbook之node版本问题

    执行gitbook build出现错误 xff0c 执行gitbook serve也是会出错 错误如下 xff1a gitbook build usr local lib node modules gitbook cli node modu
  • 结构体定义寄存器方法(很流行哦)

    ARM寄存器数量之多 xff0c 叹为观止 xff01 幸运的是 xff0c 它都是以模块分布 xff0c 再依托C语言的模块化编程 xff0c 用户就没有必要记忆那么多的寄存器名称了 xff01 拿LPC1114来说 xff0c 单片机内
  • Arduino Uno安装设备时,出现了一个错误,这个INF中的服务安装段落无效

    问题 xff1a 在windows系统下 xff0c Uno安装设备时 xff0c 出现了一个错误 xff0c 这个INF中的服务安装段落无效 原因 xff1a 缺少系统文件 解决方案 xff1a 1 先下载 xff1a usbser zi
  • Vmware Unity模式

    ubuntu 12 04 之Vmware Unity模式 安装VMware Toolsudo add apt repository ppa gnome3 team gnome3sudo apt get install gnome shell
  • 状态机实现的三种方法-C语言

    1 参考 xff1a https www cnblogs com aaronLinux p 5705457 html 2 转载 xff1a http kb cnblogs com page 528972 3 参考 xff1a FSM TCP
  • 代码函数调用关系图

    代码函数调用关系 Graphviz 43 CodeViz http www linuxidc com Linux 2015 01 111501 htmCallgraph xff1a 静态分析 C 程序函数调用关系图cflow 43 grap
  • 错误:try using -rpath or -rpath-link

    在使用到动态库的时候 xff0c 出现错误如下 xff1a arm linux bin span class hljs keyword ld span warning libssl span class hljs preprocessor
  • Nestjs框架安装与启动

    Nest是构建高效可扩展的 Node js Web 应用程序的框架 默认使用JavaScript的超集TypeScript进行开发 环境准备 查看node和npm版本 node version v10 11 0 npm version 6
  • Vcpkg安装指定版本包或自定义安装包

    文章目录 前言寻找版本安装后话 前言 windows一直用着vcpkg作为C 43 43 跨平台开发的包管理 xff0c 有些依赖要指定版本库 xff0c vcpkg目前最新的openssl版本是3 1 0 xff0c 我想安装其他版本为例
  • git push不用输入密码(方法一)-git-credentials

    install git credentials sh 命令步骤 xff1a touch git credentialsecho 34 http username password 64 localhost 34 gt gt git cred
  • PCIe 配置空间:Status 寄存器

    1 Status 寄存器位置 2 Status 寄存器细节 2 1 特殊位 对于 PCIe 设备 xff0c status 寄存器中有几个 bit 的值是固定的 Bit 4 xff1a Capability List xff0c 该位必须为
  • C语言:魔方阵-全(图解+代码+结果输出)

    目录 前言 一 奇数阶阵 xff08 n 61 2k 43 1 结果输出 xff1a 二 偶数阶阵 xff08 n 61 2k 一 四倍偶数阶阵 xff08 n 61 4k 结果输出 xff1a 二 非四倍偶数阶阵 xff08 n 61 4
  • c语言 backtrace

    c语言 backtrace 版权声明 xff1a 本文为CSDN博主 zhouyuming hbxt 的原创文章 xff0c 遵循CC 4 0 BY SA版权协议 xff0c 转载请附上原文出处链接及本声明 原文链接 xff1a https