backtrace堆栈调用追踪函数


函数说明:

#include <execinfo.h>
/*
 * 功能描述: 获取当前堆栈地址
 * 参数说明: buffer - 函数地址数组(传出)
 *          size   - 数组的最大长度 
 * 返 回 值:实际调用的层数
 */
int backtrace(void **buffer, int size);    

/*
 * 功能描述: 将地址转换成符号字符串数组
 * 参数说明: buffer - 函数地址数组
 *          size   - 有效地址的个数 
 * 返 回 值: 符号字符串数组指针(需要调用者释放)
 */
char **backtrace_symbols(void *const *buffer, int size);
   
/*
 * 功能描述: 将地址转换成符号字符串数组并写入指定文件
 * 参数说明: buffer - 函数地址数组
 *          size   - 有效地址的个数 
 *          fd     - 文件描述符
 * 返 回 值: 无
 */
void backtrace_symbols_fd(void *const *buffer, int size, int fd);

Linux例程:

#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<string.h>
#include<execinfo.h>
/*
 * 内存访问异常回调函数
 */
void segv_handle(int signum)
{
  int i;  
  size_t size;  
  int maxlen = 1024;     // 堆栈最大值  
  void *func[len];
  char **funs;  

  // 获取堆栈调用层数
  size = backtrace(func, maxlen);

  // 获取符号
  funs = (char **)backtrace_symbols(func, size);    
  // 打印输入相关信息
  fprintf(stderr, "Stack trace:\r\n");
  for (i = 0; i < size; i++)
  {
    fprintf(stderr, "%d %s \r\n", i, funs[i]);
  }        
  free(funs); // 释放动态申请的内存

  exit(1);    
}

//-------------------------------------------------
void func2nd()
{
  char *p=NULL;
  *p = 'A';        // 制造内存访问异常
}

void func1st()
{
  func2nd();
}

int main(const int argc,const char* argv[])
{
  // 无效内存异常信号捕获,SegmentationViolation
  signal(SIGSEGV, segv_handle);
  func1st(); 
  return 0;
}

编译选项:

gcc -o BackTrace BackTrace.c -rdynamic

运行结果:

Stack trace:
0 ./BackTrace(segv_handle+0x54) [0x804882f] 
1 linux-gate.so.1(__kernel_sigreturn+0) [0xb77a9d1c] 
2 ./BackTrace(func2nd+0x10) [0x80488c7] 
3 ./BackTrace(func1st+0x8) [0x80488d4] 
4 ./BackTrace(main+0x28) [0x80488fe] 
5 /lib/i386-linux-gnu/i686/cmov/libc.so.6(__libc_start_main+0xf3) [0xb75f8a63] 
6 ./BackTrace() [0x8048701] 

-rdynamic 生成符号表,否则只有地址:

Stack trace:
0 ./BackTrace() [0x80485bf] 
1 linux-gate.so.1(__kernel_sigreturn+0) [0xb77ccd1c] 
2 ./BackTrace() [0x8048657] 
3 ./BackTrace() [0x8048664] 
4 ./BackTrace() [0x804868e] 
5 /lib/i386-linux-gnu/i686/cmov/libc.so.6(__libc_start_main+0xf3) [0xb761ba63] 
6 ./BackTrace() [0x8048491] 

需要采用addr2line命令来逐个查看:

# addr2line  -e BackTrace -f 0x8048657
func2nd
??:?

- 阅读全文 -

vmware问题及解决方案


挂载hgfs共享文件时提示:

Error: cannot mount filesystem: Input/output error

解决方案:
将虚拟机挂起,再恢复运行即可。


系统启动时提示:

A start job is running for LSB: VMware Tools Service

解决方案:
执行vmware-config-tools.pl命令

Would you like to enable VMware automatic kernel modules? 
选择[no]

hgfs共享文件修改不同步:
vmware tools 9.6.1的问题,更换个9.6.0的版本即可。

- 阅读全文 -

Linux应用笔记--时间


文章摘要:
本文介绍了linux操作系统关于时间的处理命令及应用程序中对系统时间的操作。


系统命令:

查看当前时间日期:

# date
2019年 06月 14日 星期五 10:28:38 CST

设置时间日期:
日期和时间之间有空格,所以要用引号括起来:

# date -s '2018-05-12 10:30:00'
2018年 05月 12日 星期五 10:30:00 CST

# date -s '18-05-12 10:30:00'
2018年 05月 12日 星期五 10:30:00 CST

# date -s '05/12/08 10:30:00'
2018年 05月 12日 星期五 10:30:00 CST
# date -s 2019-06-14
2019年 06月 14日 星期五 00:00:00 CST
# date -s 10:30:00
2019年 06月 14日 星期五 10:30:00 CST

