Time Travel Debugging ── تسجيل الأخطاء التي لا تتكرّر في التطبيقات طويلة التشغيل وإرجاعها

· آخر تحديث: · · WinDbg, Time Travel Debugging, التصحيح, التحقيق في الأعطال, Windows, تطوير Windows, .NET, C++, الاستشارة التقنيّة

سجل التعديلات (النسخة الأولى، نُشرت في 2 Sep، 2026)
النشر الأول

«ينهار مرّة في الشهر، في منتصف الليل فقط.» «العمليّة نفسها لا تتكرّر على جهازي أبداً.» «حصلنا على تفريغ، لكن النظر إلى موقع الانهيار لا يخبرنا لماذا صار القيمة ما هي.» من بين تحقيقات أخطاء تطبيقات Windows طويلة التشغيل، هذه الحالات تستهلك أكثر الوقت. في مقال سابق، «قراءة ملفّات تفريغ الأعطال بـ WinDbg وSOS»، نظرنا في كيفيّة قراءة تفريغ انهيار، وهو صورة واحدة. يواصل هذا المقال من هناك ويعالج الأداة للحالات التي لا تكفي فيها الصورة: Time Travel Debugging (TTD).

TTD ميزة في WinDbg تسجّل تنفيذ العمليّة كاملاً وتتيح إعادة تشغيله لاحقاً أماماً وخلفاً. بدل المحاولة مرّة بعد مرّة لإعادة إنتاج خطأ، يمكنك «إرجاع» جلسة المصحّح.1 القرّاء المقصودون مطوّرو تطبيقات Windows و.NET وC++ وصائنوها ممّن أنهوا نصيبهم من تحقيق التفريغ والسجلّ وما زالت لديهم حالات لا يصلون إلى سببها الجذري. بيئة المتطلّبات Windows 10/11 أو Windows Server 2016 فما بعد مع WinDbg الحالي، ويلزم التسجيل امتياز المسؤول.12 الصعوبة متوسّطة.

افتراضات هذا المقال

البند المحتوى
القرّاء المقصودون مطوّرو تطبيقات Windows وصائنوها ذوو أخطاء طويلة التشغيل أو متقطّعة لا تصل إليها التفريغات والسجلّات
المعرفة المسبقة خبرة فتح تفريغ في WinDbg وتشغيل !analyze -v أو !clrstack. يُفترض محتوى مقال تحليل SOS
بيئة المتطلّبات Windows 10/11 أو Windows Server 2016/2019/2022/2025، WinDbg (الإصدار الحالي)، TTD.exe، امتياز المسؤول2
خارج النطاق التكامل مع Visual Studio Enterprise Snapshot Debugger؛ وضع النواة (TTD وضع مستخدم فقط3)

1. الخلاصة أوّلاً

  • يحفظ التفريغ «الحالة»؛ ويحفظ TTD «المسار». تنصّ الوثائق الرسميّة على أنّ التفريغات تميل إلى تفويت الحالة ومسار التنفيذ اللذين أدّيا إلى الفشل.1 إذا لم تخبرك صورة لحظة الانهيار بالسبب، فما تحتاجه تالياً ليس مزيداً من الصور بل تسجيلاً.
  • التسجيل ثقيل. أثناء التسجيل تعمل العمليّة المستهدَفة أبطأ من 5 إلى 20 ضعفاً أو أسوأ، وينمو ملف التتبّع بـ 5 إلى 50 ميغابايت في الثانية بينما العمليّة نشطة، بلا سقف.24 ليست أداة تعلّقها بلا شرط على تطبيق طويل التشغيل.
  • للتطبيقات طويلة التشغيل صمّم «ماذا تسجّل». يغطي الفصل 5 نقاط الدخول الأربع التي يوفّرها TTD.exe: -ring/-maxFile (أبقِ آخر N ميغابايت فقط)، و-module (سجّل فقط أثناء تنفيذ وحدتك)، و-recordmode Manual (دع التطبيق يحدّد فاصل التسجيل)، و-monitor (سجّل كلّ إطلاق).2
  • تدور إعادة التشغيل حول ثلاثة أمور: المواضع (!tt)، والأحداث (dx @$curprocess.TTD.Events)، والاستعلامات (TTD.Calls / TTD.Memory). اجمع ba (نقطة توقّف عند الوصول) مع g- (تنفيذ عكسي)، فيجيب المصحّح «من كتب هذه القيمة أخيراً؟» مباشرة.5
  • يحتوي التتبّع محتويات الذاكرة. يمكن أن يشمل معلومات شخصيّة وسرّيّة مثل مسارات الملفّات وبيانات السجلّ ومحتويات الذاكرة والملفّات.1 صمّم المشاركة والتخزين كما لملفّ سرّي.
  • اعرف ما لا يستطيعه TTD قبل أن تبدأ. لا يسجّل وضع النواة، ولا يحقن نفسه في العمليّات المحميّة (PPL)، ولا يفصل نفسه بعد الرفق، ولا يمكن تعديل الذاكرة أثناء إعادة التشغيل.32

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 32، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

2. حيث لا يكفي التفريغ

تفريغ الانهيار نسخة من الذاكرة والسجلّات في لحظة انهيار العمليّة (أو إيقافها). كما وُصف في مقال تحليل SOS، يخبرك !clrstack أين انهار و!dumpheap -stat ما يستهلك الكومة. ما لا يستطيع إخبارك به هو ما حدث في الطريق إلى تلك الحالة.

ما يلتقطه التفريغ وما يلتقطه TTDيلتقط تفريغ الانهيار حالة لحظة الانهيار فقط، لا المسار الذي أدّى إليها. يحتفظ TTD بتنفيذ التعليمات كاملاً من بدء التسجيل إلى نهايته، لذا يُحفَظ المسار مع الحالةتفريغ الانهيار: الحالة في لحظة الانهيارلا يُظهر لماذا صارت القيمة ما هيتتبّع TTD: تنفيذ التعليمات في الفاصل المسجَّليمكن العودة إلى الموضع الذي كُتبت فيه القيمةهذه الفجوة هي ما يطيل تحقيقات التشغيل الطويل

الشكل 1: التفريغ حالة؛ TTD هو المسار. في أخطاء التشغيل الطويل ما تريده عادة هو الأخير.

تبدو الحالات النموذجيّة كهذه.

  • حقل واحد في بنية على الكومة يحمل قيمة مستحيلة. يُظهر التفريغ القيمة الفاسدة، لا من كتبها ولا متى.
  • موضع الاستثناء معروف، لكن ليس لماذا كان الوسيط الممرَّر إليه غير صالح. بالمشي أبعد في المستدعين، لم تعد الدالّة التي أنتجت القيمة في الطريق على المكدّس.
  • تنمو المقابض أو الذاكرة على مدى شهر. تفريغ واحد لا يقول سوى «إنّها تنمو»؛ مسار الاستدعاء الذي أنماها ليس هناك.
ما يفوته التفريغ في حالات التشغيل الطويل النموذجيّةتُلتقَط القيمة الفاسدة لا من كتبها، ويُلتقَط موضع الاستثناء لا الدالّة التي أنتجت الوسيط إذ لم تعد على المكدّس، ويُلتقَط نمو المورد لا المسار الذي أنماه؛ تشترك الأنواع الثلاثة في هذاحقل فاسدلا سجلّ لمن كتبه أو متىاستثناء على وسيط غير صالحالدالّة التي أنتجت القيمة لم تعد على المكدّسمورد ينمو على مدى شهرلا سجلّ لمسار الاستدعاء الذي أنماهنقطة مشتركة: الحالة موجودة، لكن لا مسار

الشكل 2: الحالات الثلاث كلّها لديها «حالة بلا مسار». مزيد من الصور لا يملأ المسار.

تقارن وثائق Microsoft نقاط القوّة والضعف لطرق التحقيق كالتالي.1

الطريقة نقاط القوّة نقاط الضعف
التصحيح الحي تفاعلي، يُظهر تدفّق التنفيذ، ويتيح تغيير الحالة يوقف عمل المستخدم. يتطلّب جهداً لإعادة الإنتاج مراراً. غالباً غير قابل للاستخدام في الإنتاج. يصعب الرجوع من نقطة الفشل إلى السبب
التفريغات لا تغييرات شيفرة مسبقاً. تدخّل منخفض، يمكن جمعها عند محفّز. عبء شبه صفري عند عدم الاستخدام حتى مع لقطات متتالية، رؤية «الزمن المنقضي» خشنة
القياس عن بعد والسجلّات خفيفة. مربوطة بسيناريوهات الأعمال لا سجلّات على مسارات شيفرة غير متوقَّعة. عمق بيانات غير كافٍ، ومضمَّنة ثابتة في الشيفرة
TTD قوي على الأخطاء المعقّدة. لا تغييرات شيفرة مسبقاً. يمكن إعادة التشغيل دون اتّصال أيّ عدد من المرّات ويسجّل كلّ شيء عبء كبير أثناء التسجيل. قد يجمع بيانات أكثر ممّا يلزم. تكبر الملفّات

هناك خاصّيّة مهمّة أخرى يشير إليها الدليل الرسمي لـ TTD. عندما يتوقّف المصحّح عند نقطة الفشل، غالباً ما تكون تلك النقطة داخل شيفرة معالجة أخطاء عدّة خطوات بعد السبب الحقيقي.5 يُؤخَذ التفريغ دائماً في هذا الموضع «بعد عدّة خطوات». مع TTD يمكنك الرجوع من هناك تعليمة تعليمة.

الفجوة بين نقطة الفشل والسبب الحقيقينقطة الفشل التي يُؤخَذ عندها التفريغ غالباً داخل معالجة أخطاء عدّة خطوات بعد السبب الحقيقي، ومع TTD يمكنك الإرجاع من تلك النقطة تعليمة تعليمة إلى السببتفريغTTDالسبب الحقيقي (التعليمات التي أفسدت القيمة)عدّة خطوات إلى الأمامنقطة الفشل (استثناء، معالجة أخطاء)مجمَّد هناارجع بـ p- / t- / g-

الشكل 3: التفريغ مجمَّد عند نقطة الفشل. يستطيع TTD المشي من نقطة الفشل إلى السبب.

