pstack学习笔记

pstack学习笔记################################################################################pstack学习笔记v0.12013.10.8*** 简介:pstack的功能是显示当前进程中函数的调用栈的关系,若是多线程的情况下,会显示各个      线程中函数调用的关系。 


Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
################################################################################

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193906.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • HashMap currentHashMap总结

    HashMap currentHashMap总结HashMap不同点:(1)JDK1.7用的是头插法,而JDK1.8及之后使用的都是尾插法,那么他们为什么要这样做呢?因为JDK1.7是用单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。(2)扩容后数据存储位置的计算方式也不一样:1.在JDK1.7的时候是直接用hash值和需要扩…

    2022年6月18日
  • Java 实现一个单例模式_Java实现单例模式的两种方式

    Java 实现一个单例模式_Java实现单例模式的两种方式单例模式在实际开发中有很多的用途,比如我们在项目中常用的工具类,数据库等资源的连接类。这样做的好处是避免创建多个对象,占用内存资源,自始自终在内存中只有一个对象为我们服务。单例对象一般有两种实现方式。懒汉式和饿汉式。饿汉式实现如下:packagecom.day05;/***饿汉式**@authorAdministrator**/publicclassSingle{//定义一个个私有静态本类对…

    2022年7月8日
  • PHP面试-复习知识点整理

    PHP面试-复习知识点整理

    2022年2月10日
  • 关于我转生变成史莱姆这档事_kicker.de

    关于我转生变成史莱姆这档事_kicker.de1  请问什么所kworker进程 清理旧版本的软件缓存:  sudoapt-getautoclean这个进程是干什么的? 我的机器刚装11.04没次卡的时候top一下就发现kworker这个进程占用CPU很大,基本上都能到75%左右youmaytrytodisableallpowersavingcon

    2022年9月25日
  • potplayer软件安装与常用配置

    potplayer软件安装与常用配置potplayer软件安装与常用配置1安装potplayer是一款十分好用的视频播放器,可以播放很多格式的视频,自定义皮肤,任意倍速,截取视频片段,还可以播放直播源(比如中国的CCTV以及各大卫视)…potplayer网址下载安装即可,最后如果显示要安装插件的话,去掉勾选即可2使用设置无边框:首先打开设置界面(快捷键F5),勾选如下两项设置打开视频时,默认居中显示,非全屏:首先打开设置界面(快捷键F5),进行如下两项设置进度条缩略图:首先打开设置界面(快捷键F5

    2022年5月11日
  • HTML/CSS面试题(收集)[通俗易懂]

    HTML/CSS面试题(收集)[通俗易懂]1、目前主流的浏览器以及其内核名有哪些?点这里查看2、内元素和块级元素的区别?行内元素:不会独立出现在一行,单独使用的时候后面不会有换行符的元素。eg:span,strong,img,a等。这些元素,默认的高宽,总是其内容的高宽。并且,margin和padding值,只有左右有效。块级元素:独立在一行的元素,他们后面会自动带有换行符。eg:di

    2022年5月20日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号