Monday, 11 September 2017

0x7ff In Binary Option


Wenn Sie wissen, wie Sie Arrays in MIPS erstellen, können Sie einfach einen Binärbaum auf ein Array projizieren. Es wird mehr oder weniger eine riesige Verschwendung von Raum sein, aber es wird halb einfach funktionieren. Zuerst bestimmen, wie Sie einen Knoten im Speicher auf dem Stapel zu organisieren. Ich würde es organisieren: benennen Sie einen Nullwert für den Knoten, wahrscheinlich 0x7ff. F benennen Sie eine Nulladresse, wahrscheinlich erstellen 0 ein Array der Größe. (2n - 1) NodeSize wobei n die Tiefe des tiefsten Zweiges des Baums von 1, nicht 0, ist. NodeSize ist die Anzahl der Wörter, die benötigt werden, um einen Knoten zu beschreiben. Der Index des Arrays entspricht dem unten beschriebenen Muster. Es wird etwas schwierig sein, mit zu arbeiten, aber es sollte funktionieren. Ich nehme technisch Sie entweder nicht das Array, um Nullwerte zu indexieren, wenn Sie den Baum gut zu verwalten, oder wenn Sie behalten es in dem Format, das ich beschrieben habe, müssen Sie nicht wirklich die Adressen der anderen Knoten zu speichern, weil sie durch ihre Indizes impliziert sind . So wirklich brauchen Sie nur das eine oder das andere. Sie sollten wirklich wählen, welche wäre einfacher, indem Sie herausfinden, wie viel Sie mit Adressen arbeiten möchten und wie voll Ihr Baum sein wird. Wenn Ihr Baum voll ist, sind die impliziten Kanten hilfreich, indem Sie Platz sparen. Tldr Dies wird Raum verschwenden, indem man einen Baum auf zwei Arten beschreibt. Entfernen Sie die Array-Idee oder die Adressen. Answered Dec 7 11 at 20: 50Senden von ADC-Daten auf seriellem Port In diesem Beispiel werden wir untersuchen, wie die ADC-Daten aus dem MSP430 zu sammeln und werfen die Daten auf dem seriellen Port. A / D-Umwandlung und Senden an serielle Schnittstelle Gehen Sie durch den folgenden Code. // // MSP-FET430F149 Demo - ADC12, Beispiel A1, Senden des Pegels an der seriellen Schnittstelle // // Beschreibung: Ein einziges Sample wird auf A1 mit Bezug auf AVcc gemacht. // Softwarestart Beispiel und Konvertierung - Senden Sie den // Analog Spannungspegel an den seriellen Port als zwei Bytes. // // Zusätzlich, wenn die Spannung über 0,5Vcc ist, macht es LED bei P6.2 glow // // MSP430F149 // ---------------- // // XIN - / / // - RST XOUT - // // Vin - gtP6.1 / A1 P6.2 - gt // // P3.4 ----------- gt // 9600 - 8N1 // P3.5lt ----------- // // referencedesigner // Einige der Original-Codes stammen von Texas Instruments // unsigned int delay (unsigned int x) unsigned int i, j für (i 0 ILT xi) für (j0jlt1000 j) return 0 WDTCTL WDTPW WDTHOLD // Stop Watch Dog Timer ADC12CTL0 SHT02 ADC12ON // Set Abtastzeit, schalten Sie ADC12 ADC12CTL1 SHP ADC12IE 0x01 // aktivieren Interrupt ADC12MCTL0 0x01 ADC12CTL0 ENC // Konvertierung aktiviert P6SEL 0x02 // P6.1 ADC Option P6DIR 0x04 // P6.2 ist Ausgang für LED // Einstellungen der seriellen Schnittstelle P3SEL 0x30 // P3.4,5 USART0 TXD / RXD ME1 UTXE0 URXE0 // aktivieren USART0 TXD / RXD UCTL0 CHAR / / 8-Bit-Zeichen UTCTL0 SSEL0 // UCLK ACLK UBR00 0x03 // 32k / 9600-3,41 UBR10 0x00 // UMCTL0 0x4A // Modulation UCTL0 amp SWRST // initialisieren USART Zustandsmaschine IE1 URXIE0 // Aktivieren USART0 RX-Interrupt für () / / Dies sollte in einem Timer-Interrupt passieren eigentlich, wo // wir können gerne in nur einmal zu probieren, etwa 1 Sekunde Verzögerung (500) ADC12CTL0 ADC12SC // Sampling offen BISSR (CPUOff GIE) // LPM0 wird ADC12ISR Ausfahrt zwingen // ADC12 Interrupt-Service-Routine Pragma vectorADC12VECTOR unterbrechen Leere ADC12ISR (void) unsigned short lResultRSSI unsigned char Teil1, Teil2 if (ADC12MEM0 lt 0x7FF) P6OUT amp 0x04 // Lösche P6.2 - LED aus sonst P6OUT 0x04 // Set P6.2 - LED auf BICSRIRQ (CPUOff) // Lösche CPUOff Bit von 0 (SR) lResultRSSI ADC12MEM0 // RXBUF0 zu TXBUF0 Teil1 (lResultRSSI amp 0x00FF) // lsb Teil2 (lResultRSSI amp 0xFF00) gtgt 8 // msb while ((IFG1 amp UTXIFG0)) TXBUF0 Teil2 // Wir senden MSB zuerst, während ((IFG1 amp UTXIFG0)) TXBUF0 part1 Kopieren Sie diesen Code in Ihr IAR Embedder System ein und führen Sie den Code. Sie sollten den seriellen Anschluss des MSP430 über einen RS232-Pegelschieber an den Computer anschließen. Stellen Sie die Durchsatzrate bei 9600, 8 Datenbits, kein Pary und 1 Stopbit ein. Beachten Sie, dass Sie nicht auf der ASCII-Text, die eine Norm bei Hyperterminal ist. Verwenden Sie stattdessen ein serielles Port-Terminal, das die Daten in Hex anzeigt. Wenn die Spannung an deinem A1-Port etwa 1,5 V beträgt und deine Platine bei 3,0 V läuft, gibt dies typischerweise Daten in der Nähe von 07 FF aus (die Daten sind in Hex). Wenn Sie den KV-Eingang in der Nähe von 3,0 V erhöhen, ergibt sich 0F FF. Wenn es 0V ist, gibt es 00 00. Beachten Sie, dass die Verzögerungsschleife als for-Schleife geschrieben wird. Dies ist nicht die beste Praxis, aber es funktioniert. Ein Timer ist ein besserer Weg, um die Verzögerung zu implementieren. Tatsächlich können wir innerhalb des Timers die ADC-Konvertierungsschritte aufrufen. Nbsp nbsp nbsp nbsp nbsp nbsp namenextbutton x64 Manuelle Stack-Rekonstruktion und Stack Walking Mein Name ist Trey Nash und ich bin ein Escalation Engineer auf dem Core OS-Team. Meine Erfahrung ist als Software-Entwickler, und daher sind meine Blog-Beiträge neigen dazu, in Richtung der Hilfe-Entwickler während der Feature-Entwicklung, Test-und Support-Phasen schräg. In dieser Rate möchte ich ein bisschen auf eine vorherige Post von mir als Challenges of Debugging Optimized x64 Code erweitern. In diesem Beitrag diskutierte ich die Nuancen der x64-Aufrufkonvention (zum Glück gibt es nur einen) und wie er in optimierten Software-Builds verwendet wird. Die aufrufende Konvention wird manchmal als Application Binary Interface (ABI) bezeichnet. In diesem Beitrag möchte ich die x64 entspannen Metadaten und wie Sie es im Debugger verwenden, um manuell zu Fuß einen Stapel zu diskutieren. In einigen Fällen können Sie einen beschädigten Stapel haben, den der Debugger einfach nicht effektiv für Sie gehen kann. Dies geschieht oft, weil der Debugger einen Stapel von oben nach unten (unter der Annahme, der Stapel wächst nach oben wie ein Stapel von Plätzen auf einem Tisch), und wenn der Stapel genügend trashed ist, dann kann der Debugger nicht finden, seine Lager. In der x86-Welt, einen großen Prozentsatz der Zeit, können Sie die Stapel-Frames, indem Sie die Kette der Basis-Zeiger und dann eine crafty Stack Backtrace-Befehl, um den Stapel zu einem bestimmten Zeitpunkt zu sehen. Aber in der x64-Aufrufkonvention gibt es keinen Basiszeiger. Tatsächlich ändert sich nach dem Ausführen eines Funktionsprolog-Codes das rsp-Register im allgemeinen niemals bis zum Epilog-Code. Weitere Informationen zu X64-Prolog - und Epilog-Code-Konventionen finden Sie hier. Darüber hinaus ist die Syntax für die Erstellung eines Crafty Stack Backtrace-Befehl in der x64-Umgebung derzeit undokumentiert, und ich ziele darauf ab, etwas Licht auf, dass in der Nähe des Endes dieses Blog-Post zu vergießen. J Der Beispielcode Für diesen Blogpfosten habe ich den folgenden Beispiel-C-Code verwendet, der das. NET 4.0-Framework benötigt und leicht aus einer Visual Studio 2010-Eingabeaufforderung erstellt werden kann. Sie können den Code unten finden: using System System. Numerics mit System. Threading Verwendung mit System. Threading. Tasks System. Collections. Concurrent Klasse Entrypoint const int FactorialsToCompute 2000 static void Main () var Zahlen neue ConcurrentDictionaryltBigInteger, BigIntegergt mit (4, FactorialsToCompute ) // Erstellen Sie einen faktoriellen Delegaten. FuncltBigInteger, BigIntegergt Fakultät null Fakultät (n) gt (n 0). 1. n factorial (n-1) // Berechnet nun die Fakultät der Liste // gleichzeitig. Parallel. For (0, FactorialsToCompute, (i) gt numbersi factorial (i)) Der Geist dieses Codes ist es, gleichzeitig die ersten 2000 Fakultäten zu berechnen und die Ergebnisse in einem Wörterbuch zu speichern. Dieser Code verwendet die neue Task Parallel Library, um diese Arbeit gleichmäßig über die mehreren Kerne auf dem System zu verteilen. Um das Beispiel zu kompilieren (vorausgesetzt, dass der Code in test. cs gespeichert ist), können Sie den folgenden Befehl aus einer Visual Studio 2010-Eingabeaufforderung ausführen: csc /r: system. numerics. dll test. cs Hinweis: Wenn Sie ein 64bit verwenden Plattform verwenden, müssen Sie die Verknüpfung x64-Eingabeaufforderung verwenden, die von dem Visual Studio 2010-Installationsprogramm installiert wird. Hier können Sie eine kostenlose Evaluation von Visual Studio 2010 herunterladen. X64 Entpacken von Metadaten So wie funktioniert der Debugger und Funktionen wie RtlVirtualUnwind wissen, wie man den x64-Stack zu gehen, wenn es nicht finden können, einen Basiszeiger Das Geheimnis ist, dass es Abwicklung Metadaten, die in der Regel gebacken wird in der Portable Executable (PE) - Datei zur Linkzeit . Sie können diese Informationen mit der Option / UNWINDINFO des Befehlszeilentools dumpbin überprüfen. Zum Beispiel ging ich in das Verzeichnis auf meinem Rechner, die clr. dll enthält (c: WindowsMicrosoft. NETFrameworkv4.0.30319) und schüttete die Abroll Information Suche nach CLREvent :: WaitEx, die ich unten eingefügt haben: 00013F20 000DFDB0 000DFE3C 007267D8 WaitExCLREventQEAAKKW4WaitModePEAUPendingSyncZ (öffentliche : unsigned long cdecl CLREvent :: WaitEx (unsigned long, enum WaitMode, struct PendingSync)) Entspannen Version: 1 flags Unwind: UHANDLER Größe der Prolog: 0x20 Anzahl von Codes: 10 Codes Unwind: 20: SAVENONVOL, registerrbp offset0xB0 1C: SAVENONVOL, registerrbx offset0xA8 0F: ALLOCSMALL, size0x70 0B: PUSHNONVOL, registerr14 09: PUSHNONVOL, registerr13 07: PUSHNONVOL, registerr12 05: PUSHNONVOL, registerrdi 04: PUSHNONVOL, registerrsi Handler: 0020ADF0 CxxFrameHandler3 EH Handler Daten: 007B3F54 Ill in das bekommen, was das alles bedeutet in Kürze . Hinweis: Die dumpbin. exe-Funktionalität wird auch über den Linker verfügbar gemacht. Beispielsweise ist der Befehl dumpbin. exe / identisch mit link. exe / dump /. Im Debugger finden Sie dieselben Informationen für eine bestimmte Funktion mit dem Befehl. fnent. Um zu demonstrieren, führte ich den Beispielcode innerhalb einer windbg-Instanz aus und brach an einem beliebigen Punkt ein und wählte eines der Threads aus, um zu sehen, welches einen Stapel wie folgt hat: 12 Id: f80.7f0 Suspend: 1 Teb: 000007fffffa0000 Unfrozen Child-SP RetAddr Aufrufort 00 0000000004a51e18 000007fefd4e10ac ntdllNtWaitForSingleObject0xa 01 0000000004a51e20 000007fef48bffc7 KERNELBASEWaitForSingleObjectEx0x79 02 0000000004a51ec0 000007fef48bff70 clrCLREvent :: WaitEx0x170 03 0000000004a51f00 000007fef48bfe23 clrCLREvent :: WaitEx0xf8 04 0000000004a51f60 000007fef48d51d8 clrCLREvent :: WaitEx0x5e 05 0000000004a52000 000007fef4995249 clrSVR :: gcheap :: waitforgcdone0x98 06 0000000004a52030 000007fef48aef28 clrSVR: : GCHeap :: 07 Alloc0xb4 0000000004a520a0 000007fef48aecc9 clrFastAllocatePrimitiveArray0xc5 08 0000000004a52120 000007fef071244c clrJITNewArr10x389 09 0000000004a522f0 000007fef07111b5 SystemNumericsni0x2244c 0a 0000000004a52330 000007ff00150acf SystemNumericsni0x211b5 0b 0000000004a523d0 000007ff0015098c 0x7ff00150acf 0c 0000000004a52580 000007ff0015098c 0x7ff0015098c 0T 0000000004a52730 000007ff0015098c 0x7ff0015098c 0E 0000000004a528e0 000007ff0015098c 0x7ff0015098c 0f 0000000004a52a90 000007ff0015098c 0x7ff0015098c 10 0000000004a52c40 000007ff0015098c 0x7ff0015098c 11 0000000004a52df0 000007ff0015098c 0x7ff0015098c 12 0000000004a52fa0 000007ff0015098c 0x7ff0015098c 13 0000000004a53150 000007ff0015098c 0x7ff0015098c auf den ersten Blick mag es scheinen, dass dieser Stapel bereits weggeworfen wird, da es keine Symbolinformationen für den unteren Rahmen im Display angezeigt wird. Bevor Sie zu dieser Schlussfolgerung springen, erinnern Sie sich, dass es sich um eine verwaltete Anwendung handelt und daher JIT-kompilierten Code enthält. Um zu überprüfen, dass die Adressen ohne Symbolinformationen JITed Code sind, können Sie ein paar Dinge tun. Verwenden Sie zuerst die EEHeap-Erweiterung in der SOS-Erweiterung, um festzustellen, ob sich diese Adressen im JIT-Code-Heap befinden. Unten können Sie die Befehle sehe ich verwendet, um sowohl die SOS-Erweiterung laden und dann die Execution Engine angezeigt werden (EE) Heap Informationen: 0: 014gt. loadby sos clr 0: 014gt EEHeap - Loader Loader Heap: 8212821282128212821282128212821282128212821282128211 System-Domain: 000007fef50955a0 LowFrequencyHeap: 000007ff00020000 (2000: 1000) Größe: 0x1000 (4096) Byte. HighFrequencyHeap: 000007ff00022000 (8000: 1000) Größe: 0x1000 (4096) Byte. StubHeap: 000007ff0002a000 (2000: 2000) Größe: 0x2000 (8192) Bytes. Virtueller Anruf Stub Heap: IndcellHeap: 000007ff000d0000 (6000: 1000) Größe: 0x1000 (4096) Byte. LookupHeap: 000007ff000dc000 (4000: 1000) Größe: 0x1000 (4096) Byte. ResolveHeap: 000007ff00106000 (3a000: 1000) Größe: 0x1000 (4096) Bytes. DispatchHeap: 000007ff000e0000 (26000: 1000) Größe: 0x1000 (4096) Bytes. CacheEntryHeap: Größe: 0x0 (0) bytes. Gesamte Größe: Größe: 0x8000 (32768) Bytes. 8212821282128212821282128212821282128212821282128211 Shared-Domain: 000007fef5095040 LowFrequencyHeap: 000007ff00020000 (2000: 1000) Größe: 0x1000 (4096) Bytes. HighFrequencyHeap: 000007ff00022000 (8000: 1000) Größe: 0x1000 (4096) Byte. StubHeap: 000007ff0002a000 (2000: 2000) Größe: 0x2000 (8192) Bytes. Virtueller Anruf Stub Heap: IndcellHeap: 000007ff000d0000 (6000: 1000) Größe: 0x1000 (4096) Byte. LookupHeap: 000007ff000dc000 (4000: 1000) Größe: 0x1000 (4096) Byte. ResolveHeap: 000007ff00106000 (3a000: 1000) Größe: 0x1000 (4096) Byte. DispatchHeap: 000007ff000e0000 (26000: 1000) Größe: 0x1000 (4096) Bytes. CacheEntryHeap: Größe: 0x0 (0) bytes. Gesamte Größe: Größe: 0x8000 (32768) Bytes. 8212821282128212821282128212821282128212821282128211 Domain 1: 00000000003e73c0 LowFrequencyHeap: 000007ff00030000 (2000: 1000) 000007ff00140000 (10000: 5000) Größe: 0x6000 (24576) Bytes insgesamt, 0x1000 (4096) verschwendet Bytes. HighFrequencyHeap: 000007ff00032000 (8000: 5000) Größe: 0x5000 (20480) Byte. StubHeap: Größe: 0x0 (0) bytes. Virtueller Anruf Stub Heap: IndcellHeap: 000007ff00040000 (4000: 1000) Größe: 0x1000 (4096) Byte. LookupHeap: 000007ff0004b000 (2000: 1000) Größe: 0x1000 (4096) Byte. ResolveHeap: 000007ff0007c000 (54000: 1000) Größe: 0x1000 (4096) Byte. DispatchHeap: 000007ff0004d000 (2f000: 1000) Größe: 0x1000 (4096) Byte. CacheEntryHeap: Größe: 0x0 (0) bytes. Gesamtgröße: Größe: 0xf000 (61440) Bytes gesamt, 0x1000 (4096) Bytes verschwendet. 8212821282128212821282128212821282128212821282128211 Jit-Code-Haufen: LoaderCodeHeap: 000007ff00150000 (40000: 2000) Größe: 0x2000 (8192) Byte. Gesamtgröße: Größe: 0x2000 (8192) Bytes. 8212821282128212821282128212821282128212821282128211 Modul Thunk-Heaps: Modul 000007fee5581000: Größe: 0x0 (0) Byte. Modul 000007ff000330d8: Größe: 0x0 (0) Bytes. Modul 000007fef06f1000: Größe: 0x0 (0) bytes. Gesamte Größe: Größe: 0x0 (0) bytes. 8212821282128212821282128212821282128212821282128211 Modul-Lookup-Tabellenhaufen: Modul 000007fee5581000: Größe: 0x0 (0) Byte. Modul 000007ff000330d8: Größe: 0x0 (0) Bytes. Modul 000007fef06f1000: Größe: 0x0 (0) bytes. Gesamte Größe: Größe: 0x0 (0) bytes. 8212821282128212821282128212821282128212821282128211 Gesamt LoaderHeap Größe: Größe: 0x21000 (135168) Bytes insgesamt, 0x1000 (4096) Bytes verschwendet. Ich habe die JIT-Heap-Informationen hervorgehoben und Sie können sehen, dass die JITed-Codebefehlszeiger im Stack in diesen Bereich fallen. Die zweite Plausibiltätsprüfung Sie können ausführen ist eine Variante des u-Befehl zu verwenden, um zu bestätigen, dass es einen Call-Befehl an die Adresse unmittelbar vor ist wie folgt: 0: 012gt ub 0x7ff0015098c 000007ff0015095e 488b01 mov rax, qword ptr rcx 000007ff00150961 48898424b0000000 mov qword ptr rsp0B0h, rax 000007ff00150969 488b4108 mov rax, qword ptr rcx8 000007ff0015096d 48898424b8000000 mov qword ptr rsp0B8h, rax 000007ff00150975 4c8d8424b0000000 lea r8, rsp0B0h 000007ff0015097d 488b5308 mov rdx, qword ptr rbx8 000007ff00150981 488d8c24c0000000 lea RCX, rsp0C0h 000007ff00150989 ff5318 nennen qword ptr rbx18h So an diesem Punkt Haben wir verifiziert, dass wir wahrscheinlich einen gültigen Stack haben. Aber wie funktioniert der Debugger so effektiv zu Fuß diesen Stack für uns, wenn es keinen Stack Frame-Zeiger Die Antwort ist natürlich, dass es die Abwicklung Informationen verwendet. Um die Antwort auf diese Frage zu erforschen, konzentriert man sich auf einen bestimmten Rahmen innerhalb des Stapels wie Rahmen 4 im Stapel oben. Der Code in diesem Rahmen ist innerhalb der Funktion clrCLREvent :: WaitEx, und wenn wir das. fnent passieren, erhalten wir die folgende Ausgabe: 0: 012gt. fnent clrCLREvent :: WaitEx Debugger Funktion Eintrag 0000000004075e40 für: (000007fef48bfdb0) clrCLREvent :: WaitEx (000007fef48bfe3c) clrCLREvent :: Set exakte Treffer: clrCLREvent :: WaitEx LTNO Typ informationgt BeginAddress 00000000000dfdb0 Endadresse 00000000000dfe3c UnwindInfoAddress 00000000007267d8 Entspannen Infos bei 000007fef4f067d8. 20 Byte Version 1, Flaggen 2, prolog 20, Codes ein Rahmen reg 0, Frame-offs 0-Handler-Routine: clrCxxFrameHandler3 (000007fef49eadf0), Daten 7b3f54 00: offs 20, entspannen op 4, op info 5 UWOPSAVENONVOL FrameOffset: b0 02: offs 1c entspannen, op 4, op info 3 UWOPSAVENONVOL FrameOffset: a8 04: offs f entspannen op 2, op info d UWOPALLOCSMALL 05: offs b, entspannen op 0, op info e UWOPPUSHNONVOL 06: offs 9, entspannen op 0, op info d UWOPPUSHNONVOL 07: offs 7, entspannen op 0, op info c UWOPPUSHNONVOL 08: offs 5, entspannen op 0, op info 7 UWOPPUSHNONVOL 09: offs 4, entspannen op 0, op info 6 UWOPPUSHNONVOL Beachten Sie, dass dieser Ausgang mit dem gleichen nahezu identisch ist Informationen, die von dumpbin mit der Option / UNWINDINFO bereitgestellt werden. Ich habe zwei interessante Werte oben hervorgehoben. Der grün hervorgehobene Wert ist eine relative virtuelle Adresse (RVA) für die Abwicklungsinformation, die vom Linker in die PE-Datei gebacken wird. Der gelb hinterlegte Wert ist die tatsächliche virtuelle Adresse der Abwicklungsinformation und kann durch Hinzufügen der unten gezeigten Modulbasisadresse zum RVA für UnwindInfoAddress berechnet werden. 0: 012gt lmnm cLr Ende Modulname 000007fef47e0000 000007fef5145000 clr Durch die Untersuchung der PE-Header AVW beginnen können Sie bestätigen, dass die Abroll Informationen im. rdata Abschnitt des Moduls befindet, die ich weiter unten gezeigt haben: Dateityp: DLL-Datei-Header WERTE 8664 Maschine (X64) 6 Anzahl der Abschnitte 4BA21EEB Zeit Datumsstempel Do 18. März 2010 07.39.07 ltsnipgt SECTION HEADER 2.rdata Name 1FC8EC virtuelle Größe 67F000 virtuelle Adresse 1FCA00 Größe der Rohdaten 67E200 Dateizeiger auf Rohdaten 0 Dateizeiger auf Relocation Tabelle 0 Datei Zeiger auf Zeilennummern 0 Anzahl Umzüge 0 Anzahl Zeilennummern 40000040 Flags Initialisierte Daten (keine Ausrichtung angegeben) Read Only ltsnipgt Verwenden der Abwickelinformation Nun können Sie einen Blick auf die Abwicklungsinformationen werfen und sie mit dem Prolog-Code des Funktion, mit der es assoziiert ist. Der Einfachheit halber habe ich die. fnent Ausgang für die Funktion neu aufgelegt: 0: 012gt. fnent clrCLREvent :: WaitEx Debugger Funktion Eintrag 0000000004075e40 für: (000007fef48bfdb0) clrCLREvent :: WaitEx (000007fef48bfe3c) clrCLREvent :: Set exakte Treffer: clrCLREvent :: WaitEx LTNO Typ informationgt BeginAddress 00000000000dfdb0 Endadresse 00000000000dfe3c UnwindInfoAddress 00000000007267d8 entspannen Infos bei 000007fef4f067d8, 20 Byte Version 1, Flaggen 2, Prologs 20. Codes ein Rahmen reg 0, Frame-offs 0-Handler-Routine: clrCxxFrameHandler3 (000007fef49eadf0), Daten 7b3f54 00: offs 20, entspannen op 4, op info 5 UWOPSAVENONVOL FrameOffset: b0 02: offs 1c, entspannen op 4, op info 3 UWOPSAVENONVOL FrameOffset: a8 04: offs f entspannen op 2, op info d UWOPALLOCSMALL 05: offs b, entspannen op 0, op info e UWOPPUSHNONVOL 06: offs 9, entspannen op 0, op info d UWOPPUSHNONVOL 07: offs 7, entspannen op 0, op info c UWOPPUSHNONVOL 08: offs 5, entspannen op 0, op info 7 UWOPPUSHNONVOL 09: offs 4, entspannen op 0, Op info 6 UWOPPUSHNONVOL Der gelbe markierte Wert gibt an, dass der Prolog-Code für die Funktion 0x20 Byte lang ist. Mit Hilfe dieser Informationen können wir den Prolog-Code für die Funktion auskippen: 0: 012gt u clrCLREvent :: WaitEx clrCLREvent :: WaitEx 20 clrCLREvent :: WaitEx: 000007fef48bfdb0 488bc4 mov rax, rsp 000007fef48bfdb3 56 Push rsi 000007fef48bfdb4 57 Push rdi 000007fef48bfdb5 4154 Push-r12 000007fef48bfdb7 4155 Push r13 000007fef48bfdb9 4156 Push r14 000007fef48bfdbb 4883ec70 sub rsp, 70h 000007fef48bfdbf 48c7442440feffffff mov qword ptr rsp40h, 0FFFFFFFFFFFFFFFEh 000007fef48bfdc8 48.895.810 mov qword ptr rax10h, RBX 000007fef48bfdcc 48.896.818 mov qword ptr rax18h wird RBP die Liste der Operationen in der Abroll Info in der aufgeführten Umgekehrte Reihenfolge der Vorgänge im Baugruppencode. Jede der UWOPPUSHNONVOL-Operationen in der Abwicklungsinformation wird einem nichtflüchtigen Register zugewiesen, das zum sicheren Aufbewahren in dem Prolog-Code auf den Stapel gedrückt wird. Ich habe die Abschnitte innerhalb des Prologs und der. fnent-Ausgabe hervorgehoben, sodass das Hervorheben mit ähnlichen Farben entsprechende Informationen anzeigt. Nun können wir einen Blick auf die Roh-Stack und binden alle diese Informationen zusammen. Unten ist der Stapel mit dem Rahmen wir auf gelb markiert konzentrieren: 0: 012gt kn Child-SP RetAddr Aufrufort 00 0000000004a51e18 000007fefd4e10ac ntdllNtWaitForSingleObject0xa 01 0000000004a51e20 000007fef48bffc7 KERNELBASEWaitForSingleObjectEx0x79 02 0000000004a51ec0 000007fef48bff70 clrCLREvent :: WaitEx0x170 03 0000000004a51f00 000007fef48bfe23 clrCLREvent :: WaitEx0xf8 04 0000000004a51f60 000007fef48d51d8 clrCLREvent :: WaitEx0x5e 05 0000000004a52000 000007fef4995249 clrSVR :: gcheap :: waitforgcdone0x98 06 0000000004a52030 000007fef48aef28 clrSVR :: GCHeap :: Alloc0xb4 07 0000000004a520a0 000007fef48aecc9 clrFastAllocatePrimitiveArray0xc5 08 0000000004a52120 000007fef071244c clrJITNewArr10x389 09 0000000004a522f0 000007fef07111b5 SystemNumericsni0x2244c 0a 0000000004a52330 000007ff00150acf SystemNumericsni0x211b5 0b 0000000004a523d0 000007ff0015098c 0x7ff00150acf 0c 0000000004a52580 000007ff0015098c 0x7ff0015098c 0T 0000000004a52730 000007ff0015098c 0x7ff0015098c 0E 0000000004a528e0 000007ff0015098c 0x7ff0015098c 0f 0000000004a52a90 000007ff0015098c 0x7ff0015098c 10 0000000004a52c40 000007ff0015098c 0x7ff0015098c 11 0000000004a52df0 000007ff0015098c 0x7ff0015098c 12 0000000004a52fa0 000007ff0015098c 0x7ff0015098c 13 0000000004a53150 000007ff0015098c 0x7ff0015098c Hinweis: Die Symbole oben schauen ein wenig seltsam und kann Sie führen zu glauben, dass WaitEx selbst rekursiv aufruft, aber es ist nicht. Es erscheint nur so, weil Sie die privaten Symbole für clr. dll benötigen, um den wirklichen Funktionsnamen sehen zu können. Nur öffentliche Symbole sind außerhalb von Microsoft verfügbar. Und unten ist die rohe Stapel relevant zu dieser Rahmen mit einigen Hervorhebung und Anmerkungen, die ich hinzugefügt haben: 0: 012gt dps 0000000004a51f60-10 L20 0000000004a51f50 0000000000000001 0000000004a51f58 000007fef48bfe23 clrCLREvent :: WaitEx0x5e 0000000004a51f60 00000000c0402388 0000000004a51f68 00000000c0402500 0000000004a51f70 000007fef48afaf0 clrSystemNative :: ArrayCopy 0000000004a51f78 0000000000000182 0000000004a51f80 0000000004a521d0 0000000004a51f88 000007fe00000001 0000000004a51f90 0000000000000057 0000000004a51f98 00000000c0402398 0000000004a51fa0 fffffffffffffffe 0000000004a51fa8 007f000004a521d0 0000000004a51fb0 fffff880009ca540 0000000004a51fb8 000007fef483da5b clrSVR :: heapselect :: selectheap0x1c 0000000004a51fc0 fffff880009ca540 0000000004a51fc8 000007fefd4e18aa KERNELBASEResetEvent0xa 0000000004a51fd0 000000000043dc60 0000000004a51fd8 0000000000000178 0000000004a51fe0 0000000000493c10 0000000004a51fe8 000000000043dc60 gespeichert rdi 0000000004a51ff0 0000000000000001 Anruf in clrCLREvent :: WaitEx 0000000004a51ff8 000007fef48d51d8 clrSVR :: gcheap :: waitforgcdone0x98 0000000004a52000 0000000000493ba0 0000000004a52008 0000000000493ba0 gespeichert RBX 0000000004a52010 0000000000000058 gespeichert rbp 0000000004a52018 000007fef0711e0f SystemNumericsni0x21e0f 0000000004a52020 0000000000000178 0000000004a52028 000007fef4995249 clrSVR :: GCHeap :: Alloc0xb4 0000000004a52030 000000000043a140 0000000004a52038 000000000043dc60 0000000004a52040 0000000000000000 0000000004a52048 0000000004a522e0 In dem Stapel Auflistung ich die gleiche Farbe hervorgehoben Schema verwendet haben wie zuvor Zeigen, wie die Daten auf dem Rohstapel mit den Abwicklungsdaten korrelieren. Und mit grüner Hervorhebung habe ich gezeigt, wie der Child-SP-Wert mit dem Stack-Frame korreliert. Die Cyan-Hervorhebung stellt nichtflüchtige Register dar, die im Prolog-Code auf den Stapel gedrückt werden. Die blaue Markierung stellt den Stapelplatz dar, der für Einheimische reserviert ist, und für den Registerhomeplatz, der für das Aufrufen von Subroutinen reserviert ist. In den Abwicklungsdaten wird die Stapelreservierung durch eine UWOPALLOCSMALL-Operation repräsentiert. Und die rote Hervorhebung repräsentiert nichtflüchtige Register, die im Heimatraum des vorherigen Stapelrahmens gespeichert sind und durch eine in den Abwicklungsinformationen gespeicherte UWOPSAVENONVOL-Operation dargestellt werden. Wie Sie sehen können, haben wir alle Informationen, die wir in den Abwicklungsdaten benötigen, um zu bestimmen, welche Slots auf dem Stack für was verwendet werden. Die einzige Sache, die wir nicht kennen, ist die Partitionierung des reservierten Stapelplatzes für Einheimische, die durch die private Symbolinformation für das clr. dll-Modul beschrieben wird. Zusammenfügen fnent produziert seine Ausgabe direkt aus der Analyse der Definition der UNWINDINFO-Struktur und es gibt Ihnen sogar die Adresse, wo diese Struktur im Speicher lebt. Die UNWINDINFO-Struktur enthält auch eine variable Menge von UNWINDCODE-Strukturen. Details zu den Strukturdefinitionen für UNWINDINFO und UNWINDCODE finden Sie hier. Jede analysierte Zeile der Abwicklungsinformationen in der. fnent-Ausgabe wird durch mindestens eine dieser Strukturen unterstützt. In der Tat sehen Sie die Korrelation zwischen den Strukturfeldern für UNWINDINFO und den Daten in der. fnent-Ausgabe wie unten gezeigt: Daher repräsentiert die vorherige Zeile aus dem. fnent-Ausgang eine Push-Operation für das r14-Register (05: offs b, Entspannen Sie sich auf 0, op info e UWOPPUSHNONVOL). Betrachten wir die obige Anordnung, so sehen wir, dass die oberste UWOPPUSHNONVOL-Operation in der. fnent-Ausgabe mit dem letzten nichtflüchtigen Register-Push im Prolog-Code korreliert (push r14). Hinweis: Denken Sie daran, dass die Push-Operationen in der. fnent-Ausgabe in umgekehrter Reihenfolge angezeigt werden, wo sie sich im aktuellen Prolog-Code befinden. Dies hilft dem Abwicklungscode leicht zu berechnen Offsets, wo sie im Stapel leben sollte. Eine Sache, die Sie in der x64 aufrufenden Konvention feststellen, ist, dass, sobald der Prolog-Code ausgeführt hat, der Wert für rsp sehr selten ändern wird. Der Child-SP-Wert in dem Stapel, der durch die k-Befehle angezeigt wird, ist der Wert von rsp für diesen Rahmen, nachdem der Prolog-Code ausgeführt wurde. Somit werden die Offsets, um auf diese nichtflüchtigen Register zuzugreifen, dann auf den Child-SP-Wert (vorher grün markiert) angewendet, um zu finden, wo sie auf dem Stack leben. So, in einer Weise, der Child-SP-Wert fungiert wie der Basis-Pointer wir auf der x86-Plattform verwendet werden. In der. fnent Ausgabe oben, werden Sie auch folgende sehen: 00: 20 Starts, entspannen op 4, op info 5 UWOPSAVENONVOL FrameOffset: b0 Für UWOPSAVENONVOL, sehen Sie, dass die. fnent Ausgabe zeigt uns den Offset, wo wir dieses Register finden , Und das betreffende Register wird durch den OpInfo-Wert repräsentiert, der rbp entspricht. Der obige Offset wird auf den Child-SP-Wert (0000000004a51f60 in diesem Fall) angewendet, um die Adresse 0000000004a52010 zu erzeugen, die anzeigt, woher wir eine gespeicherte Kopie von rbp finden. Ich habe auch annotiert, wo es lebt in der Roh-Stack-Ausgabe gezeigt. Hinweis: Wenn Sie sich fragen, warum rbp im vorherigen Stack-Frame gespeichert ist, lesen Sie in meinem vorherigen Beitrag zu diesem Thema, wo ich beschreiben, wie in optimierten Builds, kann der Compiler die Home Space aus dem vorherigen Stack Frame verwenden, um nichtflüchtige Register speichern und so speichern Mit einer MOV-Operation im Gegensatz zu einer PUSH-Operation. Dies ist möglich, weil bei optimierten Builds der Home Space nicht notwendigerweise zum Speichern von Parametern verwendet wird. So wie alle diese Arbeit für CLR JIT-Code Wenn Sie diese Frage gestellt haben, dann sind Sie definitiv Aufmerksamkeit Wie wir gezeigt haben, sind der Compiler und Linker verantwortlich für die Abwicklung Abwicklung info in der Portable Executable-Datei zum Zeitpunkt der Erstellung. Aber was ist mit dynamischen Code, der zur Laufzeit generiert wird sicherlich müssen es Abwicklung Informationen für dynamisch kompilierten Code als gut, sonst wäre es keine Möglichkeit, den Stapel zu gehen oder entspannen Sie den Stapel nach einer Ausnahme. Wie sich herausstellt, gibt es APIs für diese Situation, einschließlich RtlAddFunctionTable und RtlInstallFunctionTableCallback. In der Tat verwendet die CLR RtlInstallFunctionTableCallback. Die erzeugten Abwicklungsinformationen werden dann in einer verknüpften Liste verwurzelt, in der sich der Kopf auf ntdllRtlpDynamicFunctionTable befindet. Das Format der verknüpften Listenelemente ist undokumentiert, da es ein Implementierungsdetails ist, aber mit dbghelp. dll finden Sie die Abwicklungsinformationen für einen gegebenen Befehlszeiger, wenn Sie dies wünschen, indem Sie SymFunctionTableAccess64 aufrufen. In der Tat, wenn Sie sehen möchten, die CLR Hinzufügen dynamischer Abwicklung info in Aktion können Sie den Test-Code oben unter dem Debugger und dann am Anfang Breakpoint, bevor die Anwendung gestartet wird, setzen Sie den folgenden Haltepunkt: Wenn Sie die Anwendung lassen Sie laufen sollte dann mit einem Call-Stack an den Haltepunkt am Ende, das wie folgt aussieht, die den JIT-Compiler Hinzufügen der Abroller Info an den Tisch zeigt deutlich, dynamisch: 0: 000gt kn Child-SP RetAddr Aufrufort 00 000000000017dca8 000007fef4832cc6 ntdllRtlInstallFunctionTableCallback 01 000000000017dcb0 000007fef4831422 clrInstallEEFunctionTable0x77 02 000000000017df60 000007fef4828ca8 clrStubLinker :: EmitUnwindInfo0x492 03 000000000017e050 000007fef4832c1a clrStubLinker :: EmitStub0xe8 04 000000000017e0b0 000007fef48328e5 clrStubLinker :: LinkInterceptor0x1ea 05 000000000017e160 000007fef4831e40 clrCTPMethodTable :: CreateStubForNonVirtualMethod0xa35 06 000000000017e300 000007fef4832926 clrCRemotingServices :: GetStubForNonVirtualMethod0x50 07 000000000017e3c0 000007fef48223f3 clrMethodDesc :: DoPrestub0x38b 08 000000000017e4d0 000007fef47e2d07 clrPreStubWorker0x1df 09 000000000017e590 000007fef48210b4 clrThePreStubAMD640x87 0a 000000000017e660 000007fef48211c9 clrCallDescrWorker0x84 0b 000000000017e6d0 000007fef4821245 clrCallDescrWorkerWithHandler0xa9 0c 000000000017e750 000007fef4823cf1 clrMethodDesc :: CallDescr0x2a1 0T 000000000017e9b0 000007fef49cdc3d clrMethodDescCallSite :: Call0x35 0E 000000000017e9f0 000007fef4999f0d clrAppDomain :: InitializeDomainContext0x1ac 0f 000000000017ebf0 000007fef49212a1 clrSystemDomain :: 10 InitializeDefaultDomain0x13d 000000000017f0c0 000007fef4923dd6 clrSystemDomain :: ExecuteMainMethod0x191 11 000000000017f670 000007fef4923cf3 clrExecuteEXE0x43 12 000000000017f6d0 000007fef49a7365 clrCorExeMainInternal0xc4 13 000000000017f740 000007fef8ad3309 clrCorExeMain0x15 Aber es gibt noch eine Falte zu diesem Bild. Wir wissen jetzt, dass mit der Verwendung von RtlInstallFunctionTableCallback die CLR oder eine andere JIT-Engine einen Rückruf registrieren kann, der zur Laufzeit die Abwicklungsinformationen bereitstellt. Aber wie greift der Debugger auf diese Informationen zu Wenn der Debugger in den Prozess eingebrochen ist oder wenn Sie einen Dump debuggen, kann er die Callback-Funktion, die mit RtlInstallFunctionTableCallback registriert ist, nicht ausführen. Hier kommt der sechste und letzte Parameter von RtlInstallFunctionTableCallback ins Spiel. Durch Bereitstellen des Parameters OutOfProcessCallbackDll stellt die CLR eine DLL bereit, die der Debugger verwenden kann, um die JITS-Informationen statisch zu entschlüsseln. Bei der Prüfung, welchen Weg geht die CLR für OutOfProcessCallbackDll auf meinem Rechner, sehe ich die folgende Zeichenfolge: 0: 000gt du / c 80 000007fef5916160 000007fef5916160 8220C: WindowsMicrosoft. NETFramework64v4.0.30319 8220 Mscordacwks. dll So ist der Debugger verwendet Mscordacwks. dll statisch zu untersuchen Die Abwicklungsinformationen, während der Prozess in dem Debugger unterbrochen wird, oder während ein Dump geprüft wird. Hinweis: Dies ist einer der vielen Gründe, weshalb Sie einen vollständigen Prozess-Dump zur effektiven Post-Mortem-Debug-verwalteten Anwendungen benötigen. Verwenden des Befehls k zum Dump des Stacks Wenn Sie sich die Dokumentation für den Befehl k ansehen, sehen Sie, dass es eine Möglichkeit gibt, den Basiszeiger beim Gehen des Stapels zu überschreiben. Allerdings lässt die Dokumentation es ein komplettes Mysterium, wie man diese Anwendung in der x64-Welt. To demonstrate what I mean, consider the following stack from earlier: 0:012gt kn Child-SP RetAddr Call Site 00 0000000004a51e18 000007fefd4e10ac ntdllNtWaitForSingleObject0xa 01 0000000004a51e20 000007fef48bffc7 KERNELBASEWaitForSingleObjectEx0x79 02 0000000004a51ec0 000007fef48bff70 clrCLREvent::WaitEx0x170 03 0000000004a51f00 000007fef48bfe23 clrCLREvent::WaitEx0xf8 04 0000000004a51f60 000007fef48d51d8 clrCLREvent::WaitEx0x5e 05 0000000004a52000 000007fef4995249 clrSVR::gcheap::waitforgcdone0x98 06 0000000004a52030 000007fef48aef28 clrSVR::GCHeap::Alloc0xb4 07 0000000004a520a0 000007fef48aecc9 clrFastAllocatePrimitiveArray0xc5 08 0000000004a52120 000007fef071244c clrJITNewArr10x389 09 0000000004a522f0 000007fef07111b5 SystemNumericsni0x2244c 0a 0000000004a52330 000007ff00150acf SystemNumericsni0x211b5 0b 0000000004a523d0 000007ff0015098c 0x7ff00150acf 0c 0000000004a52580 000007ff0015098c 0x7ff0015098c 0d 0000000004a52730 000007ff0015098c 0x7ff0015098c 0e 0000000004a528e0 000007ff0015098c 0x7ff0015098c 0f 0000000004a52a90 000007ff0015098c 0x7ff0015098c 10 0000000004a52c40 000007ff0015098c 0x7ff0015098c 11 0000000004a52df0 000007ff0015098c 0x7ff0015098c 12 0000000004a52fa0 000007ff0015098c 0x7ff0015098c 13 0000000004a53150 000007ff0015098c 0x7ff0015098c Now, imagine the top of the stack is corrupted, which I have simulated by blacking out the top few frames in this stack dump. Furthermore, lets assume that we identified a frame where the stack starts to look sane again by looking at the raw stack below: 0:012gt dps 0000000004a51e90 0000000004a51e90 0000000000000000 0000000004a51e98 0000000004a52130 0000000004a51ea0 00000000ffffffff 0000000004a51ea8 00000000ffffffff 0000000004a51eb0 0000000000000108 0000000004a51eb8 000007fef48bffc7 clrCLREvent::WaitEx0x170 0000000004a51ec0 0000000000000000 0000000004a51ec8 0000000000000108 0000000004a51ed0 000007fe00000000 0000000004a51ed8 0000000000000108 0000000004a51ee0 fffffffffffffffe 0000000004a51ee8 0000000000000001 0000000004a51ef0 0000000000000000 0000000004a51ef8 000007fef48bff70 clrCLREvent::WaitEx0xf8 0000000004a51f00 0000000000000000 0000000004a51f08 0000000000493ba0 From looking at this stack, we can see the typical pattern of stack frames because the return addresses resolve to symbols of sorts. To dump out the corrupted stack, here is the undocumented syntax for the x64 platform: k ltrspgt ltripgt ltframecountgt ltrspgt is the stack pointer to start with. You want to use the stack pointer that would have been in rsp when that function was active. Remember, typically rsp does not change after the function prolog code completes. Therefore, if you pick the stack pointer just below the return address, you should be good. ltripgt should be an instruction pointer from within the function that was executing at the time the ltrspgt value above was in play. In this case, the return address directly above ltrspgt comes from that function and I have highlighted it in green. This piece of information is critical so that the debugger can find the unwind metadata for the function that was current at this point in the stack. Without it, the debugger cannot walk the stack. Armed with this information, you can construct a k command to dump the stack starting from this frame as shown below: 0:012gt kn 0000000004a51ec0 000007fef48bffc7 10 Child-SP RetAddr Call Site 00 0000000004a51ec0 000007fef48bff70 clrCLREvent::WaitEx0x170 01 0000000004a51f00 000007fef48bfe23 clrCLREvent::WaitEx0xf8 02 0000000004a51f60 000007fef48d51d8 clrCLREvent::WaitEx0x5e 03 0000000004a52000 000007fef4995249 clrSVR::gcheap::waitforgcdone0x98 04 0000000004a52030 000007fef48aef28 clrSVR::GCHeap::Alloc0xb4 05 0000000004a520a0 000007fef48aecc9 clrFastAllocatePrimitiveArray0xc5 06 0000000004a52120 000007fef071244c clrJITNewArr10x389 07 0000000004a522f0 000007fef07111b5 SystemNumericsni0x2244c 08 0000000004a52330 000007ff00150acf SystemNumericsni0x211b5 09 0000000004a523d0 000007ff0015098c 0x7ff00150acf 0a 0000000004a52580 000007ff0015098c 0x7ff0015098c 0b 0000000004a52730 000007ff0015098c 0x7ff0015098c 0c 0000000004a528e0 000007ff0015098c 0x7ff0015098c 0d 0000000004a52a90 000007ff0015098c 0x7ff0015098c 0e 0000000004a52c40 000007ff0015098c 0x7ff0015098c 0f 0000000004a52df0 000007ff0015098c 0x7ff0015098c Note: The frame count in the above k expression is required. That is the way the debugger engine distinguishes between this variant of the command (with an overridden rip) and the documented form of k that does not provide an overridden rip. Conclusion Since the x64 calling convention does not utilize a base pointer (among other things), we need some extra information to effectively walk the stack. That extra information comes in the form of unwind metadata and is generated by the compiler and linker for static code and baked into the portable executable file. If you happen to code in assembly language, there are various macros that you must use to decorate your assembly code so that the assembler can generate the proper unwind metadata. For dynamically compiled code, that information is instead provided at runtime by registering a callback with the system. Knowing this information is critical if you encounter a corrupted stack and must piece it together manually. In such situations youll need to know how to dig out the unwind metadata manually and use it to effectively reconstruct the call stack. That said, you could spare yourself some effort and use the undocumented variant of the k command described above to dump the stack starting at any frame. J Happy debugging everyone 8220The example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, places, or events is intended or should be inferred.8221

No comments:

Post a Comment