indent

一、缘起

本以为有了 astyle 就能够搞定一切 C 语言文件格式美化问题。
却发现 astyle 无法将杂乱的函数定义变成想要的格式。也许是自己还没有找到正确的参数。
   之前看一本书,接触过 indent命令,但是没有深入研究,因为 astyle 已经先入为主。
但是这次因为遇到无法过去的坎,折腾了好几天。始终没有把任意形式的C函数定义格式变成同一行内定义。
又想不起来 indent,知道有,但是说不出名字。百度再次让它回到我的视野,而且一个基础的示例就解决了我的困扰。

二、安装

一般 centos7 都已经安装了

三、基础用法

1、解决我问题的示例

A、需求

对函数在多行定义的情况,将定义合并到一行内,无论此函数有多长,有多少个参数

B、示例源码

#include <stdio.h>
void fun1(int a,int b,intc)
{
printf("in fun1...\n");
}
void fun2(int a1,                  int b)

{
     printf("in fun2...\n");
}
void fun3(                  int a, int b                  )
{
     printf("in fun3...\n");

一个推荐的配置

indent -npro -nip -lp -npsl -i4 -ts4 -sob -l200 \
 -bl -bli0 -ppi 3 -cli4 -bls -cli4 -cbi0 -npcs\  fileName.c

guake

一、缘起

公司切换到linux云桌面。抛弃原来在win7下使用的系列工具。
    第一个工具就是终端,尽管系统自带terminal也能总凑和。但是总感觉有些不爽。度娘推荐了guake,试用一下,果然十分满意。

   但是linux下只有一款终端,是不够的,想多开几个窗口,不能只用这一种终端。
   于是继续搜索,发现有人推荐了一系列终端,先记下:https://www.cnblogs.com/jpfss/p/11106318.html
分别是:tilda / Yakuake / Guake / Sjterm / Terminator /
 ROXTerm / Eterm / Rxvt / Aterm / Wterm / TermkKit(基于webkit) / Terminology
  我又试用了 Terminology,感觉十分轻快舒适

二、找到 guake,试用效果很满意

1、安装

一键安装 :sudo yum -y instal guake

2、遇到问题

打开后,发现前缀很长,很丑。
修改 ~/.vimrc

在最后添加一行:
unset PROMPT_COMMAND

重新启动,果然没有了之前的乱码,777...,但是界面仍然不漂亮,
稍微定制一下,在unset上面加一句:
PS1="[Mr.Zhou \w]# "

3、terminology 试用,效果还行

首先是小巧,明显感觉到轻盈快速。
其次是每次启动时可以指定背景图片:
  terminology -b=pic.jpg
但是字体不配置的话,仍然是美中不足

其它同类产品

1、 tilda 也很好

当开启第一个 tilda 窗口时,可以用F1 调出/隐藏。
当开启第二个 tilda 窗口时,可以用F2 调出/隐藏
...

2、roxterm 感觉不错

感觉很朴实,实用,舒服

git

一、svn info 和 git 什么命令相对应

$git remote -v
origin https://github.com/Studio3T/robomogo.git (fetch)
origin https://github.com/Studio3T/robomogo.git (push)

$ git  log -1(是数字1,不是小L)
显示最后一次的入库详情

二、git切换到新分支

1、切换到基础分支,如主干

git checkout master

2、创建并切换分支

git checkout -b newBranch<br />git branch 命令此时可以看到,已经切换到了新分支 newBranch

3、更新分支代码并提交

git add *
git commit
git push  origin newBranch
git 强推
在android上搭建一个git 服务器,从笔记本强推:
git push --mirror ssh://wishcell@192.168.43.153:2222/fakegithub.git

另一种强推方式,向samba强推:
在windows访问samba的正确方式: \\192.168.1.99\user\data\prj.git

可是,当windows打开 git bash 时,却不能用这个路径强推,需要换个写法:
git push --mirror //192.168.1.99/user/data/prj.git
追加一句,强推之前,肯定需要在服务器先建立一个空的git 库: git init prj.git --bare
强推多个分支,因为一般git都有多个分支,首先用命令:
git branch -a 看看,有哪几个。
无意中发现竟然还有一个 all
$ git branch -a
*all
 master
 prjRelease
 plantFromSomeone

首先切换到all分支上,然后强推,推送过程会逐一打印 :
*[new branch] all->all
*[new branch] master->master
*[new branch] prjRelease->prjRelease
*[new branch] plantFromSomeone->plantFromSomeone

三、最基础应用,创建仓库,上传代码

git --bare init gitBack
vim .git/config
最后面,添加两行,否则 git push 报错:
[receive]
    denyCurrentBranch=ignore

gdb

一、看到别人文章写的好,忍不住抄袭过来,怕下次网址消失

https://www.jianshu.com/p/ed90aad9cb0a

二、内容

GDB初学者指南
Later_c44e
2019.04.22 15:02:59
字数 644阅读 461
从VS转gdb的人会觉得GDB比较难用,其实gdb使用熟练了比VS可能还方便。可以说不会gdb的人,没法真正懂Linux编程。
有正在学习C语言的朋友,可以进Q群121811911下载软件资料和视频,我们一起进步。
编译具有调试符号的程序
gcc编译时,带上-g选项才能产生具有调试符号的程序。才能供gdb进行有源码调试
$ gcc -g justtest.c
反汇编
disassemb命令是反汇编
(gdb) disassemble main
Dump of assembler code for function main: 0x000000000040057d <+0>: push %rbp 0x000000000040057e <+1>: mov %rsp,%rbp 0x0000000000400581 <+4>: sub $0x20,%rsp 0x0000000000400585 <+8>: mov %edi,-0x14(%rbp) 0x0000000000400588 <+11>: mov %rsi,-0x20(%rbp) 0x000000000040058c <+15>: movl $0x12345678,-0x4(%rbp) ... 0x00000000004005c6 <+73>: retq
End of assembler dump.
/r选项是反汇编时带上机器码
(gdb) disassemble /r main
Dump of assembler code for function main: 0x000000000040057d <+0>: 55 push %rbp 0x000000000040057e <+1>: 48 89 e5 mov %rsp,%rbp 0x0000000000400581 <+4>: 48 83 ec 20 sub $0x20,%rsp 0x0000000000400585 <+8>: 89 7d ec mov %edi,-0x14(%rbp) 0x0000000000400588 <+11>: 48 89 75 e0 mov %rsi,-0x20(%rbp)
... 0x00000000004005bb <+62>: e8 90 fe ff ff callq 0x400450 <write@plt> 0x00000000004005c0 <+67>: b8 00 00 00 00 mov $0x0,%eax 0x00000000004005c5 <+72>: c9 leaveq 0x00000000004005c6 <+73>: c3 retq
End of assembler dump.
/m选项是反汇编时带上源码(如果有的话)
(gdb) disassemble /m main
Dump of assembler code for function main:
4 { 0x000000000040057d <+0>: push %rbp 0x000000000040057e <+1>: mov %rsp,%rbp 0x0000000000400581 <+4>: sub $0x20,%rsp 0x0000000000400585 <+8>: mov %edi,-0x14(%rbp) 0x0000000000400588 <+11>: mov %rsi,-0x20(%rbp)
5 int nValue = 0x12345678; 0x000000000040058c <+15>: movl $0x12345678,-0x4(%rbp)
6 printf("%p:%08X\n", &nValue, nValue); 0x0000000000400593 <+22>: mov -0x4(%rbp),%edx 0x0000000000400596 <+25>: lea -0x4(%rbp),%rax 0x000000000040059a <+29>: mov %rax,%rsi 0x000000000040059d <+32>: mov $0x400654,%edi 0x00000000004005a2 <+37>: mov $0x0,%eax 0x00000000004005a7 <+42>: callq 0x400460 <printf@plt>
7 write(0, "hello,world\n", 13);
...
也可以两个选项一起用:
disassemble /rm main
设置反汇编的风格
反汇编的语法默认是GNU风格的,可以使用命令设置为Intel风格
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main: 0x000000000040057d <+0>: push rbp 0x000000000040057e <+1>: mov rbp,rsp 0x0000000000400581 <+4>: sub rsp,0x20 0x0000000000400585 <+8>: mov DWORD PTR [rbp-0x14],edi 0x0000000000400588 <+11>: mov QWORD PTR [rbp-0x20],rsi 0x000000000040058c <+15>: mov DWORD PTR [rbp-0x4],0x12345678 ... 0x00000000004005c5 <+72>: leave 0x00000000004005c6 <+73>: ret
End of assembler dump.
单步调试
next:单步步过
step:单步步入
以上是源码级别的单步。如果是汇编级别的单步,则使用:
nexti/stepi(两者效果一样)
自动显示反汇编代码
如果gdb匹配了源文件,则即使使用stepi,那么自动回显的内容依然是源码级别的,需要手动敲disassemble来查看当前汇编内容,很不方便。这时,可以通过display命令达到自动回显的目的:
(gdb) help display
Print value of expression EXP each time the program stops.
/FMT may be used before EXP as in the "print" command.
/FMT "i" or "s" or including a size-letter is allowed,
as in the "x" command, and then EXP is used to get the address to examine
and examining is done as in the "x" command.
With no argument, display all currently requested auto-display expressions.
Use "undisplay" to cancel display requests previously made.
可知,display命令是在每次调试器断下来后,自动显示某个表达式。
我们通过命令:
display /5i $pc
然后每次停下,就会显示对应的反汇编了:
(gdb) stepi
6 printf("%p:%08X\n", &nValue, nValue);
6: x/5i $pc
=> 0x400593 <main+22>: mov -0x4(%rbp),%edx 0x400596 <main+25>: lea -0x4(%rbp),%rax 0x40059a <main+29>: mov %rax,%rsi 0x40059d <main+32>: mov $0x400654,%edi 0x4005a2 <main+37>: mov $0x0,%eax
普通断点
通过breakpoint命令下断点。breakpoint之后可接源文件行、函数名称、地址。如:
(gdb) break main
Note: breakpoint 1 also set at pc 0x40058c.
Breakpoint 3 at 0x40058c: file justtest.c, line 5.
(gdb) break 8
Breakpoint 4 at 0x4005c0: file justtest.c, line 8.
(gdb) break 0x4005c0
Note: breakpoint 4 also set at pc 0x4005c0.
Breakpoint 5 at 0x4005c0: file justtest.c, line 8.
可以使用info命令查看断点信息:
(gdb) info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x000000000040058c in main at justtest.c:5
2 breakpoint keep y 0x0000000000400593 in main at justtest.c:6
3 breakpoint keep y 0x00000000004005c0 in main at justtest.c:8
通过delete命令,可以删除指定编号的断点。
(gdb) delete breakpoints 1
也可以通过disable/enable来暂定或启用断点。
(gdb) disable breakpoints 1
内存断点
watch命令是下内存写断点:
watch ($rbp-4)
类似的,还有内存读断点rwatch,与内存访问断点(读与写)awatch命令。
查看表达式及内存寄存器等
命令查看内存
x命令(examine)命令可以用于查看内存。
(gdb) help x
Examine memory: x/FMT ADDRESS.
ADDRESS is an expression for the memory address to examine.
FMT is a repeat count followed by a format letter and a size letter.
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal), t(binary), f(float), a(address), i(instruction), c(char), s(string) and z(hex, zero padded on the left).
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
The specified number of objects of the specified size are printed
according to the format.
如,以字节为单位,以16进制显示,查看4单位&nValue地址处的数据:
(gdb) x /4xb &nValue
0x7fffffffdf3c: 0x78 0x56 0x34 0x12
以10进制查看:
(gdb) x /4db &nValue
0x7fffffffdf3c: 120 86 52 18
按照float解释数据:
(gdb) x /1fw &nValue
0x7fffffffdf3c: 5.69045661e-28
按照double解释数据:
(gdb) x /1fg &nValue
0x7fffffffdf3c: 1.5089747817000635e-315
查看寄存器
(gdb) info registers
修改内存值
使用set命令
set *(type)=newValue
如:
(gdb) set (int)0x7fffffffdf38=0x40490fda
有正在学习C语言的朋友,可以进Q群121811911下载软件资料和视频,我们一起进步。

三、在windows下进行反汇编研究

https://www.cnblogs.com/amanlikethis/p/3570832.html

四、gdb查看反汇编代码,返回值存放在哪里

如果是指针,一般有些话在$rax或者$eax里面。
但是我在自己跟踪的时候为什么没有发现?难道漏掉了?
问别人,一验证,果然如此!

但是如果是其它常数呢?存放在哪个寄存器?

多线程调试之痛,以及解决之道

1、文章来源

https://www.cnblogs.com/frankbadpot/archive/2010/06/23/1762916.html

2、多线程调试之痛

调试器(如VS2008和老版GDB)往往只支持all-stop模式,调试多线程程序时,如果某个线程断在一个断点上,你的调试器会让整个程序freeze,直到你continue这个线程,程序中的其他线程才会继续运行。这个限制使得被调试的程序不能够像真实环境中那样运行--当某个线程断在一个断点上,让其他线程并行运行。
GDBv7.0引入的non-stop模式使得这个问题迎刃而解。在这个模式下,
    当某个或多个线程断在一个断点上,其他线程仍会并行运行
    你可以选择某个被断的线程,并让它继续运行
让我们想象一下,有了这个功能后
    当其他线程断在断点上时,程序里的定时器线程可以正常的运行了,从而避免不必要得超时 
    当其他线程断在断点上时,程序里的watchdog线程可以正常的运行了,从而避免嵌入式硬件以为系统崩溃而重启
    可以控制多个线程运行的顺序,从而重现deadlock场景了。由于GDB可以用python脚本驱动调试,理论上可以对程序在不同的线程运行顺序下进行自动化测试。

因此,non-stop模式理所当然成为多线程调试“必杀技”。这2009年下半年之后发布的Linux版本里都带有GDBv7.0之后的版本。很好奇,不知道VS2010里是不是也支持类似的调试模式了。

3、演示项目

A、源码

// gdb non-stop mode demo
// build instruction: g++ -g -o nonstop nonstop.cpp -lboost_thread

#include <iostream>
#include <boost/thread/thread.hpp>

struct op
{
        op(int id): m_id(id) {}
        void operator()()
        {
                std::cout << m_id << " begin" << std::endl;
                std::cout << m_id << " end" << std::endl;
        }
        int m_id;
};
int main(int argc, char ** argv)
{
        boost::thread t1(op(1)), t2(op(2)), t3(op(3));
        t1.join(); t2.join(); t3.join();
        return 0;
}

B. 把一下3行添加到~/.gdbinit来打开non-stop模式

set target-async 1
set pagination off
set non-stop on

C. 启动gdb,设断点,运行.可以看到主线程1是running,3个子线程都断在断点上,而不是只有一个子线程断在断点上.

~/devroot/nonstop$ gdb ./nonstop
GNU gdb (GDB) 7.0-ubuntu
Reading symbols from /home/frankwu/devroot/nonstop/nonstop...done.
(gdb) break 14
Breakpoint 1 at 0x402058: file nonstop.cpp, line 14.
(gdb) break 24
Breakpoint 3 at 0x401805: file nonstop.cpp, line 24.
(gdb) run
Starting program: /home/frankwu/devroot/nonstop/nonstop
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff6c89910 (LWP 2762)]
[New Thread 0x7ffff6488910 (LWP 2763)]
1 begin
Breakpoint 1, op::operator() (this=0x605118) at nonstop.cpp:14
14                  std::cout << m_id << " end" << std::endl;
2 begin
Breakpoint 1, op::operator() (this=0x605388) at nonstop.cpp:14
14                  std::cout << m_id << " end" << std::endl;
[New Thread 0x7ffff5c87910 (LWP 2764)]
3 begin
Breakpoint 1, op::operator() (this=0x605618) at nonstop.cpp:14
14                  std::cout << m_id << " end" << std::endl;
(gdb) info threads
  4 Thread 0x7ffff5c87910 (LWP 2764)  op::operator() (this=0x605618) at nonstop.cpp:14
  3 Thread 0x7ffff6488910 (LWP 2763)  op::operator() (this=0x605388) at nonstop.cpp:14
  2 Thread 0x7ffff6c89910 (LWP 2762)  op::operator() (this=0x605118) at nonstop.cpp:14