3. كيف يعمل TTD وما تكلفته

3.1 ما الذي يُسجَّل

يحقن TTD محرّك تسجيل في العمليّة المستهدَفة ويسجّل التعليمات المنفَّذة، تعليمة تعليمة. بعبارة الوثائق الرسميّة، «يشفّر تتبّعاً كاملاً على مستوى التعليمات بمتوسّط أقلّ من بايت واحد لكلّ تعليمة»؛ عمليّاً يقع بين بت واحد وبايت واحد لكلّ تعليمة. البرامج التي تنفّذ أنواعاً قليلة من الدوال وتعالج بيانات قليلة تنتج تتبّعات أصغر؛ والعكس ينتج أكبر.24

ينتج التسجيل ملفّين.1

الملفّ الدور الحجم التقريبي
.run التتبّع نفسه. يخزّن تنفيذ التعليمات أثناء التسجيل ينمو بـ 5 إلى 50 ميغابايت في الثانية أثناء النشاط. لا ينمو أثناء الخمول4
.idx الفهرس. بيانات مساعدة تتيح لـ WinDbg إعادة التشغيل والاستعلام عن الذاكرة بكفاءة. يُنشأ عند توقّف التسجيل، ويُولَّد أيضاً تلقائيّاً عندما يفتح WinDbg ملف .run 1 إلى 2 ضعف حجم التتبّع4
التدفّق من تسجيل TTD إلى إعادة التشغيليُحقَن محرّك تسجيل في العمليّة المستهدَفة ويُسجَّل تنفيذ التعليمات في ملف ‎.run؛ عندما يفتح WinDbg ملف ‎.run ينشئ فهرس ‎.idx ويعيد التشغيل أماماً وخلفاً باستخدام المواضع والأحداث والاستعلاماتالعمليّة المستهدَفةمحرّك التسجيل محقون (TTDRecordCPU).run (سجلّ تنفيذ التعليمات)افتح في WinDbgولِّد ‎.idx (فهرس)أعد التشغيل أماماً وخلفاً بالمواضع والأحداث والاستعلامات

الشكل 4: التسجيل يتمّ بـ TTD.exe أو WinDbg؛ والقراءة بـ WinDbg. يكفي مشاركة ملف .run وحده.

يُعبَّر عن الزمن داخل ملف .run كـ«موضع». يأخذ شكل رقمين ست عشريّين مفصولين بنقطتين، مثل 12:0 أو 1A0:12F؛ النصف الأوّل رقم التسلسل (يقابل حدث تسلسل) والنصف الثاني العدد التقريبي للتعليمات منذ ذلك الحدث.6 يعني FFFFFFFFFFFFFFFE:0 نهاية التتبّع.7 تحتلّ المواضع مركز الفصل 6.

كيف تُعبَّر المواضع في تتبّعالموضع رقم تسلسل ست عشري وعدد خطوات مفصولان بنقطتين؛ البداية قرب 0، والنهاية تُعبَّر كـ FFFFFFFFFFFFFFFE:0، ويمكنك أيضاً الانتقال إلى موضع تقريبي بالنسبة المئويّةالموضع xx:yy (ست عشري)xx: رقم التسلسلyy: التعليمات منذ ذلك الحدثالنهاية هي FFFFFFFFFFFFFFFE:0تعمل أيضاً نسب مئويّة مثل !tt 50

الشكل 5: الموضع هو «رقم الحدث:عدد التعليمات». ليس زمن ساعة حائط، لكن يمكن تحويله إلى زمن ساعة حائط كما في الفصل 6.

3.2 التكلفة

تصف الوثائق الرسميّة نفسها TTD بأنّه «تقنيّة تدخّليّة».2 إليك التكلفة بالأرقام.

البند المحتوى
السرعة تعمل العمليّة المستهدَفة أبطأ من 5 إلى 20 ضعفاً أو أسوأ أثناء التسجيل (حسب التطبيق وخيارات التسجيل). قد لا يُلاحَظ في واجهة المستخدم، لكنّه محسوس في عمليّات ثقيلة مثل مربع حوار فتح ملفّ23
نمو الملفّ 5 إلى 50 ميغابايت في الثانية أثناء النشاط. دقائق قليلة من التسجيل يمكن أن تبلغ عدّة غيغابايت. لا سقف مضبوط4
نفاد القرص إذا امتلأ القرص أثناء التسجيل، يكتب TTD الصفحة الأخيرة ثمّ ينتظر فعليّاً حتى يستطيع الكتابة مجدّداً. يواصل WinDbg إظهار مربع حوار التسجيل ولا يصدر خطأ ولا تحذيراً. النتيجة تتبّع ناقص4
الذاكرة يضيف التسجيل عبء وحدات CPU افتراضيّة إلى ذاكرة العمليّة المستهدَفة (افتراضيّاً 55 على x64/ARM64، و32 على x86). قلّله بـ -numVCpu فقط عندما تنقص الذاكرة2
لا يمكن الفصل ما إن يُرفَق، لا يستطيع TTD فصل نفسه. عندما تنهي التسجيل أغلق التطبيق أو أنهِ العمليّة. إذا كانت العمليّة أساسيّة للنظام يجب إعادة إقلاع نظام التشغيل2
تكلفة التسجيل وأثرها على التطبيقات طويلة التشغيلالتباطؤ أثناء التسجيل، ونمو الملفّ، والانتظار الصامت عند نفاد القرص، والعجز عن الفصل بعد الرفق هي التكاليف الأربع التي تجعل تعليق TTD بلا شرط على تطبيق طويل التشغيل مستحيلاًتسجيل TTDأبطأ من 5 إلى 20 ضعفاًينمو بـ 5 إلى 50 ميغابايت في الثانية، بلا سقفينتظر بصمت عندما ينفد القرصلا يمكن الفصل بعد الرفقالتسجيل المتواصل بلا شرط غير قابل للتطبيق

الشكل 6: أيّ واحدة من التكاليف الأربع تستبعد التسجيل المتواصل. لذلك يلزم «تصميم التسجيل» في الفصل 5.

3.3 ما لا يستطيعه

  • وضع المستخدم فقط. يمكنه تسجيل تنفيذ وضع المستخدم لعمليّة فقط؛ الشيفرة التي تعمل في وضع النواة، مثل برامج التشغيل، لا يمكن تصحيحها.3
  • العمليّات المحميّة. لا يستطيع TTD حقن نفسه في عمليّات Windows المحميّة مثل Protected Process Light (PPL).3
  • إعادة التشغيل للقراءة فقط. يمكنك العودة في الزمن، لكن لا يمكنك تغيير التاريخ. أوامر قراءة الذاكرة تعمل؛ أوامر تعديلها لا تعمل.3
  • عدم التوافق مع برامج مكافحة الفيروسات ومراقبة الذاكرة. لأنّ TTD يعلّق نفسه في العمليّة، يتعارض مع برمجيّات تتتبّع استدعاءات ذاكرة النظام أو تظلّلها. إذا أنتج التسجيل خطأ يشبه نقص الأذونات، عطِّل تلك البرمجيّات مؤقّتاً لعزل المشكلة. إطار Electron تعارض معروف أيضاً؛ حتى إذا نجح تسجيل قد تدخل العمليّة المستهدَفة في طريق مسدود أو تنهار.3
  • لا يمكن إطلاق تطبيقات UWP وتسجيلها (الرفق بتطبيق UWP قيد التشغيل ممكن). «العمليّات غير المعتادة» التي تعمل في جلسة أخرى أو سياق أمان مختلف غير مدعومة حاليّاً أيضاً.8
ما لا يستطيع TTD تسجيله أو فعلهلا يمكن تسجيل شيفرة وضع النواة والعمليّات المحميّة وتسجيل إطلاق تطبيقات UWP والعمليّات في جلسة أو سياق أمان آخر؛ ولا يمكن تعديل الذاكرة أثناء إعادة التشغيل؛ ويمكن أن تتعارض برامج مكافحة الفيروسات وElectronقيود TTDلا يمكن تسجيلهقيود وتعارضاتشيفرة وضع النواة (برامج التشغيل وغيرها)عمليّات محميّة (PPL)تسجيل إطلاق UWP (الرفق ممكن)جلسات وسياقات أمان أخرىإعادة التشغيل للقراءة فقطقد تتعارض مع مكافحة الفيروسات وElectron

الشكل 7: القيود نوعان: «لا يمكن التسجيل» و«تعارضات». الأخير يجب عزله لكلّ بيئة.

البند الأخير يُعثر من يريد تسجيل خدمة. تصف وثائق TTD.exe ‏-attach بأنّه موجَّه لـ«التحقيق في الخدمات والتطبيقات طويلة التشغيل» و-monitor بأنّه يسجّل «في كلّ مرّة يبدأ فيها برنامج أو خدمة»،2 وهذا لا يتّسق ببساطة مع عبارة صفحة استكشاف الأخطاء. عمليّاً النهج الآمن التحقّق لكلّ بيئة بهذا الترتيب: أكّد أنّ ping.exe أو cmd.exe يمكن تسجيلهما في التكوين نفسه للإنتاج، ثمّ جرّب العمليّة المستهدَفة.8

4. التسجيل — واجهة WinDbg وTTD.exe

لنقطتي دخول للتسجيل: واجهة WinDbg، أو TTD.exe سطر الأوامر.

4.1 التسجيل من واجهة WinDbg

شغّل WinDbg كمسؤول (الارتفاع إلزامي لـ TTD1)، اختر File > Start debugging > Launch executable (advanced)، حدّد التنفيذي، وعلِّم Record with Time Travel Debugging. اختيار Configure and Record يتيح تعيين موضع ملف التتبّع وRecord subset of execution (احصر الوحدات المسجَّلة بقائمة مفصولة بفواصل مثل notepad.exe,kernelbase.dll). لعمليّة قيد التشغيل أصلاً اختر File > Start debugging > Attach to process وعلِّم كذلك Record Process with Time Travel Debugging.9

أثناء التسجيل يظهر مربع حوار صغير بزرّي «Stop and Debug» و«Cancel». عندما يخرج التطبيق (أو ينهار) يُغلَق التتبّع ويفتحه WinDbg تلقائيّاً ويبني الفهرس.5

