[LINUX] Benutzerprogrammverfolgung mit SystemTap Teil 2

Dies ist eine Fortsetzung des vorherigen Trace-Benutzerprogramms mit SystemTap Teil 1.

Das letzte Mal war der Zweck "Sehen wir uns die Bewegung an, ohne die vorhandene Quelle zu ändern". Dieses Mal werde ich beschreiben, wie SystemTap zum Zweck verwendet wird: "Wenn Sie Ihr eigenes Programm entwickeln, lassen Sie uns verfolgen, während Sie den variablen Wert des Sonderziels als Debugging-Tool ausgeben."

Ich möchte es als mein eigenes Programmentwicklungswerkzeug verwenden

Die folgenden Funktionen wurden im vorherigen Trace-Skript realisiert. ・ Einrücken um die Tiefe der Funktion -Liste der Funktionsargumente und ihrer Werte

Darüber hinaus wollte ich, dass die folgende Ausgabe dem Verhalten meines eigenen Programms folgt. ・ Ich möchte wissen, wo ich vorbeigekommen bin, als es einen Zweig in der Funktion gab. ・ Ich möchte den Wert der interessierenden Variablen wissen.

Ich konnte es schaffen. Es gibt Stellen, an denen es möglich erscheint, eine komplexere Methode zu entwickeln, aber ich werde sie an dieser Stelle als Methode veröffentlichen.

Beispiel mit Beispielcode

Das Implementierungsverfahren wird beschrieben. SystemTap-Skripte und ihre entsprechenden Header-Dateien für C ++, Zeigt die Ausführungsmethode und das Ausführungsergebnis des C ++ - Quellcodes SystemTap an.

Angenommen, Sie haben die folgenden drei Dateien "tr2.cpp", "ttr3.stp" und "ttr3.h" im Verzeichnis / home / TestProgs / tr1 /.

SystemTap-Skript zur Ablaufverfolgung

/home/TestProgs/tr2/ttr3.stp


#!/usr/bin/stap

probe $1.begin
{
	printf("[proc begin] pid=%d,procname=%s\n", 
		pid(), 		//Prozessnummer
		execname()	//Name der Ausführungsdatei
	);
}

probe $1.end
{
	printf("[proc end] pid=%d,procname=%s\n", pid(), execname());
}


//Probe zum Systemaufruf
probe $1.syscall
{
	# open systemcall
	if( $syscall == 2) {
		printf("%s open(%s)\n",thread_indent(0),kernel_string($arg1))
	}
	# close systemcall
	else if ( $syscall == 3) {
		printf("%s close(%d)\n",thread_indent(0), $arg1)
	}
	//Systemrufnummer ist"ausyscall --dump"Es kann mit dem Befehl von erhalten werden.
}

//Sonde zum Start der Funktion
probe $1.function("*").call
{
	printf("%s-->%s(%s) @%s %s\n",
		thread_indent(0),	
		ppfunc(),					//Funktionsname(Klassenname und Namespace werden nicht angezeigt.
		$$parms, 					//Argumentliste
		usymfileline(addr()),		//Dateiname und Zeilennummer
		probefunc() 				//Funktionsname(Nicht entwirrt)
	);
	thread_indent(1);	//
} 

//Sonde bis zum Ende der Funktion
probe $1.function("*").return
{
	thread_indent(-1);
	printf("%s<--%s,%s\n",
		thread_indent(0),
		ppfunc(),
		$$return				//Rückgabewert
	);
}


//define TR_FUNC()	STAP_PROBE2(myTrace,lineFunc,__LINE__,__PRETTY_FUNCTION__)
probe $1.provider("myTrace").mark("lineFunc")
{
	printf("%s%s:%d:%s\n",
		thread_indent(0),		
		usymfile(addr()),		//Name der Quellcodedatei
		$arg1,					// __LINE__
		user_string($arg2)	//User Space String__PRETTY_FUNCTION__
	); 
}

//define TR_LINE()	STAP_PROBE1(myTrace,line,__LINE__)
probe $1.provider("myTrace").mark("line")
{
	printf("%s L:%d\n",
		thread_indent(0),		
		$arg1					// __LINE__
	);		
}