* 1 Thread 0x7ffff7fe3710 (LWP 2759)  (running)

D、 让线程3继续运行,注意我顾意把主线程1也continue,这是我发现的workaround,否则gdb不能切回thread 1.

(gdb) thread apply 3 1 continue

Thread 3 (Thread 0x7ffff6488910 (LWP 2763)):
Continuing.

Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
2 end
[Thread 0x7ffff6488910 (LWP 2763) exited]

warning: Unknown thread 3.

Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
(gdb) info threads
  4 Thread 0x7ffff5c87910 (LWP 2764)  op::operator() (this=0x605618) at nonstop.cpp:14
  2 Thread 0x7ffff6c89910 (LWP 2762)  op::operator() (this=0x605118) at nonstop.cpp:14
* 1 Thread 0x7ffff7fe3710 (LWP 2759)  (running)

E、 让另外两个线程继续运行而结束,主线程断在第24行,最后结束.

(gdb) thread apply 4 2 1 continue

Thread 4 (Thread 0x7ffff5c87910 (LWP 2764)):
Continuing.

Thread 2 (Thread 0x7ffff6c89910 (LWP 2762)):
Continuing.

Thread 1 (Thread 0x7ffff7fe3710 (LW命令P 2759)):
Continuing.
Cannot execute this command while the selected thread is running.
3 end
1 end
[Thread 0x7ffff5c87910 (LWP 2764) exited]
[Thread 0x7ffff6c89910 (LWP 2762) exited]

