Zombie threads
[edit | edit source]Any thread that has terminated but has not been joined or detached will leak OS resources until the process terminates. Unfortunately, neither nor will show you these zombie threads, at least not on some kernels.
One way to get them is with a gdb canned command:
# # # definetrace_call b$arg0 commands btfull continue end end documenttrace_call Tracespecifiedcallwithcallstacktoscreen.Example: setbreakpointpendingon setpaginationoff setloggingon trace_call__pthread_create_2_1 end
Usinghostlibthread_dblibrary"/lib/i686/cmov/libthread_db.so.1". (gdb)trace_call__pthread_create_2_1 Function"__pthread_create_2_1"notdefined. Breakpoint1(__pthread_create_2_1)pending. (gdb)trace_call__pthread_create_2_0 Function"__pthread_create_2_0"notdefined. Breakpoint2(__pthread_create_2_0)pending. (gdb)r Startingprogram:/home/amelinte/projects/articole/wikibooks/debug/plockfoobarbax [Threaddebuggingusinglibthread_dbenabled] Breakpoint3at0xb7f9b746 Pendingbreakpoint"__pthread_create_2_1"resolved Breakpoint4at0xb7f9c395 Pendingbreakpoint"__pthread_create_2_0"resolved [NewThread0xb7e48ad0(LWP8635)] [SwitchingtoThread0xb7e48ad0(LWP8635)] Breakpoint3,0xb7f9b746inpthread_create@@GLIBC_2.1()from/lib/i686/cmov/libpthread.so.0 #0 0xb7f9b746 in pthread_create@@GLIBC_2.1 () from /lib/i686/cmov/libpthread.so.0 Nosymboltableinfoavailable. #1 0x08048a7f in main (argc=4, argv=0xbfceb714) at plock.c:97 s=0 tnum=0 opt=-1 num_threads=3 tinfo=(structthread_info*)0x833b008 attr={__size='\0'<repeats13times>,"\020",'\0'<repeats21times>,__align=0} stack_size=-1 res=(void*)0x0 [NewThread0xb7e47b90(LWP8638)] Thread1:topofstacknear0xb7e473c8;argv_string=foo
Another way is to use (again) an interposition library:
/* * Hook library. Usage: * gcc -c -g -Wall -fPIC libhook.c -o libhook.o * ld -o libhook.so libhook.o -shared -ldl * LD_PRELOAD=./libhook.so program arguments * * Copyright 2012 Aurelian Melinte. * Released under GPL 3.0 or later. */ #define _GNU_SOURCE #include<dlfcn.h> #include<signal.h> #include<execinfo.h> #include<errno.h> #include<stdlib.h> #include<stdio.h> /*printf*/ #include<unistd.h> #include<pthread.h> #include<assert.h> typedefint(*lp_pthread_mutex_func)(pthread_mutex_t*mutex); typedefint(*pthread_create_func)(pthread_t*thread, constpthread_attr_t*attr, void*(*start_routine)(void*),void*arg); staticpthread_create_func_pthread_create_hook=NULL; staticint hook_one(pthread_create_func*fptr,constchar*fname) { char*msg=NULL; assert(fname!=NULL); if(*fptr==NULL){ printf("dlsym : wrapping %s\n",fname); *fptr=dlsym(RTLD_NEXT,fname); printf("next_%s = %p\n",fname,*fptr); if((*fptr==NULL)||((msg=dlerror())!=NULL)){ printf("dlsym %s failed : %s\n",fname,msg); return-1; }else{ printf("dlsym: wrapping %s done\n",fname); return0; } }else{ return0; } } staticvoid hook_funcs(void) { if(_pthread_create_hook==NULL){ intrc=hook_one(&_pthread_create_hook,"pthread_create"); if(NULL==_pthread_create_hook||rc!=0){ printf("Failed to hook.\n"); exit(EXIT_FAILURE); } } } /* * */ int pthread_create(pthread_t*thread, constpthread_attr_t*attr, void*(*start_routine)(void*),void*arg) { #define SIZE 40 void*buffer[SIZE]={0}; intnptrs=0; intrc=EINVAL; rc=_pthread_create_hook(thread,attr,start_routine,arg); printf("*** pthread_create:\n"); nptrs=backtrace(buffer,SIZE); backtrace_symbols_fd(buffer,nptrs,STDOUT_FILENO); returnrc; } /* * */ void_init()__attribute__((constructor)); void _init() { printf("*** _init().\n"); hook_funcs(); } void_fini()__attribute__((destructor)); void _fini() { printf("*** _fini().\n"); }
The output is a bit rough but it can be refined down to file and line by replacing with appropriate code:
***pthread_create: ./libhook.so(pthread_create+0x8c)[0x400215d3] ./plock[0x8048a7f] /lib/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0x4006f450] ./plock[0x8048791]
File descriptors
[edit | edit source]As just about anything is a file (folders, sockets, pipes, etc.), just about anything can result in a file descriptor that needs to be closed. can help:
# tree /proc/26041 /proc/26041 ... |--fd# Open files descriptors ||--0->/dev/pts/21 ||--1->/dev/pts/21 ||--2->/dev/pts/21 |`--3->socket:[113497835] |--fdinfo ||--0 ||--1 ||--2 |`--3 ...
The command for can help with the call stack.
If gdb is not available on the machine, an interposition library hooking , , , etc. can be built.
Other tools that can be used:
Ports
[edit | edit source]Which process is using a port? As root:
# netstat -tlnp ActiveInternetconnections(onlyservers) ProtoRecv-QSend-QLocalAddressForeignAddressStatePID/Programname tcp000.0.0.0:365100.0.0.0:*LISTEN- tcp00127.0.0.1:22070.0.0.0:*LISTEN3438/python ...
# lsof COMMANDPIDUSERFDTYPEDEVICESIZENODENAME init1rootcwdDIR253,040962/ ... python3438root4uIPv411416TCPlocalhost.localdomain:2207(LISTEN) # lsof -i :2207 COMMANDPIDUSERFDTYPEDEVICESIZENODENAME python3438root4uIPv411416TCPlocalhost.localdomain:2207(LISTEN)
Other tools:
IPC
[edit | edit source]For semaphores, shared memory and message queues.
# ipcs -spt ------SemaphoreOperation/ChangeTimes-------- semidownerlast-oplast-changed 187826177aurelian_mFriFeb1009:37:262012FriFeb1009:33:392012 187858946aurelian_mFriFeb1009:52:112012FriFeb1009:50:442012
DYI: an interposition resource counter
[edit | edit source]libmemleak can be easily modified to keep track of whatever resources are leaking. Hook the right API (e.g. ).