تدفّق التسجيل من واجهة WinDbgفي WinDbg المشغَّل كمسؤول اختر Launch executable (advanced) أو Attach to process، علِّم Record with Time Travel Debugging، اضبط موضع الحفظ ومرشّح الوحدة في Configure and Record، مرّ بمربع حوار التسجيل، وعندما يخرج التطبيق يُغلَق التتبّع ويُفهرَس تلقائيّاًابدأ WinDbg كمسؤولLaunch executable (advanced) / Attach to processعلِّم Record with Time Travel DebuggingConfigure and Record: موضع الحفظ، مرشّح الوحدةمربع حوار التسجيل (Stop and Debug)يخرج التطبيق، يُغلَق التتبّع ويُفهرَس تلقائيّاً

الشكل 8: التسجيل من الواجهة خمس خطوات. تخطَّ «ابدأ كمسؤول» فتتوقّف عند أوّل مربع حوار.

4.2 التسجيل بـ TTD.exe

عندما تحتاج إلى التسجيل على حاسوب لا يمكن تثبيت WinDbg عليه، أو لأتمتة التسجيل، استخدم TTD.exe وحده. يُثبَّت عبر App Installer من https://aka.ms/ttd/download، وبعد التثبيت يمكنك التحقّق منه بـ ttd.exe -help. للبيئات دون اتّصال توفّر Microsoft أيضاً إجراءً رسميّاً (مع سكربت PowerShell) لفكّ حزمة MSIX يدوياً واستخراج الثنائيّات فقط.2 يلزم التسجيل امتياز المسؤول ويُشغَّل عادة من موجه أوامر للمسؤول.2

هناك ثلاثة أوضاع تسجيل.2

أوضاع التسجيل الثلاثة لـ TTD.exeيطلق launch عمليّة جديدة بوسائط ويسجّلها، لكنّها تعمل بامتيازات مرتفعة. يرفق attach بعمليّة قيد التشغيل حسب PID. يسجّل monitor في كلّ مرّة يبدأ فيها البرنامج المحدَّد، ويحدث الإطلاق بامتيازات عاديّةأوضاع تسجيل TTD.exe-launch: أطلق وسجّل-attach: ارفق بـ PID قيد التشغيل-monitor: سجّل كلّ إطلاقيُطلَق بامتيازات المسؤوليحفظ الامتيازات العاديّةمسار إطلاق عادي، يناسب الأتمتة

الشكل 9: -launch وحده يستطيع تمرير وسائط، لكنّه يعمل بامتيازات مرتفعة. لتسجيل سلوك قريب من الإنتاج استخدم -attach أو -monitor.

:: أطلق وسجّل (الوضع الافتراضي. يمكن إغفال -launch)
TTD.exe -out C:\traces MyApp.exe --config prod.json

:: ارفق بعمليّة قيد التشغيل (أنشئ مجلّد الإخراج أولاً)
TTD.exe -attach 21440 -out C:\traces\MyApp.run

:: سجّل كلّ إطلاق (Ctrl+C يُنهي المراقبة. -out يتطلّب مساراً كاملاً)
TTD.exe -out C:\traces\ -monitor MyApp.exe
  • -launch هو الوضع الوحيد الذي يستطيع تمرير وسائط، لكن البرنامج يُطلَق بالامتيازات نفسها (المسؤول) لـ TTD.exe. للتطبيقات التي يتغيّر سلوكها مع الامتيازات سجّل بـ -attach أو -monitor لإبقاء الامتيازات العاديّة.2
  • -attach يتطلّب وجود مجلّد الإخراج أصلاً. إذا حدّدت اسم ملفّ فلا يجوز أن يوجد ملفّ بذلك الاسم.2
  • -monitor يثبّت برنامج تشغيل مراقبة إطلاق العمليّات ويسجّل في كلّ مرّة يبدأ فيها البرنامج المحدَّد (يمكن إعطاء أكثر من واحد). يبقى سارياً حتى إعادة الإقلاع ويُوقَف بـ Ctrl+C. مزاياه أنّك لا تحتاج إلى تجميع الإطلاق بنفسك، ويعمل الهدف بامتيازات عاديّة، ويناسب الأتمتة بالسكربت. إضافة -cmdLineFilter "string" تسجّل فقط الإطلاقات التي يحتوي سطر أوامرها تلك السلسلة.2
  • -children يسجّل العمليّات الابن أيضاً، لكن لكلّ عمليّة ملف .run خاص، ولا يستطيع WinDbg فتح سوى واحد في كلّ مرّة.2

أثناء التسجيل تظهر واجهة صغيرة بزرّين: «Tracing Off» (أوقف التسجيل ودع التطبيق يتابع) و«Exit App» (أغلق التطبيق وأنهِ التسجيل). للأتمتة أخفِها بـ -noUI واقبل اتفاقية الترخيص بـ -accepteula.2 يُحفَظ سجلّ التسجيل في ملف .out في الموضع نفسه لملف .run، حيث يمكنك قراءة أزمنة ساعة الحائط لبدء التسجيل ونهايته، وطول جلسة التسجيل (زمن المحاكاة)، وما إذا كان إطلاقاً أو رفقاً، وإصدار نظام التشغيل. عندما يفشل تسجيل تظهر بعض رسائل الخطأ في ملف .out فقط.2

5. تصميم التسجيل للتطبيقات طويلة التشغيل

هذا قلب المقال. بالنظر إلى تكاليف الفصل 3، التقاط خطأ يحدث في وقت مجهول في عمليّة تعمل أيّاماً يتطلّب تصميم تسجيل. يوفّر TTD.exe أربع وسائل، وتختار حسب طبيعة العَرَض.

اختيار نطاق التسجيل حسب عَرَض تطبيق طويل التشغيلإذا لم تعرف متى سيحدث أبقِ الجزء الأخير فقط بمخزن حلقي؛ إذا عرفت أيّ وحدة مشتبَه بها سجّل تلك الوحدة فقط؛ إذا أمكن تعديل التطبيق حدّد الفاصل بواجهة التسجيل اليدوي؛ إذا ظهر عند الإقلاع أو إطلاقات معيّنة فقط سجّل كلّ إطلاق بوضع المراقبةمجهول متى يحدثعند الإقلاع أو إطلاقات معيّنة فقطالوحدة المشتبَه بها واضحةيمكن تعديل التطبيقطبيعة العَرَض؟-ring / -maxFile: أبقِ النهاية فقط-monitor: سجّل كلّ إطلاقأضف -moduleحدّد الفاصل بـ -recordmode Manual

الشكل 10: الأربع ليست متنافية. الجمع بين -ring و-module هو التركيب الأكثر عمليّة للتطبيقات طويلة التشغيل.

5.1 المخزن الحلقي — أبقِ آخر N ميغابايت فقط

مع -ring يُكتَب التتبّع إلى مخزن حلقي بالحجم الذي يعطيه -maxFile، ولا ينمو الملفّ أبداً أبعد من ذلك الحدّ. ما يبقى هو الجزء الأخير فقط من التسجيل الذي يسع ذلك الحجم.2 وحدة -maxFile هي ميغابايت؛ في وضع المخزن الحلقي الافتراضي 2,048 ميغابايت، والحدّ الأدنى 1 ميغابايت، والأقصى 32,768 ميغابايت (افتراضي المخزن الحلقي في الذاكرة لعمليّة 32 بت هو 256 ميغابايت).2

:: ارفق بتطبيق مراقبة قيد التشغيل، وأبقِ آخر 4 غيغابايت فقط من التنفيذ
TTD.exe -accepteula -noUI -attach 21440 -ring -maxFile 4096 -out C:\traces\MyApp.run

:: عند اكتشاف العَرَض، أوقف التسجيل (التطبيق يتابع العمل)
TTD.exe -stop 21440

يقبل -stop اسم عمليّة أو PID أو all، ويوقف ذلك التسجيل. ينتظر -wait <seconds> حتى تنتهي كلّ جلسة تسجيل على النظام (-1 إلى ما لا نهاية)، ويُستخدم في سكربتات الأتمتة لفرض ترتيب «أوقف، ثمّ اجمع الملفّ».2

الخطّ الزمني لتسجيل مخزن حلقييبدأ التسجيل عند الرفق، تُدفَع الأجزاء الأقدم خارج المخزن الحلقي، وعندما يظهر العَرَض ويُصدَر stop يبقى فقط أحدث maxFile كالتتبّعابدأ التسجيل بـ -attach -ringالفواصل الأقدم تُدفَع للخارجيظهر العَرَضأوقف التسجيل بـ -stopيبقى أحدث maxFile فقطحدّد الحجم بحيث تسع اللحظات قبل العَرَض في المخزن

الشكل 11: المخزن الحلقي جهاز لإبقاء «اللحظات قبل العَرَض». اعمل -maxFile إلى الخلف من «الزمن من ملاحظة العَرَض إلى الإيقاف، مضروباً في النمو لكلّ ثانية».

هناك نقطتا تصميم.

  1. اجعل المخزن كبيراً بما يكفي لامتصاص الزمن من الملاحظة إلى الإيقاف. في عمليّة نشطة ينمو التتبّع بـ 5 إلى 50 ميغابايت في الثانية،4 لذا يقابل مخزن 4 غيغابايت دقيقة إلى دقيقتين تحت حمل ثقيل وأزيد قليلاً من عشر دقائق تحت حمل خفيف. تحتاج آلية تُبقي التأخير بين اكتشاف العَرَض (سطر سجلّ معيّن، عتبة عدّاد، تنبيه من المراقبة) و-stop داخل تلك النافذة.
  2. الإيقاف لا يفصل. يوقف -stop التسجيل، لكن TTD لا يفصل نفسه عن العمليّة المستهدَفة.2 إنهاء التسجيل تماماً يتطلّب إنهاء العمليّة، لذا أدخل «أعد التشغيل في نافذة الصيانة التالية بعد جمع التتبّع» في إجراء التشغيل.
