################################################################################

pstack学习笔记

v0.1 2013.10.8 ***

简介:pstack的功能是显示当前进程中函数的调用栈的关系,若是多线程的情况下,会显示各个
            线程中函数调用的关系。
            脚本用了gdb中的bt(backtrace)功能,在gdb中输入bt即可打印出程序当前的栈中
            的函数调用关系。

使用方法:pstack pid, 就是说要先把程序跑起来,查见进程号,再使用pstack pid

1.  在ubunbu系统上,使用 sudo apt-get install pstack可以直接安装pstack,注意这里
     安装上的是二进制的程序。之前对这样安装上的pstack作了测试,无法显示函数的调用
     关系。根据man pstack的说明,现在的pstack只支持32bit ELF binaries

2. 网上的一些文章指出,pstack只是一个脚本程序,在相关网站上下载了pstack.sh脚本
    测试。使用时总是提示出错,但是表现看不出来错误,全部删去,就留下前几行,还是
    显示有错,新建一个脚本文件,照抄那几行过来(这时两个文件看起来一样),但是用
    diff ***.sh ***.sh测试一下,竟然不一样。用ghex查看二进制的文件,看出是字符行
    尾的时候的编码不一样。想到下载的脚本可以是在windows下的脚本,下载安装 dos2un
    ix 编码转换工具,然后dos2unix pstack.sh, 工具可以使用。

# pstack.sh脚本简单分析
/* pstack.sh */
#! /bin/sh
# 输入参数以及pid是否存在的判断
if test $# -ne 1; then
    echo "Usage: `basename $0 .sh` <process-id>" 1>&2
    exit 1 
fi
if test ! -r /proc/$1; then
    echo "Process $1 not found." 1>&2
    exit 1
fi

# GDB doesn't allow "thread apply all bt" when the process isn't
# threaded; need to peek at the process to determine if that or the
# simpler "bt" should be used.
# 先设置参数 bt, 要是多线程的情况,那么设置为:thread apply all bt
backtrace="bt"
if test -d /proc/$1/task ; then
    # Newer kernel; has a task/ directory.
    if test `/bin/ls /proc/$1/task | /usr/bin/wc -l` -gt 1 2>/dev/null ; then
        backtrace="thread apply all bt"
    fi
elif test -f /proc/$1/maps ; then
    # Older kernel; go by it loading libpthread.
    if /bin/grep -e libpthread /proc/$1/maps > /dev/null 2>&1 ; then
        backtrace="thread apply all bt"
    fi
fi
 
GDB=${GDB:-/usr/bin/gdb}

# echo $GDB -> /usr/bin/gdb

# -nx: Do not execute commands from any `.gdbinit' initialization files.  Normal
   ly, the commands in these files are executed after all the command options  
   and  argu‐ments have been processed.
# --quiet: Do not print the introductory and copyright messages.  These message
   s are also suppressed in batch mode
# --batch: ...
# --readnever: ...
if $GDB -nx --quiet --batch --readnever > /dev/null 2>&1; then
    readnever=--readnever
else
    readnever=
fi
# 单步运行/usr/bin/gdb -nx --quiet --batch --readnever 时,--readnever会出错
 
# Run GDB, strip out unwanted noise.
# 原来用/proc/$1/exe找到pid对应的命令行, 但是发现下面命令中的是/proc/$1/exe
# 改成下面的'echo /proc/$1/exe'就可以了
$GDB --quiet $readnever -nx 'echo /proc/$1/exe' $1 <<EOF 2>&1 |
$backtrace 
EOF

# 这里,运行pstack [pid]一次会显示当时的函数调用,不能显示指定位置的堆栈情况。
# 可以先运行 gdb --quiet -nx /proc/command/exe command, 待gdb起来后,在想要的地
# 方设立断点,程序停住之后,使用bt,显示出当时的堆栈函数调用情况
 
# 整理显示输出格式
/bin/sed -n \
    -e 's/^(gdb) //' \
    -e '/^#/p' \
    -e '/^Thread/p'

附:测试程序和堆栈情况(单线程和多线程)

单线程:
# include<stdio.h>