1.日期格式: 月/日/年 或者 年-月-日;
2.只有日期无时分秒时,时分秒值为0;
3.只有时分秒无日期时,保持当前日期不变。


查看硬件时钟(RTC):

$ hwclock
2019年06月14日 星期五 14时42分06秒  -0.776878 seconds

修改硬件时钟(RTC):

# hwclock --set --date="06/12/19 14:55:00" 

硬件时钟同步至系统时钟:

# hwclock --hctosys

系统时钟同步至硬件时钟:

# hwclock --systohc

时区设置:
在/usr/share/zoneinfo/目录下找到对应的时区文件复制到/etc/localtime即可。


应用程序编程:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <stdint.h>
    
int main(int argc, char **argv)
{
  int ret;
  struct timeval tv;
  struct timezone tz;
  struct tm *ptm;
  struct tm stime;
  time_t t;

  //--------- 获取自1970年以来的秒数(UNIX时间戳)
  t = time(NULL);
  printf("time() = %d\r\n", t);
  //--------- 获取自1970年以来的秒数,微秒,时区
  gettimeofday(&tv, &tz);     // Linux不能获取时区值(时区参数可用NULL)
  printf("%d.%d\r\n", tv.tv_sec, tv.tv_usec);
  //------ 将timeval格式时间转换为年月日格式(格林尼治时间)
  ptm = gmtime(&tv.tv_sec);
  printf("%d-%02d-%02d %02d:%02d:%02d\r\n",
         ptm->tm_year + 1900, // 年 - 自1900来以来的年数
         ptm->tm_mon,         // 月 - {0,11},需要加1换算
         ptm->tm_mday,        // 日 - {0,31}
         ptm->tm_hour,        // 时 — {0,23}
         ptm->tm_min,         // 分 - {0,59}
         ptm->tm_sec);        // 秒 - {0,59}
  //------ 将timeval格式时间转换为年月日格式(本地时间)
  ptm = localtime(&tv.tv_sec);
  printf("%d-%02d-%02d %02d:%02d:%02d\r\n",
         ptm->tm_year + 1900, // 年 - 自1900来以来的年数
         ptm->tm_mon,         // 月 - {0,11},需要加1换算
         ptm->tm_mday,        // 日 - {0,31}
         ptm->tm_hour,        // 时 — {0,23}
         ptm->tm_min,         // 分 - {0,59}
         ptm->tm_sec);        // 秒 - {0,59}

  // 设置时间 ---------------------------------------
  stime.tm_year = 2019 - 1900;
  stime.tm_mon  = 5 - 1;
  stime.tm_mday = 12;
  stime.tm_hour = 01;
  stime.tm_min  = 02;
  stime.tm_sec  = 03;
  
  tv.tv_sec  = mktime(&stime); // 将年月日格式转化成unix时间戳
  tv.tv_usec = 0;

  ret = settimeofday(&tv, &tz); // 设置时间
  printf("ret = %d\r\n", ret);  // 成功返回0,其他值表示失败

  // 从实时时钟获取nS级时间(hwclock)----------------  
  struct timespec ts; 
  clock_gettime(CLOCK_REALTIME, &ts);
  printf("%d.%d\r\n", ts.tv_sec, ts.tv_nsec);

  return 0;
}

- 阅读全文 -

Linux文件系统--ramdisk应用


1.文件打包

#!/bin/sh

rm -f uInitrd

# 文件打包
cd rootfs    
find . | cpio --quiet -R 0:0 -o -H newc | gzip > ../myInitrd

# 添加uboot需要的64字节文件头
cd ../  
mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n initramfs -d myInitrd uInitrd

rm -f myInitrd

2.从initrd文件中恢复

#!/bin/sh

# 首先去除uboot的64字节文件头
sudo dd if=uInitrd of=initrd.gz bs=1 skip=64

# 解压文件(注意:gunzip解压对文件扩展名有要求)
gunzip initrd.gz

# 展开文件
cd rootfs
cpio -i -F ../initrd.gz

- 阅读全文 -

C++ Builder 皮肤安装与使用


安装皮肤:

  1. 首先下载VclSkin软件包,并解压在安装目录下(建议:为了保证应用程序在不同计算机上路径的兼容性);
  2. 运行CB6目录下的WinSkinC6安装包;
  3. 执行Compile(编译)、Install(安装)命令.

应用

  1. 新建工程

  2. 设置文件路径

    Project-->Options-->Directories/Conditionals
    Include path: 添加 $(BCB)\vclskin\CB6
    Library path: 添加 $(BCB)\vclskin\CB6

  3. 在窗体中添加SkinData控件和SkinCaption控件

- 阅读全文 -


Copyright©2019 春天花会开, All Rights Reserved. Email: webmaster@oroct.com