إيقاف تسجيل مخزن حلقي بالتنسيق مع المراقبةعندما يكتشف جانب المراقبة العَرَض عبر السجلّات أو العدّادات يستدعي TTD.exe stop، ويجمع ملف ‎.run المكتمل، ويعيد تشغيل العمليّة في نافذة الصيانة التالية لإزالة TTDالعمليّة المستهدَفةTTD.exeالمراقبة (السجلّات، العدّادات)العمليّة المستهدَفةTTD.exeالمراقبة (السجلّات، العدّادات)اكتشف العَرَض-stop PIDأوقف التسجيل (العمليّة تتابع)يُكمَل ‎.runاجمع ‎.run، شفِّر، واحفظأعد التشغيل في نافذة الصيانة التالية

الشكل 12: فقط عندما يسع التأخير بين الاكتشاف و-stop في المخزن تبقى اللحظات قبل العَرَض في التتبّع. إعادة التشغيل جزء من التشغيل.

5.2 مرشّح الوحدة — سجّل فقط أثناء تشغيل شيفرتك

يسجّل -module <module name> الوحدة المحدَّدة فقط (التنفيذي نفسه أو DLL محمَّلة؛ يمكن إعطاء أكثر من واحدة) والشيفرة التي تستدعيها تلك الوحدة. تعمل العمليّة المستهدَفة بالسرعة الكاملة حتى تنفَّذ شيفرة في الوحدة المحدَّدة؛ يبدأ التسجيل عندما يدخل التنفيذ الوحدة، ويتوقّف عندما يخرج، وتعود العمليّة إلى السرعة الكاملة. لأنّ تشغيل التسجيل وإيقافه مكلفان، يبقى التسجيل شغّالاً بينما تستدعي الوحدة المحدَّدة وحدات أخرى في العمليّة.2

:: سجّل فقط أثناء تشغيل DLL منطق القياس لدينا (مع المخزن الحلقي)
TTD.exe -accepteula -noUI -attach 21440 -module MeasureCore.dll -ring -maxFile 2048 -out C:\traces\

يتخطّى تتبّع صُنع بهذا الشكل ببساطة الفواصل التي كان التسجيل فيها متوقّفاً، فيعامل «التعليمات التالية» كأوّل تعليمة بعد استئناف التسجيل، وتصحّحه لا يختلف عن تتبّع العمليّة كلّها.2 في التطبيقات طويلة التشغيل يميل حلقة خمول واجهة المستخدم والمعالجة الداخليّة للإطار إلى حساب معظم التعليمات المنفَّذة، لذا فإنّ حصر التسجيل في وحدتك وحدها يقلّل العبء وحجم الملفّ كثيراً.

كيف يتصرّف التسجيل المرشَّح بالوحدةتعمل العمليّة المستهدَفة بالسرعة الكاملة خارج الوحدة المحدَّدة؛ يبدأ التسجيل عند دخول شيفرة الوحدة المحدَّدة، ويتابع بينما تستدعي تلك الوحدة وحدات أخرى، ويتوقّف عندما يخرج التنفيذ من الوحدةخارج الوحدة المحدَّدة: سرعة كاملةادخل الوحدة المحدَّدة: يبدأ التسجيلوحدات أخرى تستدعيها: يتابع التسجيلاخرج من الوحدة المحدَّدة: يتوقّف التسجيل

الشكل 13: لأنّ واجهات Win32 ووقت التشغيل التي تستدعيها DLL تُسجَّل أيضاً، يكفي هذا لتتبّع «ما سلّمته شيفرتنا إلى نظام التشغيل».

5.3 التسجيل اليدوي — دع التطبيق يحدّد الفاصل

مع -recordmode Manual تواصل العمليّة العمل بالسرعة الكاملة حتى بعد حقن TTD، ويحدث التسجيل فقط عندما يستدعي البرنامج واجهة التسجيل داخل العمليّة لـ TTD (الافتراضي، Automatic، يسجّل من لحظة الحقن).2 وثائق الواجهة والعيّنات في مستودع WinDbg-Samples على GitHub.10

إذا أمكن تعديل التطبيق فهذا أقلّ نهج هدراً. يمكنك بناء منطق يبدأ التسجيل عندما يعلم التطبيق نفسه أنّ شذوذاً وشيك ويتوقّف عندما تعود الأمور إلى الطبيعي: «فشلت ثلاث إعادات محاولة اتّصال متتالية»، «تجاوز تراكم الطابور العتبة»، وما شابه. في تكوين عمليّة مشرفة كالذي غُطي في مقال Job Object يمكن للمشرف أن يقرّر الفاصل بدل ذلك.

5.4 وضع المراقبة — سجّل كلّ إطلاق

للأخطاء التي تظهر فقط فور الإقلاع أو عند إطلاقات معيّنة، يناسب -monitor. يصف جدول المقارنة الرسمي أيضاً وضع المراقبة بأنّه موجَّه لـ«التقاط المشاكل المتقطّعة ومشاكل الإقلاع».2 عند تسجيل البرنامج نفسه مرّات كثيرة تصبح أسماء الملفّات التسلسليّة الافتراضيّة (MyApp01.run وMyApp02.run وما شابه) غير فعّالة لأنّ الملفّات الموجودة يجب مسحها، لذا استخدم -timestampFilename لأسماء بطابع زمني. يمكن حصر عدد التسجيلات المتزامنة بـ -maxConcurrentRecordings.2

كيف يتصرّف وضع المراقبةيثبّت خيار المراقبة برنامج تشغيل مراقبة إطلاق العمليّات، ويضيّق الهدف بمرشّح سطر الأوامر في كلّ مرّة يبدأ فيها البرنامج المحدَّد، ويسجّله، وينشئ ملف تتبّع منفصلاً لكلّ إطلاق، ويتابع حتى Ctrl+C أو إعادة إقلاعنعملاثبّت برنامج تشغيل مراقبة الإطلاقاكتشف إطلاقاً للبرنامج المحدَّديطابق -cmdLineFilter؟سجّل ذلك الإطلاق (ملف منفصل لكلّ إطلاق)لا تسجّلانتظر الإطلاق التالي (حتى Ctrl+C أو إعادة الإقلاع)

الشكل 14: وضع المراقبة «يكمن للإطلاق». يناسب الأخطاء التي تظهر عند كلّ إطلاق والأخطاء التي يمكن تضييقها بشروط الإطلاق.

5.5 أين تضع القرص

للتسجيلات طويلة التشغيل ضع التتبّعات على مجلّد مخصّص وأدخل نمو ملف .run في مراقبتك. كما لوحظ في القسم 3.2، عندما يمتلئ القرص ينتظر التسجيل بصمت بلا خطأ. الحلّ الرسمي بدائي بالقدر نفسه: «راجع المساحة الحرّة في المستكشف» و«تحقّق من أنّ ملف .run ينمو بانتظام».4 بلا مراقبة المساحة الحرّة تنتهي بتتبّع ناقص لم تُكتَب فيه اللحظة التي أردتها أكثر.

كيف ينتج نفاد القرص تتبّعاً ناقصاًعندما ينفد القرص أثناء التسجيل يكتب TTD الصفحة الأخيرة وينتظر بصمت بلا خطأ ولا تحذير، لذا لا يُسجَّل العَرَض الذي يحدث بعد ذلك، فيبقى تتبّع ناقص يُفتَح لكن ينقصه الجزء الحاسم. امنعه بمجلّد مخصّص ومراقبة نمو ‎.runيمنعينفد القرصيكتب الصفحة الأخيرة وينتظر بصمتلا خطأ، لا تحذيريحدث العَرَض بعد ذلكتتبّع ناقص بلا العَرَضمجلّد مخصّص + مراقبة نمو ‎.run

الشكل 15: تتبّع «يُفتَح لكن ينقصه الجزء الحاسم» يولد من فجوة في مراقبة القرص.

6. إعادة التشغيل — المواضع والأحداث والإرجاع

6.1 الفتح

عندما تفتح ملف .run في WinDbg، إن لم يوجد فهرس يعمل !index تلقائيّاً ويبني ملف .idx بينما يعدّ الإطارات المفتاحيّة (مواضع في التتبّع مولَّدة تلقائيّاً للفهرسة؛ التتبّعات الأكبر فيها أكثر منها). كلّما كبر التتبّع طال الوقت.5 يمكن فحص حالة الفهرس بـ !index -status؛ إذا بلّغ أيّ شيء غير «Index file loaded» فأعد بناءه بـ !index -force. إذا فشل ذلك أيضاً أغلق المصحّح واحذف ملف .idx وأعد فتح ملف .run. إعادة بناء الفهرس لا تعدّل ملف .run، لذا لا تُفقَد بيانات.8

تحذير واحد: عندما حُسِّنت فهرسة التتبّعات الكبيرة في TTD 1.11.611 تغيّر تنسيق الفهرس، وتحتاج التتبّعات الموجودة إلى إعادة فهرسة.11 إذا حملت ملفّات .idx قديمة فهنا تتعثّر.

فحص الفهرس وإعادة بنائهبعد فتح التتبّع راجع الحالة بـ !index -status؛ إن كانت أيّ شيء غير Index file loaded فأعد البناء بـ !index -force، وإذا فشل ذلك أيضاً أغلق المصحّح واحذف ملف ‎.idx وأعد فتح ‎.run. إعادة البناء لا تعدّل ملف ‎.runIndex file loadedأيّ شيء آخريفشلينجحافتح التتبّع!index -statusانتقل إلى التحليلأعد البناء بـ !index -forceأغلق، احذف ‎.idx، أعد فتح ‎.run

الشكل 16: إعادة بناء الفهرس لا تلمس ملف .run. عند الشك احذفه وأعد الفتح.

6.2 الانتقال حسب الموضع

تمرير موضع إلى !tt ينتقل إلى تلك النقطة في الزمن.6

!tt 0          ; بداية التتبّع
!tt 50         ; موضع 50% تقريباً
!tt 100        ; نهاية التتبّع
!tt 1A0:12F    ; إلى الموضع 1A0:12F

الموضع زوج من أرقام ست عشريّة، رقم التسلسل:عدد الخطوات.6 يملك كائن Position الخصائص Percent (جزء التتبّع)، وSequence، وSteps، إضافة إلى SeekTo() الذي ينتقل إلى ذلك الموضع، وToSystemTime() الذي يعيد زمن ساعة الحائط التقريبي (UTC).7 في تحقيقات التشغيل الطويل يصنع ToSystemTime() الفرق، لأنّه يتيح مطابقة الطوابع الزمنيّة في سجلّ التطبيق مع مواضع في التتبّع. تحمل نتائج TTD.Calls أيضاً SystemTimeStart / SystemTimeEnd.12

