تجزیه و تحلیل پویا برنامه ی خودتان: بازپسین، ردیابی و تایید ادعاهای ثابت
Type: Build
Languages: Python, TypeScript, C, arm64 assembly, lldb command language
Prerequisites: Phase 13 · 33 (disassembly and control flow), Phase 13 · 35 (evidence, confidence, and unknowns)
Time: ~130 minutes
اهداف یادگیری
- توضیح دهید که یک debugger از سیستم عامل در لینوکس چه نیاز دارد (
ptrace) و در macOS (مرکز وظایف و پورتهای استثناء) و چرا یک پوسته قشنگ نمی تواند یک debugee را راه اندازی کند. - نقاط شکافی نرم افزار را با نام و با فهرست آدرس تنظیم کنید، یک نقطه نظارت سخت افزاری را تنظیم کنید و محدودیت هایی را که پردازنده برای هر دو اعمال می کند، بخوانید.
- lldb را در حالت دسته از پایتون با یک هک توقف که متغیرهای ثبت، حافظه و فریم را در هر توقف ثبت می کند، و نقل متن را به یک خط زمانی بازمی کند.
- ادعاهای جامد را از درس های 32، 33، 34 و 41 با آن جدول زمانی بررسی کنید: ثبتات استدلال، تعویض میدان ساختاری، کناره ای که شاخه مشروط گرفته و کدام تماس ها رخ داده است.
- همون نقشه رو با يه نفر اجرا کن
-O2بنویسید، نقطه های شکافی را بخوانید که حل می شوند و هرگز نمی رسند و بگویید که چه چیزی ثابت می کند و چه چیزی ثابت نمی کند. - یک فایل هسته ای را ذخیره کنید و بارگذاری کنید و نام آنچه را که یک هسته سبک ستاک از آن خارج می کند را نام ببرید.
- نقشه ی مجموعه های دستور GDB و LLDB را قرار دهید و قرار دهید
strace،ltrace،bpftrace،dtraceوrrدر سیستم عامل مناسب با نسخه ها و مجوزهای آنها. - حقایق رمزگذاری مکوس را که اجازه می دهد lldb یک دوگانه ای را که شما خودتان ساخته اید، و دو شرایطی را که تحت آن انکار می کند، بیان کنید.
مشکل
درس 41 مطالعه کنیدstruct accountاز DWARF و گفتbalanceدروس 33 نمودار کنترل جریان را ساختclassifyو گفت که اولين شاخه به سمتreturn -1در درس 32 گفته شد که دو استدلال اول درx0وx1هرکدوم از اين جمله ها از بايت ها مشتق شده بود هيچکدوم از آنها مشاهده نشد
بعد يه مامور همون برنامه رو ميخواد و گزارش ميده "موبايل اصلي"bump،classifyوsum_balancesجدول نماد ها سه تا را فهرست می کند، بنابراین جمله به نظر می رسد امن است. شما برنامه را در -O2، نقطه شکافی را در هر تابع تنظیم کنید و آن را اجرا کنید. فرآیند چهار خط و خروج آن را چاپ می کند. هر نقطه شکافی گزارش می دهدhit count = 0. .
مامور در مورد منبع اشتباه نبود، در مورد ساخت و سازی که ازش پرسیده شده اشتباه بود.sum_balances(rows, 3)تنها راه که می تونیم بدونیم که این دوگانه روی این ماشین چیه اینه که زیر یک دیبگر اجرا کنیم و ببینیم
این درس یک آبرسی می سازد که به دنبالش می رود.account.c، لیست را می خواند، یک جلسه LLDB را برنامه ریزی می کند، آن را اجرا می کند و هر ادعای جامد را با آنچه توقف نشان می دهد، رتبه بندی می کند.confirmedیعنی توقف ثابت کرد که ادعا برای این مسابقه درست است.refutedیعنی یه توقف که ثابت کرده که غلطهnot-observedو درسي 35 هر حکم رو به عنوان يکobservedثبت با مقامcontrolled-replay. .
یک Debugger سه سرویس سیستم و یک میز است
یک دیبگر چهار کار را برای یک فرآیند انجام می دهد که کد آن را ندارد. این فرآیند را متوقف می کند، ثبتات خود را می خواند و می نویسد، حافظه خود را می خواند و می نویسد و می گوید که فرآیند دوباره متوقف می شود. هسته هر یک از این موارد را به عنوان یک سرویس ارائه می دهد و خدمات با سیستم عامل متفاوت است.
در لینوکس سرویس این استptrace(2)در صفحه راهنما آمده است که "وجود دارد که به وسیله آن یک فرآیند (تراسر) می تواند اجرای یک فرآیند دیگر را مشاهده و کنترل کند".PTRACE_TRACEMEاجازه می دهد تا یک کودک اعلام کند که پدر و مادرش دنبالش می گردندPTRACE_ATTACHیک فرآیند غیر مرتبط را انجام می دهد.PTRACE_PEEKDATA"کلمه اي در آدرس "در خاطره "تراسي"PTRACE_GETREGSکتاب نامه ها رو میخواد وPTRACE_SINGLESTEPیک دستور اجرا می کند. محدودیت های ماژول یاما:/proc/sys/kernel/yama/ptrace_scopeدر حالت پیش فرض از 1 به این معنی است که "عملیات هدف باید یک نسل از تماس گیرنده باشد"، 2 به این معنی است که فقط یک مدیر می تواند آن را اضافه کند، و 3 به این معنی است که هیچ کس نمی تواند.
در macOS ptraceاین یک رابط کوچک تر است. لیست های دستی اپل.PT_TRACE_ME،PT_ATTACHEXC،PT_STEP،PT_CONTINUEوPT_KILL، و ميگه که باPT_ATTACHEXC"سيگنال هاي بچه به والد مياد به عنوان استثنايي که ماش ميکنه"ptraceاصلاً.debugserverتماس هاtask_for_pid()برای گرفتن یک پورت کار ماچ برای فرآیند، پسtask_set_exception_ports()تا نقطه های تعطل به عنوان پیام های استثنایی وارد شوند.taskgatedتصمیم میگیر که کی می تونه زنگ بزنهtask_for_pid. .
شما می توانید هزینه این طراحی را در یک نقل از این درس مشاهده کنید. پوسته جلسه تحت یک جعبه شن سیت بیلت می رود. همان طرح که ۱۱ توقف خارج از جعبه شن تولید می کند این را در داخل آن تولید می کند:
(lldb) run
error: process exited with status -1 (attach failed ((os/kern) invalid address))این فرآیند ساخته شده و بعد از آن قابل قبول نشد. خطا در مورد حقوق دیبگر است و چیزی در مورد برنامه نمی گوید. هنیس آن را به عنوان شکست راه اندازی ثبت می کند، با صفر توقف و هیچ حکم.
جدول جدول نقطه شکاف است. Debugger به یاد می آورد که کدام بایت دستورالعمل را در کدام آدرس جایگزین کرده است، بنابراین می تواند اصل را در ادامه برگرداند و تعداد ضربه ها را به هر مکان محاسبه کند. breakpoint listاون ميز رو چاپ ميکنه و هر بار که مي ريد، هيرنسش ميخواد بخونه
نقطه های قطع: یک بایت یا یک کلمه جایگزین شده
نقطه شکافی نرم افزار یک دستورالعمل است که پردازنده آن را به دام می زند، نوشته شده بر روی اولین بائتهای دستورالعمل که می خواهید در آن متوقف شوید. در x86-64 که استINT3، کد آپکودCC، یک بايت طول دارد که راهنمای اینتل آن را "برای تماس با عامل استثناء های دیبگ" توصیف می کند. در arm64 این استBRK #imm16، یک دستورالعمل چهار بایت که استثنا "استثناء را در ESR_ELx با استفاده از ارزش EC 0x3C ثبت می کند".BRKدستورالعمل خود را، که به همین دلیل است که یک توقف آدرس دستورالعمل جایگزین را گزارش می دهد و نه آن را که بعد از آن است.
lldb نقاط شکاف را با نام، با فایل و خط، یا با آدرس تنظیم می کند. با نام از پیشگویی خارج می شود:
(lldb) breakpoint set -n bump
Breakpoint 1: where = account-O0`bump + 12 at account.c:13:19, address = 0x00000001000004bcbump + 12اين چهارمين دستور است. سه تا قبل از آنsub sp, sp, #0x10،str x0, [sp, #0x8]وstr w1, [sp, #0x4], تنظیم قاب که جدول خط DWARF به خط باز کردن تابع نسبت می دهد.x0وx1هنوزم استدلال ها رو نگه داريم چون مقدمه فقط کپي کردنشون
با عنوان، lldb باید بداند که آدرس به کدام ماژول تعلق دارد.breakpoint set -a 0x100000504قبل از اینکه فرآیند وجود داشته باشد، یک آدرس بار بدون بخش پشت آن وجود دارد و در یک آزمایش اول باقی ماند unresolvedدر تمام طول طول راهhit count = 0. شکلي که در بند استفاده ميکند اسم ماژول رو ميگيره:
(lldb) breakpoint set -a 0x100000504 -s account-O0
Breakpoint 4: address = 0x0000000100000504با-sشماره یه آدرس فایل در داخلشaccount-O0, lldb اسلاید بار اضافه می کند و بعد از اجرا موقعیت می خواند resolved, hit count = 2.درسه 33 فهرست داده شده آدرس فایل را می دهد، بنابراین این فرم است که یک لیست ثابت را به یک توقف پویا متصل می کند.
شاخه رو دستي رمزگشایی کن
اولين شاخه مشروط در سالclassifyدر-O0اين کلمه36f800a8در0x1000004f0، کهllvm-objdumpچاپ شدهtbz w8, #0x1f, 0x100000504. از رمزگشایی بازوی A64 آن را رمزگذاری کنیدTBZ. .
- بيت 31
b5،بيت بالا از عدد بيت. - بایت 30 تا 25
011011، گروه آزمون و شاخه. بیت 24 0 است که انتخاب می کندTBZو نهTBNZ. . - بایت 23 تا 19
b40، پنج قطعه کم از تعداد بيت:11111= 31b5= 0 بیت آزمایش شده 31 است، بیت علامت با یک مقدار 32 بیت. - بایت 18 تا 5
imm14.00000000000101= 5 . تعویض شاخهimm14 * 4= 20 =0x14، پس هدفش0x1000004f0 + 0x14 = 0x100000504. . - بایت 4 تا 0
Rt.01000=8، پس ثبتشw8. .
w8يه دستور قبل از اين توسط ldr w8, [x8, #0x4]، کهa->balanceدر آفسه 4. TBZشاخه ها وقتی بیت صفر است. شاخه زمانی گرفته می شود که بیت علامت روشن باشد، که balance >= 0. منبع نوشتهif (a->balance < 0) return -1;، پس کمپایلر حالت رو عوض کرد: کناره گرفته شده از return -1بلوک و سقوط در0x1000004f4بنابراین ادعای جامد که در آستین حمل می شود، یک ادعای حاشیه با یک پیشگوئی است: زمانی کهa->balance >= 0. در غیر اینصورت ، از طریق سقوط می شود.subs w8, w8, #0xc8حساب هاbalance - 200وb.le 0x100000524وقتی که حداکثر صفر باشد، که balance <= 200. .
نگهبانان سخت افزار اندک هستند
یک نقطه نظارت در هنگام دسترسی به حافظه در یک آدرس فرآیند را متوقف می کند. این نمی تواند یک دستورالعمل جایگزین باشد، زیرا هر دستورالعمل در هر نقطه ممکن است دسترسی را انجام دهد. بنابراین پردازنده ها مجموعه ای کوچک از مقارنات آدرس را دارند. در x86-64 آنها ثبت کننده های دیبگ هستند:DR0از طریقDR3"درسته های تا چهار نقطه توقف" را داشته باشد وDR7در arm64 زوج ها در طول یک بایت (۱،۲،۴ یا ۸ بایت) قرار می گیرند.DBGWVR<n>_EL1، که "آدرس مجازی داده های مورد استفاده برای مطابقت نقطه نظرتان را نگه دارد" وDBGWCR<n>_EL1برای کنترل ها، و راهنمای بازو می گوید "یک پیاده سازی می تواند بین 2 تا 64 نقطه نظارت را شامل شود".
lldb گزارش داده که شماره ای که داده شده:
(lldb) watchpoint set variable a->balance
Watchpoint created: Watchpoint 1: addr = 0x16fdfe00c size = 4 state = enabled type = m
(lldb) watchpoint list
Number of supported hardware watchpoints: 4چهار تا از اين دستگاه، آدرس نظارت شده0x16fdfe00c.x0 + 4: نشانگر ساختاری در bumpتوقف به اضافه ازشوی DWARFbalance.size = 4.int.type = mوقتی نقاط در نظر گرفته شده از LLDB به نقطه مشاهده بعدی دست نمی دهد و از آنجا که یک منطقه که خط بندی نشده یا قدرت دو نیست می تواند دو نقطه را بگیرد، تعداد نقاط مشاهده شما می تواند کمتر از چهار باشد.
در راهنمای اینتل آمده است: "یک دستورالعمل که حافظه را می نویسد، داده های اصلی را قبل از ایجاد استثناء دیبگ ناشی از نقطه شکستگی داده ها از بین می برد".
Watchpoint 1 hit:
old value: 250
new value: 255
* thread #1, queue = 'com.apple.main-thread', stop reason = watchpoint 1
frame #0: 0x00000001000004d0 account-O0`bump(a=0x000000016fdfe008, by=5) at account.c:14:12توقف در0x1000004d0، دستورالعمل بعد ازstr w8, [x9, #0x4]در0x1000004ccقبل از اينکه محصول رو تحليل کني بايد يه چيز رو بدونيwatchpoint set، چاپ های بیگانهWatchpoint 1 hit:با ارزش قدیمی خالی وnew value: 250اين اولين خوندنيه و هنيز يه ضربه بدون ارزش قديمي رو نادیده ميگيره
قدم زدن، توقف قوس ها و حالت دسته بندی
دستور دستور زبان LDB<noun> <verb> [-options] [arguments]. فعل قدم زدنthread step-in(s)thread step-over(n)thread step-inst(si)thread step-inst-over(ni) وthread step-out(finish)thread until 12به خط مي رفتهthread return <expr>با یک مقدار زود برگشت می کند. آرک به قدم نمی رود. در آدرس های برنامه ریزی شده متوقف می شود و اجازه می دهد یک هک توقف انجام دهد:
target stop-hook add -o "register read x0 x1 pc" -o "memory read -s4 -fx -c24 $x0" -o "frame variable -P 1"-oممکن است تکرار شود و فرمان ها در هر توقف به ترتیب اجرا می شوند.register readنام دو پرونده استدلال و شمارنده برنامه. memory read -s4 -fx -c24 $x024 کلمه چهار بايت در hex از آدرس در x0، که 96 بايت است، سهstruct accountصف هاframe variable -P 1این کتاب استدلال ها و مقایسه ها را چاپ می کند و اشاره ها را به یک سطح گسترش می دهد، بنابراین aپنج میدانش را نشان می دهد.
حالت دسته بندیlldb -b. در اين راهنما ميگه--batchدستورات رو از-s،-S،-oو-Oو سپس متوقف می شود، و اگر یک فرمان به دلیل سیگنال یا خرابی متوقف شود، Debugger به پیامک تعاملی باز می گردد.-s. يه موضوع مهم:settings set interpreter.stop-command-source-on-error falseبدونش اولينcontinueپس از خروج از فرآیند تمام پرونده پایان می یابد وbreakpoint listهيچ وقت نميچرخ.error: Process must be launched.و ادامه می دهد.
دو واقعیت در مورد شکل خروجی تعیین می کند که پارسر چگونه کار می کند. اول، خروجی هک در حالی که هک اجرا می شود چاپ می شود و Process N stoppedبلوک با اونframe #0خط بعد از آن چاپ می شود. بنابراین پارسر خط های ثبت، حافظه و متغیر را به یک قطعه منتظر جمع آوری می کند و قطعه را به بعدی متصل می کند frame #0خطي که مي دونه يه قطعه که برنامه اش در حسابش هستdyldدر_dyld_startاین توقف ورود قبل از اجرای برنامه است و نهframe #0دوم، نقطه شکاف با--auto-continueدر این برنامه، نقطه توقف ساده ای و بودجه ثابت از ۰،۰۰۰ دلار استفاده می شود.continueدر عوض دستورات
نقشه از لیست آمده است
Plan.commands()فایل فرمان را از llvm-objdump -dمتن دوگانه ای که اجرا می شود.account-O0:
breakpoint set -n bump
breakpoint set -n classify
breakpoint set -n sum_balances
breakpoint set -a 0x100000504 -s account-O0
breakpoint set -a 0x1000004f4 -s account-O0
breakpoint set -a 0x100000524 -s account-O0
breakpoint set -a 0x100000514 -s account-O0
target stop-hook add -o "register read x0 x1 pc" -o "memory read -s4 -fx -c24 $x0" -o "frame variable -P 1"
run
watchpoint set variable a->balance
watchpoint list
continue
...
breakpoint list
watchpoint list -vسه نقطه شکافی نام ورودی تابع هستند. چهار نقطه شکافی آدرس هدف و سقوط از هر شاخه مشروط است که Listing.conditional_branches()در اینجا پیدا می کنهclassify.tbzدر0x1000004f0وb.leدر0x100000510. نقطه مراقبه در اولین توقف قرار گرفته است که برنامه انتظار می رودbump. 16continueدستورات بیشتر از هر نیاز اجرا می شود و بقایای پس از خروج بی ضرر شکست می خورند بودجه دانش در مورد برنامه نیست. این یک سقف است.
ادعاها از همان ورودی ها ساخته شده اندclaims_for():
| Id | Kind | Claim | Source |
|---|---|---|---|
arg-registers | argument-register | at every entry the first arguments arrive in x0 and x1 | lesson 32 and AAPCS64 |
field-offsets | field-offset | struct account is 32 bytes with kind at 0, balance at 4, code at 8, rate at 16, label at 24 | lesson 41 and the DWARF dump |
branch-1 | branch-taken | tbz at 0x1000004f0 goes to 0x100000504 when a->balance >= 0, otherwise to 0x1000004f4 | lesson 33 edges and the lesson 34 lift |
branch-2 | branch-taken | b.le at 0x100000510 goes to 0x100000524 when a->balance <= 200, otherwise to 0x100000514 | lesson 33 edges and the lesson 34 lift |
calls | call-edge | main calls bump once, classify three times, sum_balances once | source text and nm |
store-once | store | bump writes a->balance once and the new value is the old value plus by | lesson 34 pseudocode |
stride | struct-stride | list[i].balance sits at list + 32*i + 4 | lesson 41 and the psABI aggregate rule |
output | behaviour | the program prints class 0 1 -1 and sum 315 | source arithmetic |
تعویضات ساحه ازstruct_layout()، که میگهDW_TAG_structure_typeباDW_AT_byte_size (0x20)و پنج نفرDW_TAG_memberنوشته ها با نوشته های خودDW_AT_data_member_locationنقشه هرگز شماره 4 رو تایپ نميکنه
مسابقه در -0: 11 توقف
اولين توقف اينهbumpنقطه شکاف. هک قبل از بلوک توقف اینو چاپ کرد:
x0 = 0x000000016fdfe008
x1 = 0x0000000000000005
pc = 0x00000001000004bc account-O0`bump + 12 at account.c:13:19
0x16fdfe008: 0x00000073 0x000000fa 0x00000009 0x00000000
0x16fdfe018: 0x00000000 0x3ff40000 0x00000719 0x00000001
0x16fdfe028: 0x0000006c 0xffffffd8 0x00000003 0x00000000
0x16fdfe038: 0x00000000 0x40000000 0x00000721 0x00000001
(account *) a = 0x000000016fdfe008 {
kind = 's'
balance = 250
code = 9
rate = 1.25
label = 0x0000000100000719 "savings"
}
(int) by = 5هشت کلمه اول ردیف را در برابر آفسه های DWARF بخوانید. کلمه 0 در آفسه 0 است 0x73، که's'،kindبايت، بعد از آن سه بايت پر کردن. کلمه 1 در آفسيت 40xfa= 250،balanceکلمه 2 در آفسيت 80x9،code، یکshortدر نیمه پایین با دو بایت پر کردن بالای آن. کلمه 3 در آفسیت 12 قبل از 8- بایت متفق استdouble. کلمات 4 و 5 در آفسيت 160x3ff4000000000000، که کد IEEE-754 از 1.25. کلمات 6 و 7 در آفسه 24 هستند0x100000719،labelاشاره به __TEXTهشت کلمه بعد با شروع مي شه0x6c= 'l'و0xffffffd8= -40: ردیف سوم، loanبعد از 32 بايت هر عدد با هم موافقهframe variable، پس_check_layout()سوابقfield-offsetsمثلconfirmedدر اين توقف و دوباره در هر يك از 11 توقفx0یک شاخص ساختاری دارد.
x0برابر استaوx1برابر استby، پسarg-registersدر این ورودی تایید شده است.classifyتوقف می کنهx1هنوزم مي خواد0x5، بقيه ازbumpوclassifyیک پرونده که هیچ بحثی در آن زندگی نمی کند شور است و ادعای درس 32 هیچ چیز در مورد آن نمی گوید.
دومين توقف، نقطه نظري، ارزش قديمي 250، ارزش جديد 255by=5 . یک ضربه در تمام اجرا، پسstore-onceپس سه فعاليت ازclassify، هر کدام با توقف ورودی خود و یک یا دو توقف لبه خود:
| Stop | Address | Stop reason | What it tests |
|---|---|---|---|
| 2 | 0x1000004e8 | breakpoint 2.1 | entry, a->balance = 100, x0 = a |
| 3 | 0x100000504 | breakpoint 4.1 | tbz taken, 100 >= 0, branch-1 confirmed |
| 4 | 0x100000524 | breakpoint 6.1 | b.le taken, 100 <= 200, branch-2 confirmed |
| 5 | 0x1000004e8 | breakpoint 2.1 | entry, a->balance = 255 |
| 6 | 0x100000504 | breakpoint 4.1 | tbz taken, 255 >= 0 |
| 7 | 0x100000514 | breakpoint 7.1 | b.le fell through, 255 > 200 |
| 8 | 0x1000004e8 | breakpoint 2.1 | entry, a->balance = -40 |
| 9 | 0x1000004f4 | breakpoint 5.1 | tbz fell through, -40 < 0 |
| 10 | 0x100000544 | breakpoint 3.1 | sum_balances entry, x1 = 3 |
_check_branches()گروه توقف ها را به فعال سازی ها، تعادل را در ورودی می خواند و برای هر توقف حاشیه جانشین را محاسبه می کند پیش بینی های پیش بینی شده. پنج توقف حاشیه، پنج توافق:branch-1سه بار تایید شدbranch-2دو بار. توقف 5 نشان می دهد که تعادل به عنوان 255 است که ارزش نقطه مشاهده نوشته شده است. اجرا یک برنامه است و شواهد متصل است.
در توقف 10 ، هک 24 کلمه ازlist._check_stride()کلمه 1، کلمه 9 و کلمه 17 را می گیرد که تعویضات 4، 36 و 68: 100، 255 و -40 هستند.classifyدر همان آدرس مشاهده کرد، آنها را به 315 جمع می کند و مجموع را با sum 315خط برنامه چاپ شده است. سپس فرآیند با وضعیت 0 و breakpoint listتعداد ضربات را برای نام ها 1، 3 و 1 و برای چهار لبه 2، 1، 1 نشان می دهد.confirmed، با 25 رکورد پشت سرشون، 23 تا رکورد و دو تا رکورد
-O2 - صفر توقف
همون منبع در-O2برنامه ي ديگه اي هستllvm-objdump -dازmainچهار تا دارهblدستورالعمل ها، همه بهprintf. به جای تماس هایی که دارهmov w8, #-0x1،mov w8, #0x1، صفر از طریقxzrوmov w8, #0x13b، که 315 است. کمپایلر هر نتیجه را در زمان مرتب کردن محاسبه کرد.nmلیست های هنوز_bump،_classifyو_sum_balances، چون آنها تابع های خارجی هستند و نسخه های خارج از خط برای سایر اشیاء برای تماس وجود دارد.DW_TAG_subprogramورودی برای تمام چهار تابع و صفرDW_TAG_inlined_subroutineواردات، بنابراین حتی اطلاعات دیبگ، واردات را ثبت نمی کند.
نقشه این ساختمون سه نقطه شکافی نام دارد و هیچ نقطه شکافی حاشیه ای ندارد.classifyدر-O2شش دستورات استldr،cmp،cset،cmp،csinv،ret، بدون شاخه مشروط در آن.-O0لیست ها در این دوگانه آدرس ندارند و آستین آنها را حمل نمی کند. ادعای مربوط به یک لبه متعلق به ساختمان است که لیست آن لبه دارد.
مسابقه:
(lldb) breakpoint set -n bump
Breakpoint 1: where = account-O2`bump at account.c:13:16, address = 0x0000000100000460
(lldb) run
sizeof 32 align 8
offsets 0 4 8 16 24
class 0 1 -1
sum 315
Process 48444 exited with status = 0 (0x00000000)
(lldb) watchpoint set variable a->balance
error: Command requires a process which is currently stopped.
(lldb) breakpoint list
1: name = 'bump', locations = 1, resolved = 1, hit count = 0هر نقطه شکاف حل شده آدرس وجود داره نماد وجود داره و lldb يه حرف نوشتهBRKتعداد کشته ها صفر شده چون هيچ اطلاعاتي به عنوان آدرس رسيد
| Claim | Verdict | Record |
|---|---|---|
calls | refuted | after a full run with exit status 0, entry stops bump 0, classify 0, sum_balances 0 |
output | confirmed | the four lines and exit status 0 |
arg-registers | not-observed | no stop tested it, hit counts all 0 |
field-offsets | not-observed | no stop tested it |
store-once | not-observed | no stop in bump, so the watchpoint was never set |
stride | not-observed | no stop in sum_balances |
در مورد اين که اين رد شده درست بگيmainبه سه تابع در این برنامه میگه. برای این ساخت و این اجرا این کار را نمی کند، و آستین بررسی کرد که اجرا به پایان رسیده است، زیرا تعداد ضربه صفر قبل از خروج تنها به این معنی است که اجرا هنوز به تماس نرسیده است. ادعا نمی گوید که عملکردها کد مرده هستند و اجرا هم نمی گوید که: آنها صادر می شوند و یک شی دیگر می تواند آنها را فراخوانی کند. چهار ادعای دیگر نه تایید شده و نه رد شده است. ساختار هنوز دارهbalanceدر آفسيت 4 در اين ساخت و ساز-O2DWARF ميگه، ولي هيچ توقف در اين اجرا يادداشت يادگيري را براي نشان دادنnot-observedو درس 35، ناشناخته را تا زمانی که یک مسابقه آن را مشاهده کند باز نگه می دارد.
مواد زباله هسته ای
یک فایل اصلی حافظه و ثبتات فرآیند است که به دیسک نوشته می شود، بنابراین دیبگر می تواند یک برنامه متوقف شده را پس از رفتن برنامه بخواند.core(5)می گوید "یک تعداد کوچک از سیگنال هایی که باعث توقف غیر طبیعی یک فرآیند می شوند، باعث می شوند یک رکورد از وضعیت اصلی فرآیند به دیسک نوشته شود"./cores/core.pid، "به شرط اينکه پروسه اي که تموم شده بود اجازه نوشتن در فهرست داشته باشه و فهرست وجود داشته باشه"sysctlگزارش هاkern.coredump: 1وkern.corefile: /cores/core.%P،/coresبا حالت وجود دارهdrwxrwxr-t root admin، و پوستهulimit -c0 است. تا زمانی که حد را با افزایش دهید هیچ هسته ای نوشته نمی شود.ulimit -c unlimited، یا در کل سیستم با launchctl limit core unlimited. .
.آلباير به صورت طلبي بدون تصادف هسته اي مي نويسهbumpنقطه شکاف:
(lldb) process save-core --style stack account-O0-stack.core
Saving 49152 bytes of data for memory region at 0x16fdf4000
Modified-memory or stack-memory only corefile created. This corefile may
not show library/framework/app binaries on a different system, or when
those binaries have been updated/modified. Copies are not included
in this corefile. Use --style full to include all process memory.فایل 53248 بايت بود و براي بارگذاری به دوگانه ي کنارش نياز داره
(lldb) target create "./account-O0" --core "account-O0-stack.core"
(lldb) bt
* thread #1, stop reason = ESR_EC_BRK_AARCH64 (fault address: 0x0)
* frame #0: 0x00000001000004bc account-O0`bump(a=0x000000016fdfe008, by=5) at account.c:13:19
frame #1: 0x0000000100000640 account-O0`main at account.c:40:5
frame #2: 0x000000019a949d54 dyld`start + 7184
(lldb) frame variable *a
(account) *a = (kind = 's', balance = 250, code = 9, rate = 1.25, label = "")
(lldb) frame variable a->label
(const char *) a->label = 0x0000000100000719 ""پس زمینه و رشته های عددی سالم هستند، چون روی سکه ای که هسته نجات داده زندگی می کنند.labelچاپ شده به عنوان یک رشته خالی با اشاره کننده سالم0x100000719درست است، بائتهایی که به آن اشاره می کند حرفی هستند"savings"در__TEXTبخش قابل اجرا، و یک هسته سبک استیک شامل آن بخش نیست. اشارهگر یک مشاهده است. رشته در دسترس نیست، و lldb آن را اختراع نمی کند. --style fullشامل تمام حافظه فرآیند است و هسته کامل این برنامه 34 کیلو با اندازه 2.1 گیگابایت در ماشین تحقیق بود، زیرا فرآیند نقشه کش مشترک را می گیرد. دلیل توقف می گویدESR_EC_BRK_AARCH64: هسته ثبت شده است BRKاستثنایی که نقطه شکافی مطرح کرد
در لینوکس هسته هسته را بر اساس/proc/sys/kernel/core_pattern، یک قالب با %pبرای PID%eبرای نام فرمان،%sبرای سیگنال و%tو به عنوان رهبر|لوله هاي زباله به برنامه اي مي رسنsystemd-coredumpوcoredumpctl list،info،dumpوdebugاون چيزي که نگه داشته بود رو بازگيري ميکردمgdb prog coreوlldb -c core progهر دو نتیجه رو باز کن
GDB و LLDB در کنار هم
دو دستگاه بازیافت کار مشابهی با کلمات مختلف انجام می دهند.COMMAND_MAPدر آرک 35 ردیف را نگه دارد، چاپ شده توسط python3 code/main.py commands. اونايي که در اين درس استفاده ميکنن:
| Task | gdb | lldb | lldb alias |
|---|---|---|---|
| break at a function | break bump | breakpoint set -n bump | b bump |
| break at an address in one module | break *0x1000004f0 | breakpoint set -a 0x1000004f0 -s account-O0 | |
| run commands at every stop | define hook-stop ... end | target stop-hook add -o '...' | |
| list breakpoints with hit counts | info breakpoints | breakpoint list | br l |
| watch a variable for writes | watch a->balance | watchpoint set variable a->balance | wa s v a->balance |
| list watchpoints | info watchpoints | watchpoint list -v | wa l -v |
| read one register | p $x0 | register read x0 | |
| read memory as words | x/8xw 0x16fdfe008 | memory read -s4 -fx -c8 0x16fdfe008 | x -s4 -fx -c8 0x16fdfe008 |
| show arguments | info args | frame variable --no-locals | |
| step one instruction | stepi | thread step-inst | si |
| run until the function returns | finish | thread step-out | finish |
| write a core file | gcore core | process save-core --style stack core | |
| open a core file | gdb account-O0 core | lldb -c core account-O0 |
از طرف "آلبوم"pاسم مستعارشdwim-print, که یک متغیر ساده را از طریق frame variableراه و سقوط دوباره بهexpressionبرای هر چیز دیگه ایv.frame variableترجیح میدمframe variableدر یک آرک: مکان های DWARF را می خواند و هرگز کد را در دیبگ گی اجرا نمی کند.
نسخه ها و مجوزهای در 2026-10-14. lldb دارای شماره نسخه LLVM است، و نسخه فعلی llvm.org LLVM 23.1.3 از 2026-10-06 است، تحت مجوز Apache 2.0 با استثنای LLVM. Homebrew آن را به عنوان فرمول جداگانه ارسال می کند lldb. ابزار خط فرماني اين ماشين سفينهlldb-1703.0.236.21GDB 18.1 در سال 2026-09-25 تحت GPL-3.0 یا بعدتر منتشر شد. یادداشت های انتشار آن فهرست ویندوز،.gdb_index، آرک64FPMR، و پایتونgdb.CorefileGDB هیچ پشتیبانی بومی برای فرآیندهای سیلیکون اپل تا 18.1 ندارد: یک سری 15 پیچ "دعم اولیه AArch64-Darwin" در اکتبر 2025 منتشر شد و در فوریه 2026 یک نگهبان مسیر برای فرود آن را از طریق اختصاص حق اشغال و پیچ های BFD ابتدا تعیین کرد.gdbفرمولا با بطری های arm64 و ساختگی با جعلي ساخته شده است--target=x86_64-apple-darwin20، و درخواست pull که آنها را اضافه کرده می گوید "این امکان ندارد که با GDB دوگانه های aarch64-Darwin را خراب کنید". هر یک از بازنویسندگان غیر اپل در macOS نیز نیاز به گواهی خود امضا شده و com.apple.security.cs.debuggerحق یاtask_for_pidدر این دوره Gdb در لینوکس قرار دارد، جایی که Debian برای arm64 gdb 16.3 را ثابت می کند و جایی که rrزندگی می کنه
ردیابی: برنامه از هسته چه خواسته
یک دیبگگر وضعیت برنامه را در توقف نشان می دهد. یک ردیاب اثرات برنامه را در سیستم بدون توقف طولانی نشان می دهد. ابزارها در هر سیستم عامل هستند.
| Tool | OS | Version | Licence | What it records |
|---|---|---|---|---|
strace | Linux | 7.2, 2026-08-18 | LGPL-2.1-or-later | system calls with arguments and return values |
ltrace | Linux | 0.7.3 last tarball, git snapshots in Debian | GPL-2.0 | dynamic library calls |
bpftrace | Linux | v0.27.0, 2026-09-10 | Apache-2.0 | kernel and user probes through eBPF |
dtrace and dtruss | macOS | Sun D 1.19 in macOS 26.2 | CDDL, from Sun's OpenSolaris | D probes; dtruss prints system calls |
dtrussدر راهنمای خود می گوید که "از آنجا که این از DTrace استفاده می کند، فقط کاربران با امتیازات ریشه می توانند این دستور را اجرا کنند".dtrace(1)اضافه می کند که "با تنظیمات پیش فرض حفاظت از یکپارچگی سیستم، برنامه های D مجاز به دسترسی به ارزش های آدرس هسته یا محتوای حافظه هسته نیستند" و اقدامات مخرب تحت SIP مجاز نیستند. sudo dtruss ./account-O0در این ماشین در این درس اجرا نشده است، زیرا هرنس بدون ریشه اجرا می شود و درسی ثبت می کند که به عنوان غیر تأیید شده است. یک ردیابی به یک سوال متفاوت از هرنس پاسخ می دهد: "آیا این اجرا مسئله ای استwriteبرای هر یکprintfخط" یه سوال دنباله ای هست، "آیا؟x15 تا نگه داريدbump" سوالي که از نظر "ديبگگر" مي پرسيد هر دو جواب هر دو ميده
ضبط و پخش مجدد
rrیک بار یک اجرا را ثبت می کند و آن را به صورت تعیین کننده در gdb، با اجرای برعکس تکرار می کند: یک نقطه مراقب را بر روی ارزش مورد توجه شما تنظیم کنید و reverse-contبه سمت عقب به نوشتن می رود. پروژه خودش را به عنوان "یک بار یک شکست ضبط می کنی، سپس ضبط را، به طور تعیین کننده، هر چند که می خواهی، خراب می کنی". توصیف می کند. نسخه فعلی 5.9.0 از سال 2025-02-13 است، تحت مجوز MIT با بلاک BSD-2-Clause. فقط لینوکس هست برای شمارش شاخه ها به شمارنده های عملکرد سخت افزاری نیاز دارد، بنابراین روی Intel Nehalem و بعد، برخی از هسته های Zen AMD و "مخصوص معماری های کوچک AArch64 (به عنوان مثال) اجرا می شود. ARM Neoverse N1 یا سری M سیلیکون اپل) " در لینوکس. در داخل یک ماشین مجازی، شمارنده ها باید مجازی شوند و ویکی پروژه می گوید "هیچ مجازی سازی دیگری در مک هم انجام نمی دهد"، بنابراین Docker و Colima در این ماشین نمی توانند آن را اجرا کنند. پرنسکو سرویس تجاری است که بر اساس ضبطات RR ساخته شده است.
جی دی بی یک نرم افزار ضبط کننده خودش را دارد.record full"یک دفترچه اجرا فرآیند" را با یک حد پیش فرض از 200،000 دستورالعمل ثبت می کند وrecord btraceدر این ماشین macOS، نسخه ذخیره شده از آرکست ثبت شده است: همان طرح در همان دوگانه همان توقف ها را در همان ترتیب تولید می کند و ثابت تست این ترتیب را پین می کند.
آنچه که یک دویدن ثابت می کند
یک اجرا یک ورودی را در یک ساخت ثابت می کند. استاندارد C رفتار غیر تعریف شده را به عنوان "رفتار، با استفاده از یک ساخت برنامه غیر قابل حمل یا اشتباه یا از داده های اشتباه، که برای این سند هیچ الزامی را اعمال نمی کند" تعریف می کند. بنابراین یک برنامه که بیش از یک برنامه امضا شده است.intمی تواند به طور مشروع نتایج مختلف را در -O0و-O2درس 36 با اين موضوع روبرو شدpercent_changeسلول هاي پرتاب. UBSan سوال رو به توقف ميذاره:-fsanitize=signed-integer-overflow -fsanitize-trap=undefinedباعث می شود که پرش "در اجرای یک دستور تله" باشد که به عنوان توقف با یک دلیل در LLDB فرود می آید.
کد بهینه شده همچنین آنچه را که می خواهید ببینید را حرکت می دهد. راهنمای GDB می گوید "آپتیماژور کد شما را تنظیم مجدد کرده است؛ دیبگر به شما نشان می دهد که واقعاً چه چیزی وجود دارد" و یک متغیر بهینه شده از وجود یک "GDB هرگز نمی بیند" است. GDB ارزش هایی مانند <optimized out>، و منبعش اون رو از<unavailable>: بهینه سازی شده "در واقع در برنامه وجود ندارد"، غیرقابل دسترس "در برنامه وجود دارد (در سطح ماشین) ، اما GDB هیچ راهی برای رسیدن به آن ندارد".<variable not available>وقتی شمارنده برنامه خارج از هر محدوده ی لیست موقعیت DWARF متغیر است. یک نقطه نظارتی در یک مکان که در یک سجل زندگی می کند هرگز به کار نمی رود، زیرا سجل حافظه نیست.-O2و این که همه ی این عملکرد را کنار گذاشته اند و سکوت یک نقطه نظارتی که هرگز تنظیم نشده است هیچ چیز را ثابت نمی کند.
پس هنیس سه نوع رکورد می نویسد و هیچ وقت چهارمین رکورد نمی نویسد.confirmedيه توقف که امتحانش کرده و مخالفش شدهrefuted. ادعايي که هيچ توقفي نمي تونه امتحان کنهnot-observedدر مورد این موضوع، در کتاب اصلی درس 35 اولین دو مورد را به عنوانobservedسوابق با مقامcontrolled-replayو سومين رو به عنوان نامعلوم باز نگه مي دارد
درست کردن فقط ساخت های خودتون در macOS
در سيليکيم اپل، لينکرها براي تو نشان ميدهند.ld(1)میگه-adhoc_codesign: "پروختگاهی برای دوگانه های سیلیکون اپل این است که کد گذاری شده باشد".codesign -dvvv account-O0روی چاپ های دستگاه:
Format=Mach-O thin (arm64)
CodeDirectory v=20400 size=387 flags=0x20002(adhoc,linker-signed) hashes=9+0 location=embedded
Signature=adhoc
TeamIdentifier=not set0x20002.CS_ADHOC(0x2) و اضافهCS_LINKER_SIGNED(0x20000), "به طور خودکار توسط لینکر امضا شده" در سرکد امضا کد اپل. codesign -d --entitlements -هیچ چیزی پس از نام اجرا نمی شود: دوگانه هیچ حقوق ندارد. lldb آن را راه اندازی کرد، هر نقطه شکافی را ضربه زد، یک نقطه نظارت سخت افزاری را تنظیم کرد و یک هسته را نوشت، با DevToolsSecurity -statusگزارش "موجوده توسعه دهنده در حال حاضر غیرفعال شده است" و حفاظت از یکپارچگی سیستم فعال شده است.
دو حق دارند که کنترل کنند چه کسی چه چیزی را تغییر دهد و آنها در طرف های مخالف نشسته اند.com.apple.security.cs.debuggerبرای Debugger: "قیمت بولی که نشان می دهد آیا برنامه یک Debugger است و ممکن است به سایر فرآیندهای متصل شود یا پورت های کار را دریافت کند".debugserverدر صورت خصوصی آن است وcodesign -d --entitlements -در لیست کپی ابزار خط فرمانcom.apple.private.cs.debugger،com.apple.private.set-exception-port،com.apple.private.thread-set-stateوcom.apple.private.logging.diagnostic.com.apple.security.get-task-allowXcode آن را در ساخت های دیبگ تزریق می کند، آن را در صادرات حذف می کند و اعتبارنامه یک دوگانه را که هنوز آن را دارد رد می کند. مهندسان اپل قاعده را برای رد بیان می کنند: پورت کار زمانی رد می شود که هدف زمان اجرا سخت را فعال کرده و ندارد.get-task-allow. يه صافيهclangاگه تا حالا با هم قرارداد امضا کرديcodesign --options runtime، دوباره امضا کنcodesign -s - -f --entitlements get-task-allow.plistقبل از بازتاب
سه واقعیت دیگر بخش را بسته می کند. اول، شما ممکن است اولین بار در یک جلسه ورود، دیالوگ "Developer Tools Access نیاز به کنترل یک فرآیند دیگر برای ادامه دیبگینگ دارد" را ببینید. sudo DevToolsSecurity -enableرمز عبور اضافی برای اعضای adminیا_developerگروه ها. دوم، شما SIP را غیر فعال نمی کنید تا کد خود را خراب کنید. اپل می گوید "شما نیازی به غیر فعال کردن SIP برای اجرا و خراب کردن برنامه های Xcode ندارید". و تنها بخش SIP که به خرابکاری می پردازد، آن است csrutil enable --without debugسوم، جعبه شن سياتل در اين جلسه مسدود مي شودtask_for_pidکاملا و با همsandbox-O0.lldb.txtیک مسابقه که نمی تواند شروع شود یک واقعیت محیطی است و هنیس آن را به عنوان یک واقعیت گزارش می دهد.
همه چيز در اين درس به برنامه هاي مرتب شده شما اطلاق ميکنه. اين دستورات فقط به يه پروسه ديگه متصل مي شه اگر صاحبش اين روش رو انتخاب کنه و هيچ چيز در اين مورد نمي آموزد چطوري اين روش رو عوض کنيم.
آن را بسازید
نمایش نمایش را اجرا کن:
cd phases/13-tools-and-protocols/42-dynamic-analysis-of-your-own-program
python3 code/main.py
npx tsx code/main.tsمحصول یک گزارش JSON بر روی نقل و نقل های ذخیره شده است. برای هر ساخت، نقاط شکافی با قطعنامه و شمارش ضربه ها، شمارش نقطه نگهبان سخت افزاری، هر توقف با ثبت و استدلال های آن، وضعیت خروج، خروجی برنامه، خطاهای چاپ شده، و ادعاها با حکم های آنها و اسناد شواهد پشت آنها را فهرست می کند. این شامل سفر اصلی و بازگشت، نتایج API پایتون، شکست جعبه شن و ابزار خارجی که در این ماشین غائب است.
شکل انتظار می رود:
{
"program": "account.c",
"variants": {
"O0": {
"binary": "account-O0",
"breakpoints": {"1": {"spec": "name=bump", "address": "0x1000004bc", "resolved": true, "hits": 1}, "...": "..."},
"hardwareWatchpoints": 4,
"watchpoints": {"1": {"address": "0x16fdfe00c", "size": 4, "type": "m", "hits": [[250, 255]], "hitCount": 1}},
"stops": [{"index": 0, "pc": "0x1000004bc", "function": "bump", "kind": "entry", "registers": {"x0": "0x16fdfe008", "x1": "0x5"}, "...": "..."}],
"exitStatus": 0,
"claims": [{"id": "arg-registers", "verdict": "confirmed", "confirmed": 5, "refuted": 0, "not-observed": 0, "...": "..."}],
"evidence": [{"claim": "arg-registers", "verdict": "confirmed", "stop": 0, "observation": "bump: x0 = 0x16fdfe008 and a = 0x000000016fdfe008, x1 = 0x5 and by = 5"}]
},
"O2": {"stops": [], "claims": [{"id": "calls", "verdict": "refuted", "...": "..."}], "...": "..."}
},
"core": {"savedAt": {"function": "bump", "pc": "0x1000004bc"}, "labelString": "", "...": "..."},
"types": {"python": "3.9.6", "size": 32, "...": "..."},
"sandbox": {"stops": 0, "errors": ["process exited with status -1 (attach failed ((os/kern) invalid address))"]},
"absentTools": ["bpftrace", "gdb", "llvm-objdump", "ltrace", "rr", "strace"]
}بخونcode/main.pyدر این ترتیب:
Listingتجزیه و تحلیلllvm-objdump -dمتن به تابع ها و دستورالعمل ها وFunction.conditional_branches()شاخه ها رو با هدف ها و شکست ها پيدا ميکنهstruct_layout()ساختار و ادغام اعضای را ازllvm-dwarfdumpمتنlift_condition()تبدیل یک شاخه مشروط به یک پیشگوئی، درس 34 مرحله برایtbz،cbz، و فرم های مقایسه و شاخهPlan.commands()فایل دستور lldb را از لیست می نویسد وPlan.lldb_command()این درخواست دسته بندی است.parse_transcript()راه رفتن درآمدی به ترتیب و ساختStopسوابق با سوابق، حافظه، متغیرها و ارزش های نقطه مشاهده، به علاوه جدول نقطه شکافی و وضعیت خروج.claims_for()هشت ادعای را بیان می کند وevaluate()نمره ها رو با هم بندازن_check_*عملکردهاrollup()رکورد ها را به یک حکم در هر ادعای کاهش می دهد، با رد کردن بر تایید.capture()وcapture_extras()دستگاه های نصب شده را تولید کرده وlive()تمام حلقه رو در ساخت تازه تکرار ميکنهclangوlldbمی تونم فرار کنم
چهار فرمان ديگه وجود دارهpython3 code/main.py plan O0فایل فرمان را برای ساخت چاپ می کند.python3 code/main.py commandsجدول GDB و LLDB را چاپ می کند. python3 code/main.py toolsگزارش هایی که ابزار خارجی روی آن ها قرار داردPATH.python3 code/main.py live O0مجموعه هاaccount.cدر یک دایرکتوری موقت، برنامه های از لیست جدید خود را اجرا می کند، lldb، و امتیاز ادعاها در برابر آن اجرا. در داخل یک جعبه قمار گزارش می دهد که lldb نمی تواند فرآیند را با خطا راه اندازی کند، و خروج 1.
ازش استفاده کن
از این خط برای برنامه های خودتون استفاده کنید
- با اون بساز
-gو سطح بهینه سازی که شما ارسال می کنید. دوگانه را نگه دارید، dSYM یا DWARF آن را، وllvm-objdump -dبا هم متن بفرستید - قبل از اجرا، ادعاهای را بنویسید. هر کدام یک از این موارد را به عنوان یک تابع، یک ثبت یا آدرس یا تعویض، یک ارزش یا حاشیه انتظار می رود و درس یا سند که از آن آمده است، نام می دهند. یک ادعایی که پس از دیدن توقف می نویسید، توقف را توصیف می کند و هیچ چیز را آزمایش نمی کند.
- نقشه را از لیست تولید کنید و آن را بخوانید. هر آدرس در آن باید به یک خط در لیست دنبال شود. اگر نقطه شکافی چنین خطی ندارد، آن را حذف کنید.
- یک بار در حالت دسته اجرا کنید و متن را با خط فرمان و نسخه دیبگگر در سرش نگه دارید. متن شواهد است. حکم ها از آن مشتق شده است و هر کسی می تواند آنها را دوباره مشتق کند.
- درجه، هرکدوم رو بخون
not-observedدلیل قبل از خواندن تاییدات به شما می گوید که کدام ادعاها نیاز به ورودی دیگر، ساخت دیگر، یا نقطه شکافی دیگر دارند. - ساخت بهینه شده را با همان ادعاها اجرا کنید. انتظار دارید نقاط شکافی حل شده با صفر ضربه ای که در آن کامپایلر خط کشیده شده است، و این ادعاها را باز نگه دارید.
- ثبت تایید شده و رد شده را به دفترچه درس 35 بفرستید
observed، مقامcontrolled-replay، یک رکورد در هر توقف. اونها رو که مشاهده نشده اند به عنوان نامعلوم با شماره ضربه نقطه شکستن متصل کن
آزمایشگاه تعاملی
لابراتوار A: دست به دست یک توقف را بخونید
ازcodeدایرکتوری، پیتون باز:
cd phases/13-tools-and-protocols/42-dynamic-analysis-of-your-own-program/code
python3 -qراه رفتن:
from main import *
t = load_transcript("session-O0.lldb.txt")
s = t.stops[0]
hex(s.pc), s.function, s.reason, s.registers
[hex(w) for w in s.memory[:8]]
s.struct_pointer().fieldsقبل از خط دوم، چه کلمه ای را که انتظار دارید 250 و کدام دو کلمه 1.25.struct.unpack("<d", struct.pack("<II", s.memory[4], s.memory[5]))و مقایسه کنید. پس نگاه کنید.t.stops[1].watch_hitوt.stops[1].pc، و اون آدرس رو درaccount-O0.objdump.txt: اين دستورات بعد از فروشگاهه
آزمایشگاه B: شاخه و جانشین آن
plan = make_plan("O0")
plan.branches()
classify = plan.listing.function("classify")
[lift_condition(classify, b, "a->balance")[0] for b in plan.branches()]
[(hex(s.pc), s.struct_pointer().field_int("balance")) for s in t.stops_in("classify")]هر توقف حاشیه را با توقف ورود آن مطابقت دهید و قبل از اینکه به شواهد نگاه کنید، تصمیم بگیرید که جانشین پیش بینی شده توسط پیشگوئی.[e.to_dict() for e in evaluate(plan, t, struct_layout(open("fixtures/account-O0.dwarfdump.txt").read(), "account")) if e.claim.startswith("branch")]و مقایسه کنید.
لابراتوار C: مسابقه ای که هرگز متوقف نشد
o2 = load_transcript("session-O2.lldb.txt")
len(o2.stops), o2.exit_status, o2.hits()
o2.errors[:3]
make_plan("O2").branches()
rollup(evaluate(make_plan("O2"), o2, struct_layout(open("fixtures/account-O2.dwarfdump.txt").read(), "account")))هر یک رو توضیح بدهnot-observedبا حرف های خودت، پس باز شوaccount-O2.objdump.txtو چهار ثابت را در پیدا کنیدmainکه زنگ ها رو عوض کردDW_TAG_inlined_subroutineدرaccount-O2.dwarfdump.txtباcount_tags(). .
لابراتوار D: شواهد رو شکستن
text = open("fixtures/session-O0.lldb.txt").read().replace("x1 = 0x0000000000000005", "x1 = 0x0000000000000006", 1)
broken = parse_transcript(text)
[e.to_dict() for e in evaluate(plan, broken, struct_layout(open("fixtures/account-O0.dwarfdump.txt").read(), "account")) if e.claim == "arg-registers"][:2]يه دفترچه اصلاح شده اولين رو ميگيرهarg-registersثبت به refutedو با اون بالا رفتن، در حالی که چهار ورودی دیگر باقی می مانندconfirmedپس حذف کنold value: 250خط قبل از توقف نقطه نگهبان و نگهبانstore-onceبه پايانnot-observedيه درجه بندي که نميتونه شکست بخوره نميتونه نمره بده
اگه lldb ميتونه يه پروسه رو در پوسته ات راه انداز کنه، تمومش کنpython3 main.py live O0وpython3 main.py live O2آدرس هاي دسته از جايگاه هاي تيم متفاوت خواهد بود.
آزمایشگاه تمرین
با ادعای مربوط به حلقه در sum_balances. .
الزامات:
- لوله رو در کنار عقب پيدا کن
sum_balancesدر-O0فهرست باconditional_branches()و نقطه شکافی را در سرگوشن حلقه اضافه کنید. - یک ادعا را اضافه کنید که عنوان اجرا کند
count + 1زمان ها برایcount= 3، که درسی 33 پشت کناره به علاوه آزمون خروج است. - این هک را در هر توقف سر و پا و یا نقشه به طوری که هک سوراخ های تکه شمارشگر حلقه را در هر توقف سر و پا می خواند، و یک
_check_loop()که ردیف مقادیر ضد را ثبت می کند. - متن رو دوباره بگير
python3 main.py capture O0در یک ماشین که Lldb می تواند شروع کند و مجموعه را دوباره اجرا کند. آزمایش برنامه تا زمانی که فایل دستور متعهد با برنامه جدید مطابقت نداشته باشد، که نقطه آزمایش است، شکست می خورد. - یک تست اضافه کنید که یک مقدار ضدگرفت را در نقل قول ویرایش کند و ادعا را ثابت کند.
refuted. .
موفقیت به این معنی است که گزارش نشان می دهد که سر و سر را در ترتیب با ارزش های مقابل خود متوقف می کند و -O2ران ادعا جديد رو نگه مي دارهnot-observedبه این دلیل که حلقه به صورت ویکتور یا خمیده شده است.
درس هنرپیشه
این درس شاملoutputs/skill-dynamic-analysis-of-your-own-program.mdاز آن برای تبدیل یک برنامه ساخته شده، لیست آن و یک لیست ادعاهای ثابت به یک نسخه ذخیره شده از اشکال زدایی و یک حکم در هر ادعا، با توقف که هر حکم را تولید کرده و دلیل هر ادعایی که باقی مانده است رعایت نشده است. این برای کلاود، کورسور، کودکس، OpenClaw، هرمز، یا هر عامل که SKILL.md را می خواند اعمال می شود.
بررسی کنید
نمایش و مجموعه تعیین کننده را اجرا کنید:
cd phases/13-tools-and-protocols/42-dynamic-analysis-of-your-own-program
python3 code/main.py
npx tsx code/main.ts
python3 -m unittest discover -s code/tests -vاين سويت بدون lldb اجرا ميشه و نقل نامه ها رو ميخواد که يه بار به داخلcode/fixtures/.آراستاری باید ثابت کند:
- در فهرست بازرس چهار تابع با دامنه های آنها و دو شاخه مشروط از
classifyدر-O0با هدف و سقوط - آسانسور
tbz w8, #0x1f.a->balance >= 0و بلند کردنsubsو اضافهb.le.a->balance <= 200 mainدر-O0تماس هاbump،classifyسه بار وsum_balancesوmainدر-O2فقط تماسprintf- x86-64
j<cc>. امنوماک ها مشروط هستند وjmpوcallqنیست - در ورودی DWARF یک ساختار 32 بایت با اعضای در 0، 4، 8، 16 و 24 تولید می شود.
- .
-O2DWARF دارای چهار زیر برنامه و صفر ورود زیر برنامه های داخلی است وnmهنوز هم سه تابع را فهرست می کند - نقشه برابر با فایل دستور انجام شده برای هر دو ساخت است و سرنامه ی نقل نامه، دستور LLDB را که اجرا کرده است ثبت می کند
- .
-O0نقل نامه دارای یکصد توقف در عملکردهای انتظار می رود، وضعیت خروج 0 و چهار خط خروجی است - خروجی هک به توقف بعدی متصل می شود، با
x1= 5، حافظه ازx0, و رشته برچسب - جدول نقطه شکافی دارای رزولوشن و شمارش ضربه ها 1، 3، 1، 2، 1، 1 است
- نقطه نگاه 4 بايت از نوع اصلاح در
x0 + 4، یک بار با ارزش قدیمی 250 و ارزش جدید 255 ضربه زده و چهار اسلات سخت افزاری گزارش شده است - .
-O2نقل نامه صفر توقف داره، سه نقطه حل شده با صفر ضربه، هیچ نقطه نظارتی و یک خطا در هر مورد استفاده نشدهcontinue - راه اندازی با جعبه ی شنگی قبل از توقف با خطا ی پیوستن شکست می خورد
- سفر برگشت و برگشت هسته ای به عقب باز می گردد و
balance= 250 و رشته رو از دست ميدهlabel - API پایتون پنج زمینه را می خواند، اندازه 32 و محدوده عملکرد بدون یک فرآیند
- یک نسخه ی دست نوشته x86-64 را با
rdi،rsiوrip - هر ادعايي در
-O0با ثبت ۵، ۱۱، ۳، ۲، ۱، ۱، ۱ - شواهد شاخه نام ارزش، حالت و لبه
- شواهد فیلد آفسه کلمات را از طریق طرح DWARF رمزگذاری می کند
- شواهد ذخیره و قدم بر روی ارزش های قدیمی و جدید و میزان سه ردیف
- .
-O2اجرا حاشیه های تماس را رد می کند و سایر ادعاها را نادیده می گیرد - یک ارزش ثبت اصلاح شده رد می شود، یک ضربه نقطه مشاهده حذف شده مشاهده نمی شود و رد شده برنده ی rollup می شود
- نقشه فرمان دارای فرم های gdb و lldb برای هر ردیف است و جدول سخت افزاری چهار register debug x86 را نام می دهد
- در نمایش لیست ابزار های غائب به جای شکست و حالت زنده گزارش ابزار گمشده توسط نام
- داده های ارقام از هر دو جلسه آمده و ماژول سایت داده های مشابه را در خود قرار داده است
روش های شکست تولید
| Failure | What the weak report says | What the harness must prove |
|---|---|---|
| Resolved breakpoint with zero hits | "the function runs" or "the function is dead" | a full run with exit status, hit counts, and the verdict refuted for the call edge only |
| Register read at the wrong stop | "x1 = 5 inside classify" | compare only declared arguments at the entry stop |
| Struct read without offsets | a column of hex words | every word mapped to a DW_AT_data_member_location and compared with frame variable |
| Branch graded from the mnemonic | "tbz means taken when negative" | the lifted predicate from the encoding and the stop at the successor |
| Watchpoint on a register-resident local | "no write happened" | the watchpoint was set on an address and was hit, or the record is not-observed |
| Auto-continue breakpoints | a clean transcript with no stops | plain breakpoints, a stop hook, and a continue budget |
| Address breakpoint without a module | unresolved, hit count = 0 | -s MODULE so the listing address resolves to a load address |
| First command error ends the batch | no breakpoint list at the end | interpreter.stop-command-source-on-error false |
| Stack-style core read as full memory | label = "" reported as the program's value | the core style, the pointer, and the segment it points into |
| Sandboxed shell | "lldb is broken" | attach failed ((os/kern) invalid address) recorded as an environment fact |
Hardened target without get-task-allow | "macOS forbids debugging" | the two conditions from Apple's rule, and a re-sign of your own binary |
| Transcript discarded after grading | verdicts with no source | the transcript file, its command line, and the debugger version |
قاعده عملیاتی
توقف های لیست را برنامه ریزی کنید، یک بار در حالت دسته اجرا کنید، نقل را نگه دارید و هر ادعای جامد را در هر توقف که می تواند آزمایش کند، رتبه بندی کنید. فقط از یک توقف تایید یا رد کنید، با تعداد ضربه ها و دلیل، غیر مشاهده شده را بنویسید و هرگز اجازه ندهید نقطه شکافی حل شده برای یک اجرا قرار بگیرد. فقط ساختاتی را که ساخته اید تغییر دهید.
خواندن بیشتر
- LLDB Tutorial: command grammar, breakpoints, watchpoints, stop hooks
- lldb(1) manual page: --batch, --one-line, --source, --core
- GDB to LLDB Command Map
- LLDB Python Reference: SBTarget, SBFrame, SBValue, and the embedded interpreter
- LLDB Caveats: the Python build lldb links against
- LLVM 23.1.3 release
- GDB 18.1 release announcement, 2026-09-25
- GDB manual: Process Record and Replay
- GDB manual: Debugging Optimized Code
- GDB wiki: Permissions on Darwin, code signing a debugger
- gdb-patches: Initial AArch64-Darwin support series, October 2025
- Homebrew gdb formula pull request adding arm64 bottles
- ptrace(2), Linux manual page
- lldb debugserver MachTask.mm: task_for_pid and task_set_exception_ports
- Intel SDM Volume 2: INT n, INTO, INT3, INT1
- Intel SDM Volume 3: debug registers DR0 to DR7 (Debug, Branch Profile, TSC, and Resource Monitoring Features)
- Arm A64 ISA: BRK, Breakpoint instruction
- Arm A64 ISA: TBZ, Test bit and branch if zero
- Arm Architecture Reference Manual, D2.9 Watchpoint exceptions
- Apple ld(1): -adhoc_codesign
- Apple ld64 LinkEdit.hpp: CS_LINKER_SIGNED
- Apple: Debugging Tool Entitlement, com.apple.security.cs.debugger
- Apple: Hardened Runtime
- Apple: Resolving common notarization issues, the get-task-allow entitlement
- Apple: Disabling and Enabling System Integrity Protection
- Apple Developer Forums: debugserver may not get the taskport of a hardened process
- Apple DevToolsSecurity(8)
- Apple core(5)
- Apple Technical Note TN2124: Mac OS X Debugging Magic, core dumps
- lldb
process save-corehelp text - core(5), Linux manual page
- coredumpctl(1)
- Apple dtrace(1)
- Apple dtruss(1m)
- strace releases
- ltrace
- bpftrace CHANGELOG
- rr project
- rr 5.9.0 release
- rr wiki: Building And Installing, hardware and VM requirements
- Clang UndefinedBehaviorSanitizer
- ISO/IEC 9899:2024 working draft N3220, clause 3.5 undefined behavior
- DWARF Debugging Information Format Version 5
- Procedure Call Standard for the Arm 64-bit Architecture (AAPCS64)
- System V Application Binary Interface, AMD64 Architecture Processor Supplement
This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.
Browse the complete course catalog or open this lesson on GitHub.