int func_called(int a, int b)
{
int c;
c = a + b;
return c;
}

void func_calling(void)
{
int a = 1, b = 2;
int r;
r = func_called(a, b);
printf("r=%d\n", r);
}

int main()
{
    while(1) {
func_calling();
    }
}

测试输出:
29788 pts/5    00:00:34 test2
29819 pts/4    00:00:00 ps
***@A101107831:/vm/***/notes$ ./pstack.sh 29788
[sudo] password for ***: 
#0  0x00007f6d7d366910 in __write_nocancel ()
#1  0x00007f6d7d2f9883 in _IO_new_file_write (f=0x7f6d7d639260, 
#2  0x00007f6d7d2f974a in new_do_write (fp=0x7f6d7d639260, 
#3  0x00007f6d7d2faeb5 in _IO_new_do_write (fp=<optimized out>, 
#4  0x00007f6d7d2fa025 in _IO_new_file_xsputn (n=1, data=<optimized out>, 
#5  _IO_new_file_xsputn (f=0x7f6d7d639260, data=<optimized out>, n=1)
#6  0x00007f6d7d2ca4a7 in _IO_vfprintf_internal (s=<optimized out>, 
#7  0x00007f6d7d2d38d9 in __printf (format=<optimized out>) at printf.c:35
#8  0x000000000040054d in func_calling () at test2.c:15
#9  0x0000000000400563 in main () at test2.c:27

注:使用pc上已经在运行的应用程序调试时,无法显示具体的函数名和相关参数,原因是pc
    上的应用程序没有加入调试信息

多线程:
# include<stdio.h>
# include<pthread.h>
# include<string.h>

pthread_t tid1;
pthread_t tid2;

void* thread1(void* arg)
{
while(1){
printf("thread_id = %d\n", (int)tid1);
sleep(1);
}
}

void* thread2(void* arg)
{
    while(1){
printf("thread_id = %d\n", (int)tid2);
sleep(1);
}
}

int main()
{
int err;

err = pthread_create(&tid1, NULL, thread1, NULL);
if (err != 0){
fprintf(stderr, "can't create thread: %s\n", strerror(err));
}
err = pthread_create(&tid2, NULL, thread2, NULL);
if (err != 0){
fprintf(stderr, "can't create thread: %s\n", strerror(err));
}

while(1);
}

测试输出:
*** 30280 22661 30280 99    3 21:51 pts/5    00:00:12 ./multi_threads
*** 30280 22661 30281  0    3 21:51 pts/5    00:00:00 ./multi_threads
*** 30280 22661 30282  0    3 21:51 pts/5    00:00:00 ./multi_threads
*** 30284  3758 30284  0    1 21:51 pts/4    00:00:00 ps -eLf
***@A101107831:/vm/***/notes$ ./pstack.sh 30280
[sudo] password for ***: 
Thread 3 (Thread 0x7f2a351ae700 (LWP 30281)):
#0  0x00007f2a3526e84d in nanosleep () at ../sysdeps/unix/syscall-template.S:82
#1  0x00007f2a3526e6ec in __sleep (seconds=0)
#2  0x00000000004006fc in thread1 (arg=0x0) at multi_threads.c:14
#3  0x00007f2a35575e9a in start_thread (arg=0x7f2a351ae700)
#4  0x00007f2a352a2ccd in clone ()
#5  0x0000000000000000 in ?? ()
Thread 2 (Thread 0x7f2a349ad700 (LWP 30282)):
#0  0x00007f2a3526e84d in nanosleep () at ../sysdeps/unix/syscall-template.S:82
#1  0x00007f2a3526e6ec in __sleep (seconds=0)
#2  0x0000000000400736 in thread2 (arg=0x0) at multi_threads.c:22
#3  0x00007f2a35575e9a in start_thread (arg=0x7f2a349ad700)
#4  0x00007f2a352a2ccd in clone ()
#5  0x0000000000000000 in ?? ()
Thread 1 (Thread 0x7f2a35988700 (LWP 30280)):
#0  main () at multi_threads.c:39