//define TR_LINE_MSG(a1)	STAP_PROBE2(myTrace,lineMsg,__LINE__,a1)			 
probe $1.provider("myTrace").mark("lineMsg")
{
	printf("%s L:%d, %s",
		thread_indent(0),		
		$arg1,					// __LINE__
		user_string($arg2)					
	);		
}

//define TR_MSG(a1) STAP_PROBE1(myTrace,msg,a1) 
probe $1.provider("myTrace").mark("msg")
{
	printf("%s",
		user_string($arg1)
	);		
}

//define TR_d(a1) STAP_PROBE2(myTrace,p_d,#a1,a1)
probe $1.provider("myTrace").mark("p_d")
{
	printf("%s=%d ",
		user_string($arg1),
		$arg2
	);		
}

//define TR_u(a1) STAP_PROBE2(myTrace,p_u,#a1,a1)
probe $1.provider("myTrace").mark("p_u")
{
	printf("%s=%u ",
		user_string($arg1),
		$arg2
	);		
}

//define TR_x(a1) STAP_PROBE2(myTrace,p_x,#a1,a1)
probe $1.provider("myTrace").mark("p_x")
{
	printf("%s=0x%x ",
		user_string($arg1),
		$arg2
	);		
}


//define TR_s(a1) STAP_PROBE2(myTrace,p_s,#a1,a1)
probe $1.provider("myTrace").mark("p_s")
{
	printf("%s='%s' ",
		user_string($arg1),
		user_string($arg2)
	);		
}


//define TR_LOCAL() STAP_PROBE(myTrace,local);
probe $1.provider("myTrace").mark("local")
{
	printf("[$$locals] %s\n",$$locals); //Alle lokalen Variablen im Gültigkeitsbereich
}

Ergänzung zu ttr3.stp

Wir haben provider (). Mark () verwendet, um den Quellcode zu prüfen. -Die von povider () angegebene Zeichenfolge wird als Namespace und die von mark () angegebene Zeichenfolge als Identifikationsname verwendet.

C ++ - Headerdatei gepaart mit ttr3.stp

/home/TestProgs/tr2/ttr3.h


#ifndef __TTR3_MYTRACE_H_
#define __TTR3_MYTRACE_H_    1

#ifndef NO_MYTRACE

	#include <stdio.h>
	#include <sys/sdt.h>

	//Einzug+Name der Quelldatei+Zeilennummer+Demangled Funktionsname+Neue Zeile
	#define TR_FUNC()	STAP_PROBE2(myTrace,lineFunc,__LINE__,__PRETTY_FUNCTION__)

	//Einzug+Zeilennummer+Neue Zeile
	#define TR_LINE()	STAP_PROBE1(myTrace,line,__LINE__)

	//Einzug+Zeilennummer+Argumentzeichenfolge
	#define TR_LINE_MSG(a1)	STAP_PROBE2(myTrace,lineMsg,__LINE__,a1)

	//Argumentzeichenfolge
	#define TR_MSG(a1) STAP_PROBE1(myTrace,msg,a1) 

	//Variablenname und sein Wert(printf%d Format)   
	#define TR_d(a1) STAP_PROBE2(myTrace,p_d,#a1,a1)

	//Variablenname und sein Wert(printf%u Format)   
	#define TR_u(a1) STAP_PROBE2(myTrace,p_u,#a1,a1)

	//Variablenname und sein Wert(printf%x-Format)   
	#define TR_x(a1) STAP_PROBE2(myTrace,p_x,#a1,a1)

	//Variablenname und sein Wert(printf%s Format)   
	#define TR_s(a1) STAP_PROBE2(myTrace,p_s,#a1,a1)

	//Variablennamen und ihre Werte für alle lokalen Variablen im Gültigkeitsbereich+Neue Zeile
	#define TR_LOCAL() STAP_PROBE(myTrace,local);

	//Dummy-Testfunktion
	// "> stap -v ttr3.stp "Wann, ttr3.mark in stp definiert()Wenn es jedoch nicht einmal im CPP-Code erscheint, führt die Stap-Ausführung zu einem Fehler.
	//Dient auch als Testcode ttr3.Marke definiert durch stap()All dies wird in dieser Funktion beschrieben.
	void STAP_TRACE_defines(){
		int dmyI=0;
		const char *dmyS="dummy";
		TR_FUNC();
		TR_LINE();
		TR_LINE_MSG("test mesg\n"); 
		TR_MSG("test mesg\n");
		TR_d(dmyI);
		TR_u(dmyI);
		TR_x(dmyI);
		TR_s(dmyS);
		TR_LOCAL();
		printf("%s %d\n",dmyS,dmyI);
	}

