StackWalk64 sur Windows - Get nom de symbole
Bien, deuxième question, DONC, en une seule journée. Ressemble à de la programmation sous Windows me rend heureux... : S
Je suis en train d'essayer d'obtenir la pile d'appels de fonction sur un exécutable Win32.
Ce matin, j'ai aussi posé une question à ce sujet:
Maintenant, je suis sûr que les StackWalk64
la fonction est la clé pour cela.
J'ai lu quelques articles sur la façon de l'utiliser, ainsi que le MS documentation.
Il réellement affiche les images sur mon programme de test, donc un peu de travail...
Le problème est que je ne suis pas en mesure de récupérer le nom du symbole de la pile informations.
Je suis en utilisant le SymGetSymFromAddr64
la fonction de ce, avec UnDecorateSymbolName
. Mais je ne reçois que des caractères indésirables.
Voici mon code. Espérons que c'est de ne pas le désordre, comme je n'ai pas l'habitude de la programmation sous Windows:
void printStack( void )
{
BOOL result;
HANDLE process;
HANDLE thread;
CONTEXT context;
STACKFRAME64 stack;
ULONG frame;
IMAGEHLP_SYMBOL64 symbol;
DWORD64 displacement;
char name[ 256 ];
RtlCaptureContext( &context );
memset( &stack, 0, sizeof( STACKFRAME64 ) );
process = GetCurrentProcess();
thread = GetCurrentThread();
displacement = 0;
stack.AddrPC.Offset = context.Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
for( frame = 0; ; frame++ )
{
result = StackWalk64
(
IMAGE_FILE_MACHINE_I386,
process,
thread,
&stack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL
);
symbol.SizeOfStruct = sizeof( IMAGEHLP_SYMBOL64 );
symbol.MaxNameLength = 255;
SymGetSymFromAddr64( process, ( ULONG64 )stack.AddrPC.Offset, &displacement, &symbol );
UnDecorateSymbolName( symbol.Name, ( PSTR )name, 256, UNDNAME_COMPLETE );
printf
(
"Frame %lu:\n"
" Symbol name: %s\n"
" PC address: 0x%08LX\n"
" Stack address: 0x%08LX\n"
" Frame address: 0x%08LX\n"
"\n",
frame,
symbol.Name,
( ULONG64 )stack.AddrPC.Offset,
( ULONG64 )stack.AddrStack.Offset,
( ULONG64 )stack.AddrFrame.Offset
);
if( !result )
{
break;
}
}
}
La production réelle est:
Frame 0:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠
PC address: 0x00BA2763
Stack address: 0x00000000
Frame address: 0x0031F7E8
Frame 1:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠☺
PC address: 0x00BB4FFF
Stack address: 0x00000000
Frame address: 0x0031F940
Frame 2:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠☻
PC address: 0x00BB4E2F
Stack address: 0x00000000
Frame address: 0x0031F990
Frame 3:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠♥
PC address: 0x75BE3677
Stack address: 0x00000000
Frame address: 0x0031F998
Frame 4:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠♦
PC address: 0x770F9D72
Stack address: 0x00000000
Frame address: 0x0031F9A4
Frame 5:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠♣
PC address: 0x770F9D45
Stack address: 0x00000000
Frame address: 0x0031F9E4
Frame 6:
Symbol name: ╠╠╠╠╠╠╠╠╠╠╠╠♠
PC address: 0x770F9D45
Stack address: 0x00000000
Frame address: 0x0031F9E4
Semble bizarre que la pile l'adresse est toujours à 0 par le chemin... Toute aide appréciée : )
Merci à tout le monde!
MODIFIER
Je suis à la recherche d'un simple C de la solution, sans tiers des bibliothèques...
SymGetSymFromAddr64
et UnDecorateSymbolName
?vous devez appeler SymInitialize, comme mentionné par Muqker
OriginalL'auteur Macmade | 2011-04-18
Vous devez vous connecter pour publier un commentaire.
Vous avez défini
symbol.MaxNameLength
à 255, mais vous avez alloué "symbole" sur la pile avecIMAGEHLP_SYMBOL64 symbol;
. Ce type est défini comme:Notez que le Nom de domaine n'a qu'un caractère par défaut. Si vous souhaitez stocker des plus gros noms, vous avez besoin de faire quelque chose comme:
Sinon,
SymGetSymFromAddr64()
est susceptible d'écraser la mémoire. Voici ce que la page d'aide pour la structure dit (italiques ajoutés):Vous devez également définir la SizeOfStruct membre sizeof( IMAGEHLP_SYMBOL64 ), conformément à la documentation.
Mon code ne fonctionne toujours pas, mais j'ai été en mesure d'obtenir la trace de débogage à l'aide de la
CaptureStackBackTrace
fonction. Il faut unSYMBOL_INFO
struct comme argument, qui doit être initialisé de la même façon queIMAGEHLP_SYMBOL64
. Je suis donc de l'acceptation de votre réponse. Merci beaucoup pour l'aide!La bonne façon d'allouer une taille appropriée à la structure pourrait être
malloc(offsetof(IMAGEHLP_SYMBOL64, Name[MaxNameLen]))
. Contrairement à l'ajout des tailles, ce qui représente pour le rembourrage et l'alignement.OriginalL'auteur AShelly
Découvrez la Stackwalker projet sur codeplex - il est open source. Fonctionne très bien.
Eh bien, vous pouvez voir la source, et d'apprendre ce qui fonctionne. Il n'y a pas beaucoup de c++; dans ce projet, la base de code qui montre comment résoudre le problème que vous avez soulevé, c'est juste C de code.
Essayé... Pas de chance pour l'instant... : (
Essayé, ça marche sur mon développement ordinateur portable, mais la même .exe ne fonctionne pas sur tout autre ordinateur portable - il ne parvient pas à trouver la signification des symboles.
OriginalL'auteur Cheeso
J'ai utilisé votre code et il n'a pas non plus de travail au début, jusqu'à ce que j'ai remarqué dans la documentation que vous devez d'abord appeler SymInitialize, comme SymInitialize(processus, NULL, TRUE) . Vous pouvez appeler cette fonction avant d'RtlCaptureContext.
OriginalL'auteur Muqker
Il y a deux problèmes à résoudre en premier:
1) Nom doit être préaffectés comme l'a souligné AShelly. Vous n'avez pas besoin de malloc pour le faire:
2) ok pour utiliser RtlCaptureContext() pour mettre en contexte dans les versions 32 bits. Si vous avez machine 64 bits puis changer IMAGE_FILE_MACHINE_I386 pour le 64 bits approprié type. Si vous avez des 32 bits de construire ensuite utiliser inline assemblée pour définir correctement EBP, ESP et EIP. Voici une façon de le faire:
Point mineur - SymGetSymFromAddr64 est ok, mais il est recommandé d'utiliser SymFromAddr à la place.
Bonne chance à tous ceux qui le traçage de la pile sur Windows.
OriginalL'auteur Sergey D
Voir cette réponse à ce qui est essentiellement la même question:
https://stackoverflow.com/a/28276227/10592
Noter que vous devez vous assurer que vos utilisateurs ont la .fichier pdb, et que leur processus peut trouver - voir la réponse pour plus de détails.
OriginalL'auteur Tim Cooper