Breakpoint 3, main (argc=1, argv=0x7fffffffe348) at nonstop.cpp:24
24          return 0;

(gdb) continue
Thread 1 (Thread 0x7ffff7fe3710 (LWP 2759)):
Continuing.

Program exited normally.

设置 GDB 工程代码,在其它机器上调试时尤其重要

1、dir 命令,添加一个搜索路径

(gdb) dir source_dir/

2、set substitute-dir命令

set substitute-path from_path  to_path

3、list命令

l 为 list 的缩写
查看30~90行之间的代码: l 30,90

4、总结

在gdb里面查看源码,
list 一下提醒找不到相关文件,列出来的是绝对路径的完整文件名。
help files   看一下帮助,可以加载符号,源文件等,自己看一下。
dir 设置源码路径无效,show directories  看到设置成功,但是还是找不到文件。
应该是绝对路径的问题。
因为igcc 根据你编译的时候指定的是绝对路径还是  ../../XXX.cpp之类的相对路径,在生成debug_info的时候,也把这个路径保存为debug_info 里面的文件名字,就是最后 gdb list 里面找到的文件名字。
这个可以list  查看是不是绝对路径,然后可以用命令
 readelf -p .debug_str  exe_or_so_file 
看到里面保存是是完整的绝对路径。
gdb 的dir 命令添加的源码搜索路径只对相对路径的情况有效。
一个解决办法就是在gcc的时候,使用相对路径那么gdb里面你就可以使用 dir来设置了。像些CMake之类的,它喜欢使用绝对路径,有人可以写个脚本让它使用相对路径,参考  http://stackoverflow.com/questions/9607155/make-gcc-put-relative-filenames-in-debug-information
如果gcc里面-g  生成的debug_info 使用的绝对路径了,最简单的办法就是你把源码也放到相应的位置上去了。
但如果你不想使用这个绝对路径,那也还是有办法的。 
GDB还提供另外一个选择,可以让你修改源码搜索路径,把源码绝对路径里面的一个path映射到另一个path上去,这样即使你debug info了里面的是绝对路径,源码也可以放到另外的目录。
这就是命令
set substitute-path from_path  to_path
比如 list显示的源码是   /home/aaa/1.cpp
那么设置了  set substitute-path /home/aaa/   /home/bbb/