مطابقة المواضع مع طوابع السجلّ الزمنيّةبدءاً من طابع زمني في سجلّ التطبيق اتبع زمن ساعة الحائط التقريبي لكائن Position لتحديد الموضع في التتبّع، وانتقل إليه بـ SeekTo، واقرأ التنفيذ حولهسجلّ التطبيق: وقت الشذوذجد موضعاً قريب ToSystemTimeانتقل إليه بـ SeekToاقرأ الاستدعاءات والقيم المحيطة

الشكل 17: «ماذا كان يفعل قبيل سطر السجلّ هذا؟» يمكن البحث عنه عبر التقابل بين المواضع وزمن ساعة الحائط.

المواضع مفيدة للمشاركة أيضاً. عندما تسلّم تتبّعاً لزمیل ألحق موضع !tt x:y فيبدأ النظر من النقطة الزمنيّة نفسها. كتابة نطاقات المواضع في تقارير الأخطاء ممارسة موصى بها رسميّاً أيضاً.2

6.3 الإرجاع

إلحاق - بأوامر الخطوة المعتادة يتحرّك إلى الخلف في الزمن.13

الأمر المعنى زرّ الشريط
p- ارجع تعليمة واحدة (أو سطر مصدر واحد). يُعدّ استدعاء دالّة خطوة واحدة Step Over Back
t- ارجع تعليمة واحدة (أو سطر مصدر واحد). يدخل استدعاءات الدوال Step Into Back
g- نفّذ عكسياً. يتوقّف عند إصابة نقطة توقّف، أو عند حدث، أو عند بداية التتبّع Go Back

الأحداث التي توقف g- هي نفسها التي توقف g الأمامي.13 بعبارة أخرى، اضبط ba (نقطة توقّف عند الوصول) أو bp وشغّل g- فتعود مباشرة إلى «آخر موضع صمد فيه ذلك الشرط». هذه الحركة الأساسيّة للفصل 7.

الاختيار بين أوامر العكسيرجع p- خطوة واحدة عبر استدعاءات الدوال، ويرجع t- تعليمة واحدة داخل الدوال، ويرجع g- مباشرة إلى نقطة توقّف أو حدث أو بداية التتبّع. ما يوقف g الأمامي يوقف g- أيضاًp-t-g-الموضع الحاليارجع خطوة واحدة عبر الاستدعاءاتارجع تعليمة واحدة داخل الدوالارجع مباشرة إلى شرط التوقّف التاليba / bp / حدث / بداية التتبّع

الشكل 18: للنظر بعناية في الجوار استخدم t-؛ للقفز إلى سبب بعيد استخدم ba + g-.

6.4 الدخول عبر الأحداث

إذا لم تكن متأكّداً من أين تبدأ القراءة فابدأ بقائمة الأحداث. يسرد @$curprocess.TTD.Events إنشاء الخيوط وإنهاءها، وتحميل الوحدات وتفريغها، والاستثناءات كأحداث.14

dx -g @$curprocess.TTD.Events
dx @$curprocess.TTD.Events.Where(t => t.Type == "Exception").Select(e => e.Exception)

يحتوي حدث استثناء الموضع والنوع (Software / Hardware) ورمز الاستثناء وعدّاد البرنامج في ذلك الوقت، والنقر على رابط [Time Travel] في المخرجات ينتقل إلى ذلك الموضع.15 يتبع الدليل الرسمي هذا التدفّق: يقفز إلى موضع انتهاك وصول (0xc0000005)، ويشتبه في فساد المكدّس لأنّ مؤشّر المكدّس ومؤشّر القاعدة يختلفان، ويرجع ثلاث تعليمات بـ t- للتحقّق من القيم.5 تصوّر نافذة Timelines في WinDbg الاستثناءات ونقاط التوقّف ووصولات الذاكرة واستدعاءات الدوال كخطّ زمني، والنقر المزدوج على استثناء يصدر SeekTo() نفسه.16

6.5 الخيوط والمواضع

يُظهر !positions كلّ خيط نشط في الموضع الحالي مع موضع كلّ خيط في التتبّع.17 هناك مطبّ هنا. تبديل الخيوط بـ ~<number>s لا يحرّك الموضع في التتبّع. لا يتغيّر الموضع الذي يستخدمه المصحّح لقراءة الذاكرة، لذا للنظر إلى ذاكرة خيط آخر «في تلك النقطة الزمنيّة» انتقل هناك برابط الموضع في مخرجات !positions أو بـ !tt x:y.13

المسار الأساسي عبر إعادة تشغيلافتح التتبّع وابنِ الفهرس، وانتقل من قائمة الأحداث إلى موضع الاستثناء، وارجع خطوة إلى السبب، وإن لزم انتقل إلى موضع خيط آخر بـ positionsافتح التتبّع وفهرسهجد الاستثناء في TTD.Eventsانتقل إلى الموضع بـ [Time Travel]ارجع بـ t- / p- / g-راجع مواضع الخيوط الأخرى بـ !positions~s لا يحرّك موضع التتبّع

الشكل 19: «ادخل عبر حدث، وامشِ إلى الخلف» هو المسار الأساسي عبر إعادة التشغيل. تبديل الخيوط ليس تحريك مواضع.

7. إيجاد «متى» بالاستعلامات — TTD.Calls وTTD.Memory

القوّة الحقيقيّة لإعادة التشغيل أنّ يمكنك الاستعلام عن التتبّع كلّه. تُعرَض كائنات TTD عبر نموذج بيانات المصحّح (أمر dx)، ويمكنك ترشيحها وفرزها وتجميعها بأسلوب LINQ.18

7.1 TTD.Calls — البحث عن استدعاءات الدوال

يجمع @$cursession.TTD.Calls("module!symbol") استدعاءات الدالّة المحدَّدة من التتبّع كلّه. البدل مسموح، ويحمل كلّ استدعاء مواضع البداية والنهاية (TimeStart / TimeEnd)، ومعرِّف الخيط (مع UniqueThreadId لا يُعاد استخدامه أبداً)، والوسائط (Parameters[])، والقيمة المرجَعة (ReturnValue)، وعنوان الرجوع (ReturnAddress).12

مثال الوثائق الرسميّة هو GetLastError. جمّع الاستدعاءات ذات القيمة المرجَعة غير الصفريّة حسب رمز الخطأ فتحصل على قائمة بأيّ أخطاء حدثت وكم مرّة أثناء التتبّع.18

dx -g @$cursession.TTD.Calls("kernelbase!GetLastError").Where(x => x.ReturnValue != 0).GroupBy(x => x.ReturnValue).Select(x => new { ErrorNumber = x.First().ReturnValue, ErrorCount = x.Count() }).OrderByDescending(p => p.ErrorCount),d

لـ«من أين استُدعي آخر MessageBox؟» خذ آخر استدعاء بـ OrderBy(c => c.TimeStart).Last() وانتقل هناك عبر رابط [Time Travel] لـ TimeStart.18

بناء استعلام TTD.Callsاجمع الاستدعاءات باسم الدالّة، رشّح بالقيمة المرجَعة أو الوسائط، جمّع حسب رمز الخطأ وما شابه، افرز حسب الزمن، وانتقل إلى موضع الاستدعاء الذي تريده عبر رابط Time TravelTTD.Calls (اسم الدالّة، البدل)Where: رشّح بالقيمة المرجَعة أو الوسائطGroupBy: جمّع حسب رمز الخطأ وغيرهاOrderBy: افرز حسب الزمنانتقل عبر [Time Travel] على TimeStart

الشكل 20: طريقة استخدام الاستعلامات أن تبدأ لا من «أين» بل من «متى، وكم مرّة، وبأيّ وسائط».

كلمة عن الرموز. يحدّد TTD عدد أنواع وسائط الدالّة وأنواعها ونوع إرجاعها واصطلاح الاستدعاء من معلومات رموز PDB. بالرموز الخاصّة تحصل على اسم الدالّة والوسائط الصحيحة. بالرموز العامّة فقط تحصل على اسم الدالّة ووسائط افتراضيّة (أربعة أعداد صحيحة 64 بت بلا إشارة). وحدة بلا رموز أصلاً تحصل على اسم الدالّة UnknownOrMissingSymbols.1218 لأنواع PDB وكيفيّة تخزينها انظر «ما هو PDB؟».

توفّر الرموز ونتائج TTD.Callsبالرموز الخاصّة تحصل على اسم الدالّة والوسائط الصحيحة؛ بالرموز العامّة فقط تحصل على اسم الدالّة والوسائط الافتراضيّة الأربع 64 بت؛ بلا رموز يصبح اسم الدالّة UnknownOrMissingSymbolsرموز خاصّةرموز عامّةلا شيءرموز الوحدة؟اسم الدالّة + وسائط وقيمة إرجاع صحيحةاسم الدالّة + وسائط افتراضيّة (4 أعداد 64 بت)UnknownOrMissingSymbols

الشكل 21: ما إذا احتفظت بملفّات PDB لوحداتك يحدّد مباشرة مدى فائدة الاستعلامات.

يشمل Calls حساباً، لذا كلّما كبر التتبّع طال الوقت وارتفع استخدام CPU. تُخزَّن النتائج مؤقّتاً في الذاكرة، لذا تكون الاستعلامات الثانية فما بعد للدالّة نفسها أسرع.12 عندما لا يعيد استعلام شيئاً هناك أربعة أسباب: كيفيّة كتابة الاستدعاء (راجع اسم الوحدة بأمر x؛ إذا عاد بأحرف كبيرة فاستخدم ذلك)، DLL المستهدَفة غير محمَّلة بعد في ذلك الموضع (انتقل إلى موضع بعد التحميل وشغّله مجدّداً)، الدالّة مضمَّنة (لا يمكن تتبّعها)، أو البدل واسع جدّاً (ضيّقه).18

7.2 TTD.Memory — البحث عن وصولات الذاكرة