#else

	#define TR_FUNC()			/**/
	#define TR_LINE()			/**/
	#define TR_LINE_MSG(a1)	/**/				 
	#define TR_MSG(a1)  		/**/
	#define TR_d(a1) 			/**/
	#define TR_u(a1) 			/**/
	#define TR_x(a1) 			/**/
	#define TR_s(a1) 			/**/
	#define TR_LOCAL() 		/**/

#endif // NO_MYTRACE

#endif // __TTR3_MYTRACE_H_

Ergänzung von ttr3.h

Beispiel für einen C ++ - Quellcode

/home/TestProgs/tr2/tr2.cpp


#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <assert.h>

#include "ttr3.h"


class classSample1{
	public:
		classSample1(){};
		~classSample1(){};
		int func_C1(){
			printf("classSample1::func_C1()\n");
			TR_LINE(); //Zeilenumbruch der eingerückten Zeilennummer
			return 0;
		}
		int func_C2(int m);
		int cnt_func_C2 = 0;
};

int classSample1::func_C2(int m){
	printf("classSample2::func_C2()\n");
	TR_FUNC();	//Einrückungsdateiname Zeilennummer entwirrter Funktionsname Zeilenumbruch
	cnt_func_C2++;
	int l= cnt_func_C2 % 2;
	uint32_t u32=0xfffffffd + cnt_func_C2;
	uint64_t u64=0xfffffffffffffffd + cnt_func_C2;
	int32_t  i32=-3 + cnt_func_C2;
	int64_t  i64=-3 + cnt_func_C2;

	printf("cnt_func_C2 %d , l:%d ,u32:%u, u64:%lu\n",cnt_func_C2,l,u32,u64);	

	TR_LINE_MSG("");TR_d(cnt_func_C2);TR_d(l);TR_MSG("\n"); 				 	//Einrückungszeilennummer cnt_func_C2-Wert l-Wert Zeilenvorschub
	TR_LINE_MSG("");TR_d(i32);TR_u(u32);TR_d(i64);TR_u(u64);TR_MSG("\n");	//Einrückungszeilennummer i32-Wert u32-Wert i64-Wert u64-Wert Zeilenvorschub
	TR_LINE_MSG("");TR_LOCAL();													//Einzug Alle lokalen Variablen in diesem Bereich()

	assert(cnt_func_C2<m);  //Als Beispiel ausgesetzt.

	if (l == 0) {
		TR_LINE_MSG("even.\n");	//Zeichenfolge für eingerückte Zeilennummer
		return 0;
	}else{
		TR_LINE_MSG("odd.\n");	//Zeichenfolge für eingerückte Zeilennummer
		return 1;
	}
}



int main(int argc, char *argv[])
{
	int ret=0;

	classSample1 c1; 

	for(;;) {

		ret = c1.func_C1();
		sleep(2);

		ret = c1.func_C2(5);
		sleep(2);

	}
	return ret;
}

Ergänzung

-TR _ *** wird wie printf hinzugefügt.

Kompilieren Sie den C ++ - Quellcode

> cd /home/TestProgs/tr2/
> gcc -Wall -g -O0 -std=c++11 tr2.cpp -o tr2 -lstdc++

Führen Sie das SystemTap-Skript aus

> stap -v ttr3.stp 'process("/home/TestProgs/tr2/tr2")'

Geben Sie dem Argument eine Zeichenfolge, die den vollständigen Pfad zur ausführbaren Datei enthält. Das unten gezeigte Parser-Ergebnis wird ausgegeben.

stdout


Pass 1: parsed user script and 491 library scripts using 243904virt/56396res/3316shr/53796data kb, in 790usr/40sys/837real ms.
WARNING: function _start return probe is blacklisted: keyword at ttr3.stp:45:1
 source: probe $1.function("*").return
         ^
