โพรบ
<probe_rule> / <predicate> / { <actions> }
เราใช้คำว่า probe (โพรบ) เพื่ออ้างถึงสามส่วนนี้ ได้แก่ probe_rule, predicate และ actions
เมื่อทำการเขียนไบต์โค้ดใหม่ Whamm จะทำงานดังนี้:
- ท่องไปตามโมดูล Wasm ของแอปพลิเคชันเพื่อค้นหาตำแหน่งที่สนใจตามที่ระบุไว้ใน
probe_ruleของแต่ละโพรบ - ตรวจสอบว่า
predicateประเมินเป็นfalseแบบสแตติกหรือไม่- ถ้าประเมินเป็น
falseก็จะเดินหน้าต่อ โดยไม่ฉีด actions ของโพรบ - ถ้าไม่ประเมินเป็น
falseก็จะฉีด actions ของโพรบที่ตำแหน่งนั้น พร้อมกับpredicateที่ถูกพับค่าแล้ว- ถ้า
predicateประเมินเป็นtrueแบบสแตติก ก็จะฉีด actions เข้าไปในโปรแกรมโดยไม่มีเงื่อนไข - ถ้า
predicateไม่พับเป็นค่าbooleanธรรมดา ก็จะฉีด actions ที่มีเงื่อนไข ณ ตำแหน่งนี้ จากนั้น predicate จะถูกประเมินแบบพลวัตเมื่อแอปพลิเคชันรัน เพื่อให้ actions ของโพรบทำงานตามเงื่อนไข
- ถ้า
- ถ้าประเมินเป็น
ตัวช่วย info ใน CLI
whamm info --help
คำสั่ง info ที่ CLI ให้มาเป็นแหล่งข้อมูลชั้นเยี่ยมสำหรับดูว่าอะไรใช้เป็นกฎการแมตช์ของโพรบได้บ้าง
คำสั่งนี้ให้เอกสารที่อธิบายส่วนประกอบของกฎการแมตช์ ตลอดจนตัวแปรและฟังก์ชันที่ผูกไว้ซึ่งอยู่ในสโคป ซึ่งช่วยให้ผู้ใช้เรียนรู้วิธีสร้าง instrumentation ของตนได้เป็นอย่างดี
กฎการแมตช์ของโพรบ
provider:package:event:mode
probe_rule เป็นวิธีแสดง “ตำแหน่ง” ที่คุณต้องการทำ instrumentation ในโปรแกรม
มันเป็นลำดับชั้นตาม provider, package, event และ mode
| ส่วน | คำอธิบาย |
|---|---|
| provider | ชื่อของ provider ที่รองรับความสามารถ instrumentation ที่ใช้ในโพรบนี้ |
| package | ชื่อของ package ภายใน provider ที่ระบุ ซึ่งรองรับความสามารถ instrumentation ที่ใช้ในโพรบนี้ |
| event | ชื่อของ event ที่สัมพันธ์กับตำแหน่งที่จะแทรกโพรบนี้ในโปรแกรมที่ทำ instrumentation |
| mode | ชื่อของ mode ที่ควรใช้เมื่อปล่อย actions ของโพรบ ณ ตำแหน่งของ event เช่น before, after และ alt |
แต่ละส่วนของ probe_rule จะเพิ่มความจำเพาะขึ้นเรื่อยๆ จนกระทั่งถึง mode ของโพรบ
ลองพิจารณากฎการแมตช์ตัวอย่าง: wasm:opcode:br_if:before
กฎนี้ตีความได้ว่า “แทรกโพรบนี้ก่อนแต่ละ ออปโคด br_if ของ Wasm ในโปรแกรมของฉัน”
อ่านเอกสารอีเวนต์ที่ทำ instrumentation ได้ของเราเพื่อดูสิ่งที่รองรับในปัจจุบันและเป้าหมายในอนาคต
เพรดิเคต
/ <predicate> /
predicate เป็นวิธีแสดง “เงื่อนไข” ที่คุณต้องการให้ประเมินเป็น true เพื่อให้ actions ของโพรบถูกทำ
มันช่วยจำกัดกฎการแมตช์ให้แคบลงอีกชั้น
ส่วนนี้ของโพรบเป็นทางเลือก
ถ้าโพรบใดไม่มี predicate actions จะถูกทำเสมอเมื่อถึงตำแหน่งของโพรบระหว่างการทำงานของโปรแกรม
การพับค่าคงที่ของข้อมูลสแตติก
โพรบสามารถมีเพรดิเคตบนข้อมูลทั้งสแตติกและพลวัตได้
เพื่อรองรับสิ่งนี้ เมื่อกำหนดเป้าหมายเป็นการเขียนไบต์โค้ดใหม่ คอมไพเลอร์ whamm จะทำการแพร่ค่าคงที่สำหรับข้อมูลที่นิยามแบบสแตติก
หมายความว่า เนื่องจากข้อมูลสแตติกรู้ได้ตั้งแต่ตอนคอมไพล์ไทม์ ค่าของตัวแปรเหล่านั้นจะถูกแทนที่ และนิพจน์สามารถประเมินบางส่วนได้
ตัวอย่างเช่น ลองพิจารณาโพรบต่อไปนี้:
wasm:opcode:br_if:before / pc == 25 && arg0 == 1 / {..}
อ่านได้ว่า แนบโพรบที่ออปโคด wasm br_if แต่รันตรรกะนี้เฉพาะเมื่อ pc เป็น 25 และ arg0 ประเมินเป็น 1
ขณะที่เราท่องไปตามแอปพลิเคชัน เรารู้แบบสแตติกว่าเรากำลังอยู่ที่ออฟเซต pc เท่ากับ 25 ภายในฟังก์ชัน
แต่เราไม่รู้ค่าของ arg0 จนกว่าโค้ดจะรันจริง!
นี่คือจุดที่การประเมินบางส่วนเข้ามามีบทบาท
สมมติว่าเราอยู่ที่ pc 0 ภายในฟังก์ชันหนึ่ง การแพร่ค่าคงที่และการประเมินบางส่วนจะมีลักษณะดังนี้:
0 == 25 && arg0 == 1
false && arg0 == 1
false
เพรดิเคตประเมินเป็น false แบบสแตติก! นั่นหมายความว่าเราไม่ควรแนบโพรบที่ตำแหน่งนี้ เพราะมันไม่แมตช์!
สมมติว่าเราอยู่ที่ pc 25 ภายในฟังก์ชันหนึ่ง:
25 == 25 && arg0 == 1
true && arg0 == 1
arg0 == 1
อืม … เรายังมีส่วนหนึ่งของเพรดิเคตเหลืออยู่! ควรทำอย่างไรดี … เรายังจำเป็นต้องมีเพรดิเคตบนส่วนนี้ของนิพจน์ เพียงแต่ต้องฉีดนิพจน์ที่ประเมินบางส่วนแล้วนี้ออกไปรันตอนรันไทม์! ดังนั้น เราจะฉีดเนื้อโพรบโดยห่อด้วยเงื่อนไขนี้!
โปรดทราบว่าสิ่งนี้มีลักษณะแตกต่างออกไปเล็กน้อยสำหรับเป้าหมาย wei เพราะ Whamm ต้องปรับแต่งเพรดิเคตเป็นอย่างอื่นตรงจุดนั้น ซึ่งช่วยให้เอนจินรันส่วนที่ถูกต้องของเพรดิเคตในเวลาที่ถูกต้อง (match time กับรันไทม์)
Actions
{ <actions> }
actions คือคำสั่งที่ถูกทำ ณ ตำแหน่งของ probe_rule หาก predicate ประเมินเป็น true
ลำดับการฉีดโพรบ
เมื่อมีโพรบหลายตัวแมตช์ตำแหน่งไบต์โค้ดเดียวกัน whamm รับประกันลำดับการฉีดภายใต้กฎสองข้อ:
กฎข้อ 1: หมวดหมู่โพรบเดียวกัน — ลำดับในสคริปต์ถูกคงไว้
โพรบสองตัวที่อยู่ในหมวดหมู่การฉีดเดียวกัน (เช่น เป็น opcode:call:before ทั้งคู่ หรือเป็น func:entry ทั้งคู่) จะถูกฉีดตามลำดับที่ปรากฏในสคริปต์เสมอ
// order0.mm — func:entry fires first, then the second func:entry
wasm:func:entry { /* A */ }
wasm:func:entry { /* B */ }
// at any function entry: A runs, then B runs
การรับประกันนี้ยังใช้ได้กับสคริปต์หลายไฟล์ที่ส่งให้คอมไพเลอร์ด้วย: โพรบจากสคริปต์แรกจะถูกฉีดก่อนโพรบจากสคริปต์ที่สอง
กฎข้อ 2: หมวดหมู่โพรบต่างกัน — ลำดับถูกกำหนดโดยเป้าหมายการฉีด
เมื่อโพรบสองตัวอยู่ต่างหมวดหมู่การฉีดกัน (เช่น wasm:opcode:call:before กับ wasm:func:entry) ลำดับสัมพัทธ์ ณ ตำแหน่งที่ใช้ร่วมกันไม่ถูกควบคุมด้วยลำดับในสคริปต์
เป้าหมายการเขียนไบต์โค้ดใหม่ (wirm) ใช้โมเดลการฉีดสองรอบ:
- รอบที่ 1 (ปกติ): โพรบ
before,afterและaltถูกฉีดระหว่างการท่องไบต์โค้ด - รอบที่ 2 (โหมดพิเศษ): โพรบเชิงโครงสร้างอย่าง
func:entry,func:exit,block:entry,block:exitและอื่นๆ ที่คล้ายกัน ถูกแก้ไขให้ชัดเจนและฉีดตอน encode
เนื่องจากสองรอบนี้เป็นอิสระต่อกัน โพรบ before จึงถูกฉีดก่อนโพรบ func:entry ณ ตำแหน่งไบต์โค้ดเดียวกัน (คำสั่งแรกของฟังก์ชัน) เสมอ ไม่ว่าโพรบใดจะปรากฏก่อนในสคริปต์
หากคุณต้องการลำดับที่เฉพาะเจาะจงระหว่างโพรบต่างหมวดหมู่ ให้ใส่ตรรกะทั้งหมดไว้ในโพรบเดียวที่อีเวนต์จำเพาะกว่า (เช่น opcode:call:before แทนที่จะผสม func:entry กับ opcode:call:before ที่ตำแหน่งเดียวกัน)