之后,即使你的源文件1.cpp 放在 /home/bbb下面也是可以找到的了。因为gdb帮你做了字符串替换

gcov_lcov

一、报错lcov和gcov的使用错误

编译使用的gcc版本和gcov的版本对不上的话,使用lcov和gcov的时候会报错

lcov的错误:
[xx@localhost XXX]$ lcov --capture --directory cov --output-file xxx.info --test-name xxx
Capturing coverage data from cov
Found gcov version: 4.8.5
Scanning cov for .gcda files ...
Found 35 data files in cov
Processing XXX.gcda
geninfo: ERROR: XXX.gcno: reached unexpected end of file

gcov的错误:
[xxx@localhost xxx]$ gcov -o cov ./xxx.c
cov/xxx.gcno:版本‘405 ’,首选‘408R’

gcov: out of memory allocating 16030351984 bytes after a total of 135168 bytes

确保gcc和gcov版本一样即可

按照上面说的方法实践,果然搞定
查看了一下:
  gcc -v : 4.4.7
  g++ -v  : 4.4.7
   gcov -v :4.4.7
    lcov -v :1.10

然后将lcov 版本升级到 1.12,问题搞定

通用代码的覆盖率问题

1、问题描述

公共代码在项目A中被覆盖 30,在项目 B 中覆盖另外 70,怎样`才能统计出 100% 的覆盖效果?

2、实验代码

[zhoujinhua@ecs-b0b7 tmp]$ cat common.c
#include <stdio.h>

int myAdd(int a, int b)
{
    return a+b;
}
int mySub(int a, int b)
{
    return a - b;
}

[zhoujinhua@ecs-b0b7 tmp]$ cat good.c
    #include <stdio.h>
    #include <execinfo.h>
    #include <stdlib.h>

    extern int myAdd(int a, int b);
    void print_call_stack()
    {
        int    i          = 0;
        int    size       =32;
        void  *array[32];
        int    stack_num  = backtrace(array, size);
        char **stacktrace = (char**)backtrace_symbols(array, stack_num);
        for (i=0; i<stack_num; i++)
        {
            printf("func_%d addr:%s\n", i, stacktrace[i]);
        }
        free(stacktrace);
        return;
    }
    void func_1(){print_call_stack();}
    void func_2(){func_1();}
    void func_3(){func_2();}
    void func_4(){func_3();}
    void func_5(){func_4();}
    void func_6(){func_5();}
    int main(int argc, char **argv)
    {
        myAdd(3,4);
        printf("argc = %d\n", argc);
        if (argc < 2)
        {
            printf("please use at least one parameter!\n");
            return 1;
        }
        func_6();
        return 0;
    }
[zhoujinhua@ecs-b0b7 tmp]$ cat better.c
#include <stdio.h>
extern int mySub(int a,int b);
int main()
{
    return mySub(9, 2);
}
[zhoujinhua@ecs-b0b7 tmp]$

3、实验操作步骤

1、编译第一个项目

gcc -g3 -fprofile-arcs -ftest-coverage good.c common.c -o dir1/good

2、运行第一个项目,产生覆盖率数据

./dir1/good

3、将中间文件放入第一个目录

mv *.gcda ./dir1/
  mv *.gcna ./dir1/
  mv *.gcov ./dir1/

4、编译第二个项目,同样的操作步骤

gcc -g3 -fprofile-arcs -ftest-coverage better.c common.c -o dir2/better

5、当前目录下的所有覆盖文件进行统计

lcov -d ./ -c -o ./prj_dir/my_prj.info -t 'prj_title' -b ./
  说明:-d ./ 表示当前目录下的所有

6、最终生成漂亮的覆盖率网页

genhtml -o prj_dir/ prj_dir/my_prj.info

7、网页查看,不用浏览器,直接在 linux 命令行就能查看,TAB切换、跳转

yum -y install w3m w3m-image
   w3m ./prj_dir/index.html

在某些大型项目中,无法随意修改编译、链接参数,怎样实现stacktrace
当编译、链接参数无法正确✔️配置时,尽管如下函数可以运行,但是结果缺不是预想那样
void print_call_stack()
{
    int    i          = 0;
    int    size       =32;
    void  *array[32];
    int    stack_num  = backtrace(array, size);
    char **stacktrace = (char**)backtrace_symbols(array, stack_num);
    for (i=0; i<stack_num; i++)
    {
        printf("func_%d addr:%s\n", i, stacktrace[i]);
    }
    free(stacktrace);
    return;
}

stacktrace[i] 并没有被转换成函数名,仍然是栈中十六进制数的样子。

此时只能自己实现转换。
通过观察发现,array[1],就是上一层函数中的某个地址,一般是函数名离开偏移地址。
如果上层函数是func,责array[1]的值是 func + offset.
可以通过简单的条件判断:
if ((array[1]>func) && ((array[1]-func)<1024)) //限定偏移范围,可以调整
{
    return true;
}

但是实际编译是,编译器会报错,提示void*类型不能和函数类型进行减法操作。
需要做一次转换,将两个值都转化为word32:

typedef word32 unsinged int
typedef void (*entryFuncType)()
typedef struct
{
    eFuncIdx      idx;
    entryFuncType func;
}funcMapType;
funcMapType map[]=
{
    {eIdx_1,  func_1},
    {eIdx_2,  func_2},
};
BOOL isInFunction(void *stackPos, entryFuncType func)
{
    bool ret = false;
    int  offset=0;
    char buf_1[32] = {0};
    char buf_2[32] = {0};
    word32 stackPosVal=0;
    word32 funcVal=0;
    sprintf(buf_1, "0x%x",stackPos);
    sprintf(buf_2, "0x%x",func);
    sscanf(buf_1, "%x", &stackPosVal);
    sscanf(buf_2, "%x", &funcVal);
    offset=stackPosVal - funcVal;
    if ((0<offset) && (offset<1024))
    {
        ret = true;
    }
    return ret;
}

void print_call_stack()
{
    int    i          = 0;
    int    size       =32;
    void  *array[32];
    int    stack_num  = backtrace(array, size);
    char **stacktrace = (char**)backtrace_symbols(array, stack_num);

    //这个简单的判断,可以替换成一个循环
    if(isInFunction(array[1], myFunction))
    {
        //do something....
    }
    free(stacktrace);
    return;
}

ftp

一、ftp数据一键传输

1、第一种办法

curl -u -uUser:Pwd 192.168.1.2/* -O

open 192.168.1.2
User
Pwd
mget *
quit
----------------------oneKeyScript.sh------------
用法:ftp -i -s:oneKeyScript.sh
缺陷:
1、此方法在windows下可以工作,但是在linux终端报错,不知道什么原因
2、遇到乱码时,报错退出

2、第二种办法,关掉交互提示

ftp> prompt off
interactive mode off
ftp> ls -lrt
ftp> mget *

似乎没有遇到什么缺陷,在 linux 下可以将全部文件拉到本地,
尽管有一部分乱码

二、FTP数据传输中乱码问题

1、根本原因

从服务器下载大量文件。
发现一部分数据是 GBK/GB2312中文编码,在windows下可以正常显示,但是在编码为 zh_CN.UTF-8 的窗口下,显示为乱码。

另一部分编码为utf-8的文件,显示效果相反

可以临时改变终端的编码格式:
export LANG=zh_CN.UTF-8 ==>>
export LANG=zh_CN.GB18030
GB18030包含了GBK和GB2312

2、意外收获解决办法

利用mobaxterm,竟然可以将终端中正常显示,而windows窗口显示乱码的文件,拉取到windows中然后自动转换格式,拉完之后还是可以正常显示

everything

一、同类文档管理

1、step-1,准备好文件,必须按规则命名

15900@DESKTOP-CGPRCF3 MINGW64 /d/tmp/工作安排
    $ ls -l | awk '{print $NF}'
    员工1_项目1_来源A_开始20240102_状态完成.xls
    员工1_项目2_来源A_开始20240102_状态进行中.xls

2、step-2,准备好文件,必须按规则命名

打开everything.
输入:员工1,查看结果
没有结果...
搜索- 高级搜索 - 必含单词(第一个) - 全子匹配 - 去掉勾选 - 确定
回到搜索界面,看到员工1所有文档。
删除条件,改为:员工1  完成
搜索结果再次为空。
搜索- 高级搜索 - 必含单词(第一个) - 全子匹配 - 去掉勾选 - 确定
回到搜索界面。看到员工1状态完成的一个文档

css

一、例一,利用纯css实现菜单效果

1、来源及技术要点,原理

心血来潮,想到csdn上看看技术直播,随便一看,果然不虚此行。
一位老兄讲解的纯 css 实现页面效果,在几天前我做了一个任务,
花好多心思,好长时间也没搞定,效果很勉强,这位老兄15分钟,讲的清清楚楚。

主要是利用 html 的页内链接,以及 <div>限定区域外,内容不显示的原理

直接链接:
https://live.csdn.net/v/27147?utm_medium=distribute.pc_video_shortvideo.none-task-short_video-csdn#pc_video_shortvideo#short_video#27147-8.nonecase&depth_1-utm_source=distribute.pc_video_shortvideo.none-task-short_video-csdn#pc_video_shortvideo#short_video#27147-8.nonecase&

2、先上html 代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset='UTF-8' />
        <title>纯CSS实现点击切换效果</title>
        <link rel='stylesheet' type='text/css' href='./page1.css' />
    </head>
    <body>
        <div class='A'>
            <div class='title'>
                <a href='#list1'>按钮1</a>
                <a href='#list2'>按钮2</a>
                <a href='#list3'>按钮3</a>
            </div>
            <div class='content'>
                <div id='list1'>内容1</div>
                <div id='list2'>内容2</div>
                <div id='list3'>内容3</div>
            </div>
        </div>
    </body>
</html>

3、css代码

/*用星号去掉浏览器默认的外边距和内边距 */
*{
    margin:0;
    padding:0;
}
/* 对class=‘A’的 div 进行配置 */
div.A{
    width:750px;
    height:550px;
    background-color:#aaa;
    margin:0 auto;
}

/*对class='A'的div, 它里面 class='title' 的 div 进行配置*/
div.A div.title{
    width:750px;
    height:50px;
    background-color:purple;
}
/* 对 title 中的所有链接类型<a>进行设置 */
div.A div.title a{
    display:block; /* 将其设置为block类型,然后才能为其设置宽高 */
    width:200px;
    height:40px;
    float:left;
    background-color:#fff;
    margin: 5px 0 0 35px;
    text-align:center; /* 字体左右对齐 */
    line-height:40px;  /* 字体上下对齐,不能用center */
}

/*对class='A'的div, 它里面 class='content' 的 div 进行配置*/
div.A div.content{
    width:750px;
    height:500px;
    background-color:#bbb;
    overflow:hidden; /*对超出div范围的内容,不作显示*/
}
div.A div.content div#list1{
    width:100%;
    height:100%;
    font-size:50px;
    text-align:center;
    line-height:500px;
    background-color:red;
}
div.A div.content div#list2{
    width:100%;
    height:100%;
    font-size:50px;
    text-align:center;
    line-height:500px;
    background-color:green;
}
div.A div.content div#list3{
    width:100%;
    height:100%;
    font-size:50px;
    text-align:center;
    line-height:500px;
    background-color:blue;
}

w3cschool.cn/css/css-sfrk2opy.html

很多网站是全背景图片的,而且适应各种主流分辨率,给人一种干净大气的感觉,实属设计派的一个耍酷良方,下面介绍几种实现全屏图片自适应缩放背景图片的方法。

1.帅气简单的CSS3方法

html {
background: url(images/bg.jpg) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
Safari 3+
Chrome Whatever+
IE 9+
Opera 10+
Firefox 3.6+

2.只使用CSS之方法一

img.bg {
min-height: 100%;
min-width: 1024px;
width: 100%;
height: auto;
position: fixed;
top: 0;
left: 0;
}
@media screen and (max-width: 1024px) {
img.bg {
left: 50%;
margin-left: -512px;
}
}

以下浏览器的任何版本: Safari / Chrome / Opera / Firefox
IE 6: (各种方案奈我何?!)
IE 7/8: 大部分工作,小屏幕的时候全屏,但是不是居中
IE 9: 没问题

3.只使用CSS之方法二

#bg {
position:fixed;
top:-50%;
left:-50%;
width:200%;
height:200%;
}
#bg img {
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
margin:auto;
min-width:50%;
min-height:50%;
}
Safari / Chrome / Firefox
IE 8+
Opera

4.jQuery方法

#bg { position: fixed; top: 0; left: 0; }
.bgwidth { width: 100%; }
.bgheight { height: 100%; }
(window).load(function() { var theWindow = (window),
bg = ("#bg"),
aspectRatio = bg.width()/bg.height();
function resizeBg() {
if ( (theWindow.width()/theWindow.height()) bg .removeClass() .addClass('bgheight'); }else{ bg
.removeClass()
.addClass('bgwidth');
}
}
theWindow.resize(function() {
resizeBg();
}).trigger("resize");
});

IE7+
任何除了IE的浏览器的任何版本