Pass 2: analyzed script: 57 probes, 41 functions, 6 embeds, 2 globals using 246812virt/60696res/4680shr/56704data kb, in 120usr/110sys/228real ms.
Pass 3: translated to C into "/tmp/stap4b9QpY/stap_8a82d56cba8247f5ae53b508cd7dbe33_50483_src.c" using 246956virt/61192res/5028shr/56848data kb, in 50usr/110sys/159real ms.
Pass 4: compiled C into "stap_8a82d56cba8247f5ae53b508cd7dbe33_50483.ko" in 4050usr/640sys/4517real ms.
Pass 5: starting run.

Öffnen Sie eine andere Shell und führen Sie das Zielprogramm aus

> cd /home/TestProgs/tr2/
> ./tr2

Ausgabeergebnis des SystemTap-Skripts ttr3.stp

stdout


[proc begin] pid=16890,procname=tr2
     0 tr2(16890): open(/etc/ld.so.cache)
     0 tr2(16890): close(3)
     0 tr2(16890): open(/lib64/libstdc++.so.6)
     0 tr2(16890): close(3)
     0 tr2(16890): open(/lib64/libgcc_s.so.1)
     0 tr2(16890): close(3)
     0 tr2(16890): open(/lib64/libc.so.6)
     0 tr2(16890): close(3)
     0 tr2(16890): open(/lib64/libm.so.6)
     0 tr2(16890): close(3)
     0 tr2(16890):-->_start() @0x4006e0 _start
    19 tr2(16890):-->__libc_csu_init() @0x400a10 __libc_csu_init
    32 tr2(16890): -->_init() @0x400628 _init
    43 tr2(16890): <--_init,
    47 tr2(16890): -->frame_dummy() @0x4007a0 frame_dummy
    57 tr2(16890):  -->register_tm_clones() @0x400740 register_tm_clones
    68 tr2(16890):  <--register_tm_clones,
    70 tr2(16890): <--frame_dummy,
    73 tr2(16890):<--__libc_csu_init,
    86 tr2(16890):-->main(argc=0x1 argv=0x7ffc0ea27058) @/home/TestProgs/tr2/tr2.cpp:53 main
   100 tr2(16890): -->classSample1(this=0x0) @/home/TestProgs/tr2/tr2.cpp:11 _ZN12classSample1C2Ev
   113 tr2(16890): <--classSample1,
   116 tr2(16890): -->func_C1(this=0x7ffc0ea26f50) @/home/TestProgs/tr2/tr2.cpp:13 _ZN12classSample17func_C1Ev
   222 tr2(16890):   L:15
   227 tr2(16890): <--func_C1,return=0x0