يجمع @$cursession.TTD.Memory(start address, end address, "access type") الوصولات إلى نطاق الذاكرة المحدَّد من التتبّع كلّه. الأنواع r (قراءة)، وw (كتابة)، وrw، وe (تنفيذ)، وrwe، وec (تنفيذ/تغيير).19 يُجاب «من كتب هذا المتغيّر أخيراً؟» بالجمع بـ "w" وأخذ .Last() والانتقال إلى ذلك الموضع.5

dx -g @$cursession.TTD.Memory(0x00a4fca0, 0x00a4fca4, "w")
dx @$cursession.TTD.Memory(0x00a4fca0, 0x00a4fca4, "w").Last().TimeStart.SeekTo()

إذا احتجت فقط إلى البحث أماماً أو خلفاً من الموضع الحالي فـ @$curprocess.TTD.PrevMemoryAccess("w", address, size) / NextMemoryAccess أخفّ وتقبل نطاقات متعدّدة في آن. يمكن إيجاد الموضع الذي تغيّر فيه سجلّ بـ @$curthread.TTD.PrevRegisterWrite("rcx").6

7.3 ba + g- — جعل المصحّح يجيب «من أفسده؟»

تكثيف الإجراء المعروض في الدليل الرسمي إلى شكل قابل للاستخدام لتحقيقات التشغيل الطويل يعطي التالي.5

  1. انتقل إلى موضع الاستثناء بـ TTD.Events
  2. ارجع بـ t- وافترض أيّ متغيّر يحمل القيمة الفاسدة
  3. احصل على عنوان ذلك المتغيّر بـ dx &variable
  4. اضبط نقطة توقّف كتابة بـ ba w4 <address>
  5. شغّل g- للرجوع مباشرة إلى الموضع الذي كُتب فيه ذلك المتغيّر أخيراً
  6. تحقّق ممّا إذا كانت تلك النقطة (أو بضع تعليمات أسبق) هي السبب. إذا جاءت القيمة المكتوبة من متغيّر آخر فاضبط ba على ذلك المتغيّر وشغّل g- مجدّداً
  7. كرّر حتى تصل إلى التعليمات التي أفسدته
تتبّع أصل قيمة بـ ba وg-اضبط نقطة توقّف كتابة على عنوان القيمة الفاسدة ونفّذ عكسياً، توقّف عند التعليمات التي كتبته أخيراً، وإذا جاءت تلك القيمة من متغيّر آخر كرّر الخطوات نفسها حتى تصل إلى التعليمات التي أفسدتهنعملاحدّد عنوان القيمة الفاسدةاضبط نقطة توقّف كتابة بـ ba wنفّذ عكسياً بـ g-توقّف عند التعليمات التي كتبته أخيراًهل جاءت القيمة من متغيّر آخر؟التعليمات المفسدة = السبب

الشكل 22: تحقيق ينتهي عند «إنّه فاسد» بتفريغ يتقدّم آليّاً إلى «من أفسده» بـ TTD.

تضيف TTD 1.11.553 فما بعد أيضاً @$curframe.TTD.VariableHistory() الذي يعيد تاريخ قيم المتغيّرات المحلّيّة لإطار. يُظهر جدولاً لأسماء المتغيّرات وأيّ قيم حملها كلّ متغيّر على أيّ نطاقات مواضع.11 في حالات مثل فساد المكدّس حيث تريد أن تعرف «منذ متى والقيمة خاطئة» يفيد لتضييق أين تضبط ba أوّلاً.

8. تطبيق هذا على أخطاء التشغيل الطويل

نطبّق الآن هذه الأدوات على الأنواع الثلاثة المذكورة في البداية.

أنواع أخطاء التشغيل الطويل ونقطة دخول TTD لكلّ منهاللاستثناءات المتقطّعة وفساد البيانات ارجع من الحدث بـ ba وg-؛ لنمو الموارد طابق استدعاءات الحصول والإفلات بـ TTD.Calls؛ لعدم الاستجابة وسلاسل الانتظار اتبع المواضع وأزمنة ساعة الحائط لاستدعاءات واجهات الانتظاراستثناءات متقطّعة وفساد بياناتTTD.Events، ثمّ ba + g-نمو المقابض والذاكرةطابق الحصول والإفلات بـ TTD.Callsعدم الاستجابة وسلاسل الانتظار!positions وأزمنة ساعة الحائط لواجهات الانتظارسجّل بـ -module محصوراً في DLL الخاصّة بك

الشكل 23: تختلف نقطة الدخول حسب النوع. ما يشتركن فيه تضييق نطاق التسجيل قبل أن تبدأ القراءة.

النوع 1: الاستثناءات المتقطّعة وفساد البيانات. أبقِ اللحظات قبل العَرَض بالمخزن الحلقي في القسم 5.1، واقفز إلى موضع الاستثناء من قائمة الأحداث في القسم 6.4، وتتبع أصل القيمة بـ ba + g- في القسم 7.3. الفرق عن تحقيق التفريغ أنّ التحقيق لا ينتهي عندما تجد «المتغيّر الفاسد»؛ من هناك تتقدّم آليّاً إلى الخلف.

النوع 2: نمو المقابض والذاكرة. هذا نوع الحالة المشرَّح في «تسرّب مقبض ينهار بعد شهر». لا يمكنك تسجيل شهر كامل، لذا احصر التسجيل في DLL الخاصّة بك بـ -module في القسم 5.2، واجمعه مع -ring، وأبقِ «الدقائق القليلة أثناء النمو». على التتبّع اجمع TTD.Calls("kernelbase!CreateFileW") وTTD.Calls("kernelbase!CloseHandle") وطابق القيمة المرجَعة لـ CreateFileW (قيمة المقبض) مع الوسيط الأوّل لـ CloseHandle (Parameters[0]). قيمة ReturnValue لـ CloseHandle علم نجاح منطقي، لذا لا تفيد للمطابقة. إذا تُرك مقبض دون إغلاق يعطيك ReturnAddress (المستدعي) لذلك الاستدعاء لـ CreateFileW المستدعي الذي يتسرّب.12 مع ذلك، رصد ما إذا وُجد تسرّب ومدى كبره أرخص بـ Application Verifier أو عدّادات المقابض؛ تقسيم العمل الصحيح إدخال TTD عند مرحلة تثبيت أيّ مسار يتسرّب. لاحظ أنّ التسجيل مع تفعيل Application Verifier يدهور أداء إعادة التشغيل بوضوح بسبب كيفيّة استخدام الذاكرة، لذا عطِّله أثناء التسجيل.8

النوع 3: «لا يستجيب» وسلاسل الانتظار. كما كُتب في «ما الذي يعنيه «لا يستجيب» حقّاً»، التجمّد سؤال عمّن ينتظر من. لا ينمو التتبّع أثناء الخمول،4 لذا لا يظهر زمن انتظار خيط ينتظر في النواة كتعليمات. ما يظهر هو الاستدعاء قبيل دخول الانتظار والتعليمات بعد رجوعه. انظر إلى موضع كلّ خيط بـ !positions،17 وصفّ «أيّ خيط بدأ انتظار ماذا، ومتى» من SystemTimeStart / SystemTimeEnd لـ TTD.Calls("kernelbase!WaitForSingleObject") وما شابه؛ مطابقاً لطوابع السجلّ الزمنيّة يتيح ذلك إعادة بناء سلسلة الانتظارات.12 «أخطاء تعتمد على الترتيب» مثل DllMain وقفل المحمِّل أو الإيقاظات الزائفة لمتغيّرات الشرط مجال يناسب فيه TTD، الذي يسجّل الترتيب نفسه.

9. TTD مع تطبيقات .NET

تنصّ وثائق TTD الرسميّة على أنّ الشيفرة المُدارة يمكن تصحيحها بـ TTD في WinDbg باستخدام امتداد SOS (sos.dll) العامل في وضع 64 بت.1 تحميله هو نفسه في الفصل 3 من مقال تحليل SOS (.loadby sos coreclr أو التحميل التلقائي)، و!clrstack و!pe يعملان عند كلّ موضع في التتبّع. المسار الأساسي الانتقال إلى موضع الاستثناء بـ TTD.Events ثمّ قراءة المكدّس المُدار بـ !clrstack.

إعداد قراءة تتبّع TTD لتطبيق .NETافتح تتبّع TTD في WinDbg، حمِّل امتداد SOS بـ 64 بت، انتقل إلى موضع حدث الاستثناء، واقرأ الحالة المُدارة بـ !clrstack و!pe. استخدم TTD.Calls للاستدعاءات عبر الحدود الأصليّةتتبّع TTD (‎.run)WinDbgامتداد SOS (64 بت)انتقل إلى موضع الاستثناء بـ TTD.Eventsاقرأ بـ !clrstack / !peTTD.Calls للاستدعاءات عبر الحدود الأصليّة

الشكل 24: الحالة المُدارة عبر SOS، وبحث الاستدعاءات عند الحدود الأصليّة. افصل الأدوار فلا تتوه.

تحذيران. أوّلاً ما تضمنه Microsoft هو «SOS في وضع 64 بت». لا شيء مذكور عن تطبيقات .NET المبنيّة لـ x86، لذا شغّل هدف التحقيق كـ x64 إن استطعت. ثانياً يعتمد TTD.Calls على معلومات رموز PDB.12 لا تعوّل على البحث عن دوال مُدارة مترجمة بـ JIT بالاسم؛ الاستخدام الموثوق تتبّع الاستدعاءات عبر الحدود الأصليّة مثل أهداف P/Invoke في DLL أصليّة، وCOM، وواجهات Win32. مشاكل الكومة المُدارة مثل تلك في «تمييز تأخير GC عن تسرّب ذاكرة في .NET» تُتابَع أوّلاً بـ dotnet-counters / dotnet-gcdump / !gcroot على تفريغ، ويخرج TTD عند المرحلة التي تتورّط فيها حدود أصليّة.

10. الاختيار بين التفريغات والسجلّات وETW وTTD

TTD ليس علاجاً لكلّ شيء، ولا يحلّ محلّ الأدوات القائمة. هنا يُصفّ مقابل الأدوات المعالَجة في مقالاتنا.