注:按照下面gdb multi-thread debug方法,在pc上无法显示有关多线程的信息(被调试进
    程使用pc已经在运行的应用程序进程)

gdb多线程debug:
https://sourceware.org/gdb/onlinedocs/gdb/Threads.html#Threads

pstack学习笔记相关推荐

  1. Intel VT学习笔记(六)—— VM-Exit Handler

    Intel VT学习笔记(六)-- VM-Exit Handler Reutrn To DriverEntry VM-Exit Handler External interrupt I/O instr ...

  2. Intel VT学习笔记(四)—— VMCS(下)

    Intel VT学习笔记(四)-- VMCS(下) 要点回顾 VM-Exit Information Guest state fields 代码实现 参考资料 要点回顾 在上一篇中,我们了解了如何设置 ...

  3. Intel VT学习笔记(二)—— VMXEVMXON

    Intel VT学习笔记(二)-- VMXE&VMXON VT生命周期 VMXE VMXON 准备工作 VMXON region 代码实现 参考资料 VT生命周期 描述: 软件通过执行VMXO ...

  4. Intel VT学习笔记(三)—— VMCS(上)

    Intel VT学习笔记(三)-- VMCS(上) 要点回顾 VMCS 设置字段 错误排查 Fields Host-State Area VM-Control Fields 代码实现 参考资料 要点回 ...

  5. 【郝斌老师数据结构学习笔记 day 7】

    目录 前言 一.栈的定义 二.栈的分类 三.栈的一些算法 四.栈的日常应用 总结 前言 数据结构的学习笔记,记录第七天 一.栈的定义 定义:一种可以实现 "先进后出" 的存储结构 ...

  6. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  7. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  8. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  9. 2020年Yann Lecun深度学习笔记(下)

    2020年Yann Lecun深度学习笔记(下)

最新文章

  1. linux 从grub 进入rescue,在grub的rescue模式修复linux引导
  2. 数据结构一:链表(单向链表)
  3. 第三次学JAVA再学不好就吃翔(part52)--String类的其他功能
  4. uniapp中实现每次点击左侧菜单右边区域都从顶部开始
  5. node包管理器npm常用命令
  6. mysql5.1 utf8_编译安装mysql 5.1使用utf8解决乱码问题
  7. 物维管理、楼控系统、安防系统、巡检管理、电子巡更、门禁管理、变配电、给排水、防盗报警、消防报警、电梯监视、智能楼宇、物业管理、报修管理、维保管理、工单管理、物料管理、审批、租赁管理、楼宇管理、房产管理
  8. boot客户管理系统实训报告_客户太多,客户转化困难?分析报告迟迟出不来,CRM客户管理系统助你一臂之力...
  9. 用VMware克隆CentOS 6.4后修改HWaddr
  10. N沟道和P沟道MOS管的四个不同点
  11. 盘点数据分析中常用的图表类型
  12. 轻量级日志分析PLG平台Loki安装部署及使用(promtail+loki+Grafana)
  13. 事务 Transcation 是什么?
  14. 基于SpringBoot的学生成绩管理系统
  15. java打印等腰三角形
  16. ⌈ 2022杀青 ⌋ 一个普通人的年终总结,这一年我获得了更多的新鲜体验 | 普通而平凡的一年 | 向前走,走到光里 | 2023你好
  17. Centos7和Centos6.5密码破解
  18. 电子名片将在两年内,替代纸张型个人简历
  19. 图像处理课设(奇怪版)
  20. 江南大学2023年851真题回顾

热门文章

  1. OSG中uniform变量
  2. GRU时间序列数据分类预测
  3. LNK2019解决思路
  4. AWS KVS(Kinesis Video Streams)之WebRTC集成过程报错问题整理(八)
  5. AWS KVS(Kinesis Video Streams)之WebRTC移植编译(一)
  6. Infragistsitcs NetAdvantage WebCombo 控件
  7. 拼多多“造血”新农商
  8. Linux 下 输入账号 密码 显示 last login:Mon Apr 1 05:49:00 on tty1 但是跳转不进去系统?
  9. 使用nexus搭建maven私服教程详解
  10. hongyi lee hw02-03