2003172 tr2(16890): -->func_C2(this=0x7ffc0ea26f50 m=0x5) @/home/TestProgs/tr2/tr2.cpp:23 _ZN12classSample17func_C2Ei
2003220 tr2(16890):  /home/TestProgs/tr2/tr2.cpp:24:int classSample1::func_C2(int)
2003281 tr2(16890):   L:34, cnt_func_C2=1 l=1 
2003299 tr2(16890):   L:35, i32=-2 u32=4294967294 i64=-2 u64=18446744073709551614 
2003324 tr2(16890):   L:36, [$$locals] __PRETTY_FUNCTION__=[...] l=0x1 u32=0xfffffffe u64=0xfffffffffffffffe i32=0xfffffffffffffffe i64=0xfffffffffffffffe
2003337 tr2(16890):   L:44, odd.
2003345 tr2(16890): <--func_C2,return=0x1
4003668 tr2(16890): -->func_C1(this=0x4006e0) @/home/TestProgs/tr2/tr2.cpp:13 _ZN12classSample17func_C1Ev
4003729 tr2(16890):   L:15
4003738 tr2(16890): <--func_C1,return=0x0
6006538 tr2(16890): -->func_C2(this=0x7ffc0ea26f50 m=0x5) @/home/TestProgs/tr2/tr2.cpp:23 _ZN12classSample17func_C2Ei
6006587 tr2(16890):  /home/TestProgs/tr2/tr2.cpp:24:int classSample1::func_C2(int)
6006612 tr2(16890):   L:34, cnt_func_C2=2 l=0 
6006630 tr2(16890):   L:35, i32=-1 u32=4294967295 i64=-1 u64=18446744073709551615 
6006655 tr2(16890):   L:36, [$$locals] __PRETTY_FUNCTION__=[...] l=0x0 u32=0xffffffff u64=0xffffffffffffffff i32=0xffffffffffffffff i64=0xffffffffffffffff
6006668 tr2(16890):   L:41, even.
6006676 tr2(16890): <--func_C2,return=0x0
8008347 tr2(16890): -->func_C1(this=0x4006e0) @/home/TestProgs/tr2/tr2.cpp:13 _ZN12classSample17func_C1Ev
8008409 tr2(16890):   L:15
8008418 tr2(16890): <--func_C1,return=0x0
10009956 tr2(16890): -->func_C2(this=0x7ffc0ea26f50 m=0x5) @/home/TestProgs/tr2/tr2.cpp:23 _ZN12classSample17func_C2Ei
10010004 tr2(16890):  /home/TestProgs/tr2/tr2.cpp:24:int classSample1::func_C2(int)
10010028 tr2(16890):   L:34, cnt_func_C2=3 l=1 
10010046 tr2(16890):   L:35, i32=0 u32=0 i64=0 u64=0 
10010070 tr2(16890):   L:36, [$$locals] __PRETTY_FUNCTION__=[...] l=0x1 u32=0x0 u64=0x0 i32=0x0 i64=0x0
10010081 tr2(16890):   L:44, odd.
10010089 tr2(16890): <--func_C2,return=0x1
12014178 tr2(16890): -->func_C1(this=0x4006e0) @/home/TestProgs/tr2/tr2.cpp:13 _ZN12classSample17func_C1Ev
12014238 tr2(16890):   L:15
12014246 tr2(16890): <--func_C1,return=0x0
14014842 tr2(16890): -->func_C2(this=0x7ffc0ea26f50 m=0x5) @/home/TestProgs/tr2/tr2.cpp:23 _ZN12classSample17func_C2Ei
14014888 tr2(16890):  /home/TestProgs/tr2/tr2.cpp:24:int classSample1::func_C2(int)
14014912 tr2(16890):   L:34, cnt_func_C2=4 l=0 
14014930 tr2(16890):   L:35, i32=1 u32=1 i64=1 u64=1 
14014953 tr2(16890):   L:36, [$$locals] __PRETTY_FUNCTION__=[...] l=0x0 u32=0x1 u64=0x1 i32=0x1 i64=0x1
14014965 tr2(16890):   L:41, even.
14014972 tr2(16890): <--func_C2,return=0x0
16015484 tr2(16890): -->func_C1(this=0x4006e0) @/home/TestProgs/tr2/tr2.cpp:13 _ZN12classSample17func_C1Ev
16015579 tr2(16890):   L:15
16015588 tr2(16890): <--func_C1,return=0x0
18020986 tr2(16890): -->func_C2(this=0x7ffc0ea26f50 m=0x5) @/home/TestProgs/tr2/tr2.cpp:23 _ZN12classSample17func_C2Ei
18021033 tr2(16890):  /home/TestProgs/tr2/tr2.cpp:24:int classSample1::func_C2(int)
18021057 tr2(16890):   L:34, cnt_func_C2=5 l=1 
18021074 tr2(16890):   L:35, i32=2 u32=2 i64=2 u64=2 
18021098 tr2(16890):   L:36, [$$locals] __PRETTY_FUNCTION__=[...] l=0x1 u32=0x2 u64=0x2 i32=0x2 i64=0x2
[proc end] pid=16890,procname=tr2

Von der vorherigen Funktion, ・ Einrücken um die Tiefe der Funktion -Liste der Funktionsargumente und ihrer Werte

Vielen Dank, dass Sie so weit gelesen haben.

Recommended Posts

Rückverfolgung von Benutzerprogrammen mit SystemTap Teil 1
Benutzerprogrammverfolgung mit SystemTap Teil 2
Sandkasten mit neo4j Teil 10
Bildverarbeitung mit Python (Teil 2)
Python mit freeCodeCamp Teil1 studieren
Angrenzende Bilder mit Python Teil 1
Schaben mit Selen + Python Teil 1
Bildverarbeitung mit Python (Teil 1)
Nampre mit Python lösen (Teil 2)
Bildverarbeitung mit Python (3)
Schaben mit Selen + Python Teil 2