ما تريد معرفته الأداة التي تستخدمها أوّلاً متى يدخل TTD
الحالة في لحظة الانهيار تفريغ الانهيار (WER LocalDumps / ProcDump) عندما يُظهر التفريغ «إنّه فاسد» لا من أفسده
أيّ ملفّ أو مفتاح سجلّ فشل Process Monitor عندما تحتاج أيضاً كيف بُنيت الوسائط الممرَّرة إلى الواجهة الفاشلة
أداء الحاسوب كلّه طويل المدّة WPR/WPA، PerfView (ETW) عندما تكون مشكلة صحّة لا أداء وتحتاج ترتيباً على مستوى التعليمات
تسلسل الأحداث على مستوى الأعمال سجلّات التطبيق عندما حدث على مسار شيفرة بلا تسجيل (يسجّل TTD كلّ شيء بلا تغييرات شيفرة مسبقة1)
من كتب تلك القيمة، وترتيب الاستدعاءات TTD
اختيار طريقة تحقيقأوّلاً اقبض على الحالة بتفريغات وسجلّات خفيفة، وحقّق في الواجهات الفاشلة بـ ProcMon وفي الأداء بـ ETW، وانتقل إلى TTD فقط عندما ما زلت تحتاج من مرّر ماذا ومتىنعملاالعَرَضاقبض على الحالة بالتفريغات والسجلّات (خفيفة)واجهات فاشلة: ProcMonالأداء: WPR/WPA، PerfViewتحتاج من ومتى وماذا مُرِّر؟صمّم نطاق التسجيل وسجّل بـ TTDحُسم بالأدوات الخفيفة

الشكل 25: اقبض على «النتيجة» بأدوات خفيفة أوّلاً، وأخرج TTD فقط للحالات التي يتبيّن فيها أنّ «المسار» مطلوب.

الترتيب «الأخفّ أوّلاً». تكاد التفريغات والسجلّات لا تكلّف شيئاً للجمع، لذا أبقِها دائماً؛ أخرج TTD، بعد تصميم الفصل 5، للحالات التي أظهر فيها قراءة التفريغ أنّ المسار مطلوب. بالنظر إلى عبء TTD وإلى أنّ التتبّعات تحتوي معلومات سرّيّة، لا سبب لعكس هذا الترتيب.

11. ملاحظات تشغيليّة

  • عامل التتبّعات كملفّات سرّيّة. يحتوي التسجيل محتويات الذاكرة ويمكن أن يشمل معلومات شخصيّة وأمنيّة مثل مسارات الملفّات وبيانات السجلّ ومحتويات الذاكرة والملفّات.12 عند التسجيل في بيئة عميل افهم مسبقاً ما قد يُشمَل (سلاسل الاتّصال والرموز وبيانات العملاء) وقرّر قناة نقل مشفَّرة وموضع تخزين ومدّة احتفاظ.
  • شارك ملف .run وحده. ملف .idx بحجم ملف .run تقريباً ويُولَّد تلقائيّاً عندما يفتحه WinDbg. تضغط ملفّات .run جيّداً. عند الإبلاغ عن خطأ في TTD نفسه ألحق ملف .out أيضاً.2
  • أبقِ الإصدارات متوائمة. يواصل TTD التحديث مع WinDbg؛ يشمل 1.11.611 إصلاحاً لانهيارات التسجيل في برامج تستخدم AVX/AVX512 وتغيّراً في تنسيق الفهرس.11 خلط إصدار قديم في جانب التسجيل أو إعادة التشغيل يعني إعادة فهرسة أو إعادة تسجيل.
  • راجع -replayCpuSupport عند إعادة التشغيل على CPU مختلف. يفضّل الافتراضي قابليّة النقل، ويُوفَّر MostConservative للحالات التي يختلف فيها CPU التسجيل عن CPU إعادة التشغيل (مثل إعادة تشغيل تتبّع Intel على arm64). بالمقابل، إذا علمت أنّ CPU إعادة التشغيل مساوٍ أو أفضل يمكنك اختيار تسجيلاً أصغر وأسرع.2
  • يمكن تسجيل Windows Server أيضاً. يدعم TTD.exe ‏Windows Server 2016/2019/2022/2025.2
  • عزل فشل التسجيل. جرّب أوّلاً ما إذا أمكن تسجيل ping.exe أو cmd.exe؛ إن لم يكن فاشتهِ تعارضاً مع برمجيّات تدخّليّة مثل مكافحة الفيروسات أو افتراضيّة التطبيقات.8
إجراء التعامل مع التتبّعاتلأنّ التتبّع المسجَّل يحتوي محتويات الذاكرة افهم أيّ معلومات قد يحتوي، اضغط ملف ‎.run وحده وسلّمه عبر قناة مشفَّرة، قرّر موضع التخزين ومدّة الاحتفاظ، وفي جانب التحليل افتحه بإصدار WinDbg نفسه وابنِ الفهرساكتمل التسجيل (‎.run / ‎.idx / ‎.out)افهم أيّ معلومات قد يحتوياضغط ‎.run وحده، شفِّر، وسلّمقرّر موضع التخزين ومدّة الاحتفاظافتح بإصدار WinDbg نفسه وولِّد ‎.idx

الشكل 26: تسليم تتبّع تسليم ملفّ سرّي. قرّر الإجراء قبل أن تسجّل.

12. الخلاصة

  • التفريغ «حالة»؛ TTD هو «المسار». في الحالات التي تحتاج أصل قيمة فاسدة أو ترتيب الاستدعاءات يحوّل TTD التحقيق إلى عمل آلي
  • التسجيل أبطأ من 5 إلى 20 ضعفاً، وينمو بـ 5 إلى 50 ميغابايت في الثانية، ولا يستطيع الفصل. للتطبيقات طويلة التشغيل صمّم نطاق التسجيل أوّلاً بـ -ring/-maxFile و-module و-recordmode Manual و-monitor
  • إعادة التشغيل «ادخل عبر حدث، وامشِ إلى الخلف»: TTD.Events ثمّ [Time Travel] ثمّ t-/g- وba + g- لجعل المصحّح يجيب «من أفسده»
  • TTD.Calls وTTD.Memory استعلامات على التتبّع كلّه. طابق طوابع السجلّ الزمنيّة بـ ToSystemTime() وSystemTimeStart
  • لـ .NET اقرأ الحالة بـ SOS بـ 64 بت واستخدم TTD.Calls عند الحدود الأصليّة
  • التتبّع ملفّ سرّي. شارك ملف .run وحده، وقرّر القناة والتخزين أوّلاً

الحالات التي جُمع فيها تفريغ لكن السبب خارج المتناول، أو توقّف العمل لأنّ الخطأ لا يتكرّر، تُحسَم في كثير من الأحيان بـ TTD ما إن يمكن تصميم نطاق التسجيل. يمكننا أيضاً تولّي كلّ شيء من تصميم التسجيل إلى تحليل ملف .run، لذا تواصل مع تفريغاتك وسجلّاتك.

مقالات ذات صلة

مجالات الاستشارة ذات الصلة

تتعامل شركة كومورا سوفت ذ.م.م. مع تحقيق السبب الجذري لأخطاء تطبيقات Windows التي تظهر فقط بعد تشغيل طويل أو بشكل متقطّع، بجمع تفريغات الانهيار والسجلّات وتتبعات TTD؛ وبناء إعداد تحقيق يشمل تصميم نطاق التسجيل؛ وعزل الإخفاقات التي تتورّط فيها حدود أصليّة (COM وP/Invoke ومجموعات تطوير الأجهزة). تواصل مبكّراً من مرحلة «لدينا تفريغ لكن لا نصل إلى السبب».

