2010-09-23 21 views
5

Je veux déboguer dans l'implémentation d'une méthode BCL [MethodImpl(MethodImplOptions.InternalCall)], qui est vraisemblablement implémentée en C++. (Dans ce cas particulier, je regarde System.String.nativeCompareOrdinal.) C'est principalement parce que je suis curieux et que je veux savoir comment il est implémenté. Toutefois, le débogueur Visual Studio refuse d'intervenir dans cette méthode. Je peux mettre un point d'arrêt sur cet appel:Comment puis-je déboguer dans une méthode BCL non administrée (InternalCall)?

"Hello".Equals("hello", StringComparison.OrdinalIgnoreCase); 

puis afficher débogage> Fenêtres> désassemblage, l'étape dans Egaux appel, et l'étape jusqu'à ce qu'il soit à l'instruction call x86. Mais quand j'essaie d'utiliser "Step Into" sur ce call (que je sais de Reflector est l'appel nativeCompareOrdinal), il ne passe pas à la première instruction à l'intérieur de nativeCompareOrdinal comme je le souhaite - il passe à la place, et va directement à l'instruction x86 suivante dans Equals.

Je construis comme x86, puisque le débogage en mode mixte n'est pas supporté pour les applications x64. J'ai décoché "Just My Code" dans Outils> Options> Débogage, et j'ai "Activer le débogage de code non géré" cochée dans les propriétés du projet> onglet Déboguer, mais il continue de franchir le call. J'ai également essayé de démarrer le processus, puis d'attacher le débogueur et d'attacher explicitement à la fois les débogueurs gérés et les débogueurs natifs, mais il n'interviendra toujours pas dans cette méthode InternalCall.

Comment faire pour que le débogueur Visual Studio entre dans une méthode non gérée?

Répondre

5

Oui, c'est difficile. Le décalage que vous voyez pour l'instruction CALL est faux. De plus, il ne vous laissera pas accéder à une adresse de code non gérée lorsque l'accent est mis sur une fonction gérée.

Commencez par activer le débogage de code non géré et définir un point d'arrêt sur l'appel. Exécutez le code et lorsque les coups de points de rupture utilisent Debug + Windows + désassemblage:

  "Hello".Equals("hello", StringComparison.OrdinalIgnoreCase); 
00000025 call  6E53D5D0 
0000002a nop    

Le débogueur tente d'afficher l'adresse absolue, mais se trompe, car il utilise l'adresse incrémentale bogus au lieu de l'adresse d'instruction réelle. Donc d'abord récupérer la vraie valeur relative: 0x6E53D5D0 - 0x2A = 0x6E53D5A6.

Ensuite, vous devez trouver l'adresse de code réel. Debug + Windows + Registers et regardez la valeur du registre EIP. 0x009A0095 dans mon cas. Ajoutez 5 pour obtenir le nop, puis ajoutez le décalage relatif: 0x9A0095 + 5 + 0x6E53D5A6 = 0x6EEDD640. La véritable adresse de la fonction.

Déboguer + Windows + Call Stack et double-cliquer sur une trame de pile non gérée. Vous pouvez maintenant entrer l'adresse calculée dans la boîte d'adresses de la fenêtre de désassemblage, préfixe 0x. Bingo, vous savez que vous êtes bon si vous voyez le code d'installation du cadre de la pile. Définissez un point d'arrêt dessus et appuyez sur F5.


Bien sûr, vous allez faire un pas de code machine puisqu'il n'y a pas de code source disponible. Vous obtiendrez un meilleur aperçu de ce que fait ce code en regardant le code source de SSCLI20. Je ne garantis pas que ce code correspondra au code actuel de votre version actuelle du CLR, mais d'après mon expérience, ces fragments de code de bas niveau qui existent depuis la version 1.0 sont hautement conservés. L'implémentation est dans clr \ src \ classlibnative \ nls, pas sûr du fichier de code source. Il ne sera pas nommé "nativeCompareOrdinal", c'est juste un nom interne utilisé par ecall.cpp.

+0

Je ne me suis pas contenté d'une méthode, mais d'un thunk - il y a eu un appel à un JMP vers un POP EAX (pour faire sortir la valeur de retour de l'appel de la pile). Démarrage plausible pour un thunk, je suppose. Hélas, lorsque j'ai défini un point d'arrêt sur l'opcode CALL, le débogueur s'est assis là pour toujours, monopolisant le processeur mais ne se brisant jamais; et quand j'ai supprimé ce point d'arrêt et défini des points d'arrêt sur JMP et POP à la place, il est passé juste devant eux, laissant l'application se terminer sans jamais se briser. Donc je peux regarder les opcodes x86 de cette façon, mais apparemment je ne peux pas déboguer à travers eux. Bien mieux que rien, mais toujours un peu décevant. –

+0

Il n'y a pas de thunk, je ne pense pas que vous avez trouvé le bon code. –