روابط مرجعيّة

  1. Microsoft Learn, Time Travel Debugging - Overview. حول تسجيل TTD تنفيذ عمليّة وإعادة تشغيله أماماً وخلفاً، وميل التفريغات إلى تفويت الحالة ومسار التنفيذ اللذين أدّيا إلى الفشل، واشتراط التسجيل امتياز المسؤول، وإمكان احتواء التسجيلات معلومات شخصيّة وأمنيّة، وجدول مقارنة طرق التحقيق، وأدوار .run/.idx، وتصحيح الشيفرة المُدارة بامتداد SOS في وضع 64 بت.  2 3 4 5 6 7 8 9 10

  2. Microsoft Learn, Time Travel Debugging - TTD.exe command line utility. حول التباطؤ من 5 إلى 20 ضعفاً أو أكثر، والعجز عن فصل نفسه بعد الرفق، ودعم Windows Server 2016 إلى 2025، والتثبيت والنشر دون اتّصال، والأوضاع الثلاثة -launch/-attach/-monitor، والخيارات -out/-noUI/-accepteula/-stop/-wait/-tracingOff/-children/-cmdLineFilter/-timestampFilename/-ring/-maxFile/-maxConcurrentRecordings/-numVCpu/-replayCpuSupport/-module/-recordmode، وقراءة ملف .out، ونصيحة مشاركة التتبّعات.  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

  3. Microsoft Learn, Time Travel Debugging - Overview - Things to look out for. حول عدم التوافق مع برامج مكافحة الفيروسات ومراقبة الذاكرة وElectron، ووضع المستخدم فقط، وكون إعادة التشغيل للقراءة فقط، والعجز عن الحقن في العمليّات المحميّة (PPL)، وأثر الأداء بنحو 10 إلى 20 ضعفاً أثناء التسجيل.  2 3 4 5 6 7

  4. Microsoft Learn, Time Travel Debugging - Working with Trace Files. حول عوامل حجم التتبّع (بت واحد إلى بايت واحد لكلّ تعليمة)، والنمو بـ 5 إلى 50 ميغابايت في الثانية أثناء النشاط ولا شيء أثناء الخمول، وغياب سقف حجم أقصى، وكون الفهرس 1 إلى 2 ضعف التتبّع، وسلوك التسجيل والفهرسة عند نفاد القرص مع الحلّ.  2 3 4 5 6 7 8 9

  5. Microsoft Learn, Time Travel Debugging - Sample App Walkthrough. حول الإجراء العام للانتقال إلى موضع حدث استثناء والرجوع بـ ba وg- إلى الموضع الذي كُتبت فيه قيمة غير صالحة أخيراً، وكون نقطة الفشل غالباً داخل معالجة أخطاء عدّة خطوات بعد السبب الحقيقي، وإغلاق التتبّع عند انهيار وفهرسته تلقائيّاً من WinDbg، واستخدام TTD.Memory و.Last() 2 3 4 5 6 7

  6. Microsoft Learn, !tt (time travel). حول تحديد المواضع لـ !tt (نسبة مئويّة أو xx:yy)، ومعنى مكوّني الموضع (رقم التسلسل وعدد الخطوات)، وTTD.PrevRegisterWrite/PrevMemoryAccess/NextMemoryAccess 2 3 4

  7. Microsoft Learn, TTD Position Objects. حول Percent/Sequence/Steps لكائن Position، وSeekTo()، وToSystemTime() الذي يعيد زمن ساعة الحائط التقريبي (UTC)، وFFFFFFFFFFFFFFFE:0 الذي يدلّ على نهاية التتبّع.  2

  8. Microsoft Learn, Time Travel Debugging - Troubleshooting. حول اشتراط الارتفاع، وعدم دعم تسجيل إطلاق تطبيقات UWP، وخروج «العمليّات غير المعتادة» في جلسة أو سياق أمان آخر عن النطاق، والعزل بـ ping.exe/cmd.exe، وتباطؤ إعادة التشغيل عند استخدام Application Verifier في الوقت نفسه، وإعادة بناء الفهرس بـ !index -status/!index -force 2 3 4 5

  9. Microsoft Learn, Time Travel Debugging - Record a trace. حول التسجيل من Launch executable (advanced) / Attach to process في واجهة WinDbg، ومربع Record with Time Travel Debugging، وضبط موضع الحفظ بـ Configure and Record، وحصر الوحدات بـ Record subset of execution

  10. Microsoft, WinDbg-Samples - TTD in-process recording API (GitHub). حول وثائق واجهة التسجيل داخل العمليّة التي، مجتمعة مع -recordmode Manual، تتيح للبرنامج التحكّم ببدء التسجيل وإيقافه. 

  11. Microsoft Learn, Time travel debugging release notes. حول إصلاح التسجيل لبرامج تستخدم AVX/AVX512 وتغيّر تنسيق الفهرس (يلزم إعادة الفهرسة) في 1.11.611، و@$curframe.TTD.VariableHistory() المضاف في 1.11.553.  2 3

  12. Microsoft Learn, TTD Calls Objects. حول وسائط TTD.Calls، والخصائص ThreadId/UniqueThreadId/Function/ReturnValue/ReturnAddress/Parameters[]/TimeStart/TimeEnd/SystemTimeStart/SystemTimeEnd، والافتراضيّات عند غياب معلومات رموز PDB (أربعة وسائط أعداد صحيحة 64 بت بلا إشارة، UnknownOrMissingSymbols)، واستغراق الحساب وقتاً مع تخزين النتائج مؤقّتاً.  2 3 4 5 6 7

  13. Microsoft Learn, Time Travel Debugging - Replay a trace. حول التنفيذ العكسي بـ p-/t-/g-، وتوقّف g- عند الأحداث نفسها للتنفيذ الأمامي، و!positions، وكون ~s لا يغيّر الموضع في التتبّع.  2 3

  14. Microsoft Learn, TTD Event Objects. حول أنواع الأحداث (ThreadCreated/ThreadTerminated/ModuleLoaded/ModuleUnloaded/Exception) والكائنات الابن Position وModule وThread وException. 

  15. Microsoft Learn, TTD Exception Objects. حول Type (Software/Hardware) وProgramCounter وCode وFlags وPosition لكائن الاستثناء. 

  16. Microsoft Learn, WinDbg: Timelines. حول نافذة Timelines التي تصوّر الاستثناءات ونقاط التوقّف ووصولات الذاكرة واستدعاءات الدوال، والنقر المزدوج على استثناء يصدر Position.SeekTo()

  17. Microsoft Learn, !positions. حول عرض كلّ خيط نشط وموضع كلّ خيط في التتبّع.  2

  18. Microsoft Learn, Introduction to Time Travel Debugging objects. حول كائنات @$curprocess.TTD / @$cursession.TTD، والاستعلامات بـ OrderBy/Where/Select/GroupBy، وأمثلة تجميع أخطاء GetLastError وإيجاد آخر استدعاء لـ MessageBoxW، ومعنى UnknownOrMissingSymbols، والأسباب الأربعة لعدم إرجاع Calls شيئاً.  2 3 4 5

  19. Microsoft Learn, TTD Memory Objects. حول أنواع وصول TTD.Memory (r/w/rw/e/rwe/ec) والانتقال إلى موضع عبر رابط [Time Travel] في النتائج. 

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

ما الفرق بين Time Travel Debugging (TTD) وتفريغ الانهيار؟
تفريغ الانهيار صورة لذاكرة لحظة الانهيار: يُظهر الحالة في تلك اللحظة، لا المسار الذي أدّى إليها. تتبّع TTD تسجيل كامل لتنفيذ تعليمات العمليّة يمكن إعادة تشغيله لاحقاً أماماً وخلفاً، لذا يمكنك الإرجاع والتحقّق مباشرة ممّن كتب المتغيّر أخيراً أو ما استُدعي قبل الاستثناء مباشرة. تنصّ وثائق Microsoft الرسميّة أيضاً على أنّ التفريغات تميل إلى تفويت الحالة ومسار التنفيذ اللذين أدّيا إلى الفشل. الثمن أنّ العمليّة تعمل أبطأ من 5 إلى 20 ضعفاً أثناء التسجيل، وينمو ملف التتبّع بنحو 5 إلى 50 ميغابايت في الثانية بينما العمليّة نشطة.
هل يمكن ترك TTD معلّقاً على تطبيق إنتاج يعمل أيّاماً؟
ليس كما هو. يبطئ TTD العمليّة كثيراً أثناء التسجيل، وينمو التتبّع بـ 5 إلى 50 ميغابايت في الثانية في عمليّة نشطة، ولا سقف لحجم الملفّ. استخدامه على تطبيق طويل التشغيل يفترض تصميم تسجيل: -ring (مخزن حلقي) في TTD.exe مع -maxFile لإبقاء آخر N ميغابايت فقط، و-module للتسجيل فقط أثناء تشغيل وحدتك، أو -recordmode Manual لترك التطبيق يختار فاصل التسجيل. كذلك، ما إن يُرفَق TTD لا يستطيع فصل نفسه، لذا يجب أن تقرّر مسبقاً كيف تنهي التسجيل، وهذا يعني إنهاء العمليّة (إعادة تشغيلها).
هل يمكن تسجيل الخدمات والعمليّات في جلسات أخرى؟
تصف وثائق TTD.exe ‏-attach بأنّه موجَّه للتحقيق في الخدمات والتطبيقات طويلة التشغيل، و-monitor بأنّه يسجّل في كلّ مرّة يبدأ فيها برنامج أو خدمة. من جهة أخرى تنصّ صفحة استكشاف الأخطاء على أنّ العمليّات غير المعتادة التي تعمل في جلسة أخرى أو سياق أمان مختلف غير مدعومة حاليّاً للتسجيل. ما إذا كان يعمل فعلاً يعتمد على البيئة، لذا سجّل أوّلاً عمليّة بسيطة مثل ping.exe أو cmd.exe في التكوين نفسه للإنتاج، ثمّ جرّب العمليّة المستهدَفة، وبعد ذلك فقط أدخله في تشغيلك.
هل يمكن استخدام TTD على تتبّعات تطبيقات .NET؟
نعم. تنصّ الوثائق الرسميّة على أنّ امتداد SOS (sos.dll) العامل في وضع 64 بت يمكن استخدامه على تتبّع TTD في WinDbg لتصحيح الشيفرة المُدارة. النمط الأساسي تشغيل أوامر SOS مثل !clrstack و!pe عند كلّ موضع في التتبّع، بالانتقال إلى موضع حدث استثناء ثمّ قراءة المكدّس المُدار. يعتمد استعلام TTD.Calls، الذي يبحث عن الاستدعاءات باسم الرمز، على معلومات رموز PDB، لذا في تطبيقات .NET الاستخدام الموثوق تتبّع الاستدعاءات عبر الحدود الأصليّة مثل P/Invoke وCOM وواجهات Win32.
هل من الآمن إرسال ملف تتبّع (‎.run) إلى شركة أخرى أو خارج المنظّمة؟
ليس كما هو. يحتوي تسجيل TTD محتويات ذاكرة العمليّة، وتنصّ الوثائق الرسميّة صراحة على أنّه يمكن أن يشمل معلومات شخصيّة أو سرّيّة مثل مسارات الملفّات وبيانات السجلّ ومحتويات الذاكرة والملفّات. إذا أرسلت واحداً فافهم أوّلاً ما سُجِّل (سلاسل الاتّصال والرموز وبيانات العملاء وما شابه)، ثمّ قرّر قناة نقل مشفَّرة وموضع تخزين. يكفي مشاركة ملف ‎.run وحده؛ يُولَّد ملف الفهرس (‎.idx) تلقائيّاً عندما يفتحه WinDbg.
لا يعيد TTD.Calls شيئاً عندما أبحث عن دالّة. لماذا؟
هناك أربعة أسباب رئيسة. أوّلاً الرموز: تُسمَّى الدوال في وحدة بلا PDB باسم UnknownOrMissingSymbols، وقد يكون اسم الوحدة بأحرف كبيرة، لذا راجع اسم الرمز الفعلي بأمر x. ثانياً قد لا تكون DLL المستهدَفة محمَّلة بعد في ذلك الموضع؛ انتقل إلى موضع بعد تحميل DLL واستعلم مجدّداً. ثالثاً إذا كانت الدالّة مضمَّنة لا يستطيع محرّك الاستعلام تتبّعها. رابعاً قد يكون البدل واسعاً جدّاً فيطابق دوالاً كثيرة؛ ضيّق النمط.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

يركّز على تطوير برامج ويندوز، والاستشارات التقنية، والتحقيق في الأخطاء، ويتميّز في المشاريع التي تبقى فيها الأصول القديمة ناشطة، وفي تشخيص الأعطال التي يصعب تحديد سببها.

العودة إلى المدونة