panda/taint.rs
1//! Taint analysis API
2//!
3//! This module provides a series of helpers designed for using the [`taint2`] PANDA plugin in order
4//! to perform [dynamic taint analysis] in order to help track
5//!
6//! [`taint2`]: https://github.com/panda-re/panda/tree/dev/panda/plugins/taint2
7//! [dynamic taint analysis]: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.681.4094&rep=rep1&type=pdf
8//!
9//! ## Example
10//!
11//! ```no_run
12//! use panda::taint;
13//! use panda::regs::Reg;
14//!
15//! // show all registers are untainted
16//! for reg in [Reg::RAX, Reg::RBX, Reg::RCX, Reg::RDX] {
17//! println!("{:?} is tained? {:?}", reg, taint::check_reg(reg));
18//! }
19//!
20//! println!("Tainting RAX...");
21//! taint::label_reg(Reg::RAX, 1);
22//!
23//! // ...
24//!
25//! // show taint has propagated to any values effected by the opterations performed on RAX
26//! for reg in [Reg::RAX, Reg::RBX, Reg::RCX, Reg::RDX] {
27//! println!("{:?} is tained? {:?}", reg, taint::check_reg(reg));
28//! }
29//! ```
30//!
31//! ([Full Example](https://github.com/panda-re/panda-rs/blob/master/panda-rs/examples/unicorn_taint.rs))
32
33use crate::api::regs::Reg;
34use crate::plugin_import;
35use crate::sys::{target_ptr_t, CPUState};
36
37use std::collections::HashSet;
38use std::ops::Range;
39use std::os::raw::{c_int, c_long, c_void};
40use std::ptr;
41use std::sync::Once;
42
43plugin_import! {
44 /// Direct access to the taint2 C API when direct use is needed
45 static TAINT: Taint = extern "taint2" {
46 fn taint2_enable_taint();
47 fn taint2_enable_tainted_pointer();
48 fn taint2_enabled() -> bool;
49
50 fn taint2_label_addr(a: Addr, offset: c_int, label: u32);
51 fn taint2_label_ram(ram_offset: u64, label: u32);
52 fn taint2_label_reg(reg_num: c_int, offset: c_int, label: u32);
53 fn taint2_label_io(ia: u64, label: u32);
54 fn taint2_label_ram_additive(ram_offset: u64, label: u32);
55 fn taint2_label_reg_additive(reg_num: c_int, offset: c_int, label: u32);
56 fn taint2_label_io_additive(ia: u64, label: u32);
57 fn taint2_add_taint_ram_pos(cpu: &mut CPUState, addr: u64, length: u32, start_label: u32);
58 fn taint2_add_taint_ram_single_label(cpu: &mut CPUState, addr: u64, length: u32, label: c_long);
59
60 fn taint2_delete_ram(ram_offset: u64);
61 fn taint2_delete_reg(reg_num: c_int, offset: c_int);
62 fn taint2_delete_io(ia: u64);
63
64 fn taint2_query_pandalog(addr: Addr, offset: u32) -> *mut c_void;
65 fn pandalog_taint_query_free(tq: *mut c_void);
66
67 fn taint2_query(addr: Addr) -> u32;
68 fn taint2_query_reg(reg_num: c_int, offset: c_int) -> u32;
69 fn taint2_query_ram(ram_offset: u64) -> u32;
70 fn taint2_query_laddr(la: u64, off: u64) -> u32;
71 fn taint2_query_io(ia: u64) -> u32;
72 fn taint2_query_llvm(reg_num: c_int, offset: c_int) -> u32;
73
74 fn taint2_query_set_a(a: Addr, out: &mut *mut u32, outsz: &mut u32) -> u32;
75
76 fn taint2_query_set(a: Addr, out: *mut u32);
77 fn taint2_query_set_ram(ram_offset: u64, out: *mut u32);
78 fn taint2_query_set_reg(reg_num: c_int, offset: c_int, out: *mut u32);
79 fn taint2_query_set_io(ia: u64, out: *mut u32);
80
81 fn taint2_query_tcn(a: Addr) -> u32;
82 fn taint2_query_tcn_ram(ram_offset: u64) -> u32;
83 fn taint2_query_tcn_reg(reg_num: c_int, offset: c_int) -> u32;
84 fn taint2_query_tcn_io(ia: u64) -> u32;
85 fn taint2_query_tcn_llvm(reg_num: c_int, offset: c_int) -> u32;
86
87 fn taint2_query_cb_mask(a: Addr, size: u8) -> u64;
88
89 fn taint2_labelset_addr_iter(addr: Addr, app: LabelSetVisitorRawFn, stuff: *mut c_void);
90 fn taint2_labelset_ram_iter(ram_offset: u64, app: LabelSetVisitorRawFn, stuff: *mut c_void);
91 fn taint2_labelset_reg_iter(reg_num: c_int, offset: c_int, app: LabelSetVisitorRawFn, stuff: *mut c_void);
92 fn taint2_labelset_io_iter(ia: u64, app: LabelSetVisitorRawFn, stuff: *mut c_void);
93 fn taint2_labelset_llvm_iter(reg_num: c_int, offset: c_int, app: LabelSetVisitorRawFn, stuff: *mut c_void);
94
95 fn taint2_num_labels_applied() -> u32;
96
97 fn taint2_track_taint_state();
98
99 fn taint2_query_results_iter(qr: &mut QueryResult);
100 fn taint2_query_result_next(qr: &mut QueryResult, done: &mut bool) -> u32;
101 fn taint2_query_laddr_full(reg_num: u64, offset: u64, qr: &mut QueryResult);
102 fn taint2_query_reg_full(reg_num: u32, offset: u32, qr: &mut QueryResult);
103 fn taint2_query_ram_full(addr: u64, qr: &mut QueryResult);
104 };
105}
106
107pub type LabelSetVisitorRawFn = extern "C" fn(u32, *mut c_void) -> c_int;
108
109#[derive(Clone, Copy)]
110#[repr(C)]
111pub union ValueUnion {
112 pub ha: u64,
113 pub ma: u64,
114 pub ia: u64,
115 pub pa: u64,
116 pub la: u64,
117 pub gr: u64,
118 pub gs: u64,
119 pub ua: u64,
120 pub con: u64,
121 pub ret: u64,
122}
123
124#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
125#[repr(C)]
126#[allow(non_camel_case_types)]
127pub enum AddrType {
128 HADDR,
129 MADDR,
130 IADDR,
131 PADDR,
132 LADDR,
133 GREG,
134 GSPEC,
135 UNK,
136 CONST,
137 RET,
138 ADDR_LAST,
139}
140
141#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
142#[repr(C)]
143#[allow(non_camel_case_types)]
144pub enum AddrFlag {
145 IRRELEVANT = 5,
146 EXCEPTION = 1,
147 READLOG,
148 FUNCARG,
149}
150
151#[derive(Clone, Copy)]
152#[repr(C)]
153pub struct Addr {
154 pub typ: AddrType,
155 pub val: ValueUnion,
156 pub off: u16,
157 pub flag: AddrFlag,
158}
159
160static TAINT_ENABLE: Once = Once::new();
161
162/// Ensure the taint system is enabled
163///
164/// Note: most functions call this internally, check the docs for individual helpers, as in most
165/// cases you don't need to call this directly unless you want to enable the taint system earlier
166/// than directly before using it.
167///
168/// On subsequent calls, this function will have the same performance characteristics as
169/// [`Once::call_once`](https://doc.rust-lang.org/std/sync/struct.Once.html#method.call_once).
170pub fn enable() {
171 TAINT_ENABLE.call_once(|| {
172 TAINT.taint2_enable_taint();
173 })
174}
175
176/// Check if the taint system is enabled
177pub fn is_enabled() -> bool {
178 TAINT.taint2_enabled()
179}
180
181/// Enable pointer tainting rules. May result in overtainting.
182pub fn enable_tainted_pointer() {
183 TAINT.taint2_enable_tainted_pointer()
184}
185
186/// Apply a 32-bit taint label to a given register.
187///
188/// ## Example
189///
190/// ```no_run
191/// use panda::taint;
192/// use panda::regs::Reg;
193///
194/// // Select register by enum for compile-time guarantees
195/// taint::label_reg(Reg::RAX, 1);
196///
197/// // Select register by string when needed
198/// taint::label_reg("rax", 1);
199/// ```
200///
201/// If a register is not supported by the [`Reg`] API, either make an issue or use
202/// [`taint2_label_reg`] directly. (example: `TAINT.taint2_label_reg(reg_num, 0, label)`)
203///
204/// [`taint2_label_reg`]: Taint::taint2_label_reg
205///
206/// **Note**: This will enable taint if not already enabled.
207pub fn label_reg(register: impl Into<Reg>, label: u32) {
208 let reg = register.into() as c_int;
209 enable();
210 for i in 0..std::mem::size_of::<target_ptr_t>() {
211 TAINT.taint2_label_reg(reg, i as c_int, label);
212 }
213}
214
215/// Add a 32-bit taint label to a given register. Any previous taint labels on the same register are not removed.
216///
217/// ## Example
218///
219/// ```no_run
220/// use panda::taint;
221/// use panda::regs::Reg;
222///
223/// // Select register by enum for compile-time guarantees
224/// taint::label_reg_additive(Reg::RAX, 1);
225///
226/// // Select register by string when needed
227/// taint::label_reg_additive("rax", 1);
228/// ```
229///
230/// If a register is not supported by the [`Reg`] API, either make an issue or use
231/// [`taint2_label_reg_additive`] directly. (example: `TAINT.taint2_label_reg_additive(reg_num, 0, label)`)
232///
233/// [`taint2_label_reg_additive`]: Taint::taint2_label_reg_additive
234///
235/// **Note**: This will enable taint if not already enabled.
236pub fn label_reg_additive(register: impl Into<Reg>, label: u32) {
237 let reg = register.into() as c_int;
238 enable();
239 for i in 0..std::mem::size_of::<target_ptr_t>() {
240 TAINT.taint2_label_reg_additive(reg, i as c_int, label);
241 }
242}
243
244/// Apply a 32-bit taint label to a specific byte of a given register.
245///
246/// ## Panics
247///
248/// This function panics if `byte_offset` is greater than or equal to the size of the register.
249///
250/// ## Example
251///
252/// ```no_run
253/// use panda::taint;
254/// use panda::regs::Reg;
255///
256/// // Select register by enum for compile-time guarantees
257/// taint::label_reg_byte(Reg::RAX, 0, 1);
258///
259/// // Select register by string when needed
260/// taint::label_reg_byte("rax", 0, 1);
261/// ```
262///
263/// **Note**: This will enable taint if not already enabled.
264pub fn label_reg_byte(register: impl Into<Reg>, byte_offset: usize, label: u32) {
265 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
266
267 let reg = register.into() as c_int;
268 enable();
269 TAINT.taint2_label_reg(reg, byte_offset as c_int, label);
270}
271
272/// Apply a 32-bit taint label to a specific byte of a given register. Any previous taint labels on the same register
273/// byte are not removed.
274///
275/// ## Panics
276///
277/// This function panics if `byte_offset` is greater than or equal to the size of the register.
278///
279/// ## Example
280///
281/// ```no_run
282/// use panda::taint;
283/// use panda::regs::Reg;
284///
285/// // Select register by enum for compile-time guarantees
286/// taint::label_reg_byte_additive(Reg::RAX, 0, 1);
287///
288/// // Select register by string when needed
289/// taint::label_reg_byte_additive("rax", 0, 1);
290/// ```
291///
292/// **Note**: This will enable taint if not already enabled.
293pub fn label_reg_byte_additive(register: impl Into<Reg>, byte_offset: usize, label: u32) {
294 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
295
296 let reg = register.into() as c_int;
297 enable();
298 TAINT.taint2_label_reg_additive(reg, byte_offset as c_int, label);
299}
300
301/// Apply a 32-bit taint label to a given byte in RAM.
302///
303/// ## Example
304///
305/// ```no_run
306/// use panda::taint;
307///
308/// // taint the byte at address 0xfffffff01c5 with a label of 4
309/// taint::label_ram(0xfffffff01c5, 4);
310/// ```
311///
312/// **Note**: This will enable taint if not already enabled.
313pub fn label_ram(addr: target_ptr_t, label: u32) {
314 enable();
315 TAINT.taint2_label_ram(addr as u64, label)
316}
317
318/// Add a 32-bit taint label to a given byte in RAM. Any previous taint labels on the same byte are not removed.
319///
320/// ## Example
321///
322/// ```no_run
323/// use panda::taint;
324///
325/// // Add a new taint label `4` to the byte at address 0xfffffff01c5
326/// taint::label_ram_additive(0xfffffff01c5, 4);
327/// ```
328///
329/// **Note**: This will enable taint if not already enabled.
330pub fn label_ram_additive(addr: target_ptr_t, label: u32) {
331 enable();
332 TAINT.taint2_label_ram_additive(addr as u64, label);
333}
334
335/// Apply a 32-bit taint label to a range of bytes in RAM.
336///
337/// ## Example
338///
339/// ```no_run
340/// use panda::taint;
341/// use panda::prelude::*;
342///
343/// // Select register by enum for compile-time guarantees
344/// let start = 0xfffffff01c4;
345/// let end = start + std::mem::size_of::<target_ptr_t>();
346/// taint::label_ram(start..end, 4);
347/// ```
348///
349/// **Note**: This will enable taint if not already enabled.
350pub fn label_ram_range(addr_range: Range<target_ptr_t>, label: u32) {
351 enable();
352 for addr in addr_range {
353 TAINT.taint2_label_ram(addr as u64, label);
354 }
355}
356
357/// Add a 32-bit taint label to a range of bytes in RAM. Any previous taint labels on the same range of bytes are not
358/// removed.
359///
360/// ## Example
361///
362/// ```no_run
363/// use panda::taint;
364/// use panda::prelude::*;
365///
366/// // Select register by enum for compile-time guarantees
367/// let start = 0xfffffff01c4;
368/// let end = start + std::mem::size_of::<target_ptr_t>();
369/// taint::label_ram_range_additive(start..end, 4);
370/// ```
371///
372/// **Note**: This will enable taint if not already enabled.
373pub fn label_ram_range_additive(addr_range: Range<target_ptr_t>, label: u32) {
374 enable();
375 for addr in addr_range {
376 TAINT.taint2_label_ram_additive(addr as u64, label);
377 }
378}
379
380/// Removes all taint labels on all bytes of a given register.
381///
382/// This function effectively does nothing if taint is not enabled.
383pub fn unlabel_reg(register: impl Into<Reg>) {
384 if !TAINT_ENABLE.is_completed() {
385 return;
386 }
387
388 let reg = register.into() as c_int;
389 for i in 0..std::mem::size_of::<target_ptr_t>() {
390 TAINT.taint2_delete_reg(reg, i as c_int);
391 }
392}
393
394/// Removes all taint labels on a specific byte of a given register.
395///
396/// This function effectively does nothing if taint is not enabled.
397///
398/// ## Panics
399///
400/// This function panics if `byte_offset` is greater than or equal to the size of the register.
401pub fn unlabel_reg_byte(register: impl Into<Reg>, byte_offset: usize) {
402 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
403
404 if !TAINT_ENABLE.is_completed() {
405 return;
406 }
407
408 let reg = register.into() as c_int;
409 TAINT.taint2_delete_reg(reg, byte_offset as c_int);
410}
411
412/// Removes all taint labels on a given byte in RAM.
413///
414/// This function effectively does nothing if taint is not enabled.
415pub fn unlabel_ram(addr: target_ptr_t) {
416 if !TAINT_ENABLE.is_completed() {
417 return;
418 }
419
420 TAINT.taint2_delete_ram(addr as u64);
421}
422
423/// Removes all taint labels on a range of bytes in RAM.
424///
425/// This function effectively does nothing if taint is not enabled.
426pub fn unlabel_ram_range(addr_range: Range<target_ptr_t>) {
427 if !TAINT_ENABLE.is_completed() {
428 return;
429 }
430
431 for addr in addr_range {
432 TAINT.taint2_delete_ram(addr as u64);
433 }
434}
435
436/// Check if a register is tainted by any label
437///
438/// ## Example
439///
440/// ```no_run
441/// use panda::taint;
442/// use panda::regs::Reg;
443///
444/// taint::label_reg(Reg::RAX);
445///
446/// if taint::check_reg(Reg::RAX) {
447/// println!("RAX is tainted by some label");
448/// }
449/// ```
450pub fn check_reg(reg: impl Into<Reg>) -> bool {
451 let reg_num = reg.into() as c_int;
452 check_reg_num(reg_num)
453}
454
455/// Check if a specific byte of a register is tainted by any label
456///
457/// ## Panics
458///
459/// This function panics if `byte_offset` is greater than or equal to the size of the register.
460///
461/// ## Example
462///
463/// ```no_run
464/// use panda::taint;
465/// use panda::regs::Reg;
466///
467/// taint::label_reg_byte(Reg::RAX, 1, 1);
468///
469/// if taint::check_reg_byte(Reg::RAX, 1) {
470/// println!("RAX[1] is tainted by some label");
471/// }
472/// ```
473pub fn check_reg_byte(reg: impl Into<Reg>, byte_offset: usize) -> bool {
474 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
475
476 let reg_num = reg.into() as c_int;
477 check_reg_num_byte(reg_num, byte_offset)
478}
479
480/// Check if a register is tainted by any label, by the register number
481///
482/// ### Notes
483///
484/// * When your given register is supported in the [`Reg`] API, use [`check_reg`]
485/// * If taint has not been enabled by **your** plugin, this will return false
486pub fn check_reg_num(reg_num: c_int) -> bool {
487 TAINT_ENABLE.is_completed() && {
488 let reg_size = std::mem::size_of::<target_ptr_t>();
489
490 (0..reg_size).any(|offset| TAINT.taint2_query_reg(reg_num, offset as c_int) > 0)
491 }
492}
493
494/// Check if a specific byte of a register is tainted by any label, by the register number
495///
496/// ## Panics
497///
498/// This function panics if `byte_offset` is greater than or equal to the size of the register.
499///
500/// ### Notes
501///
502/// * When your given register is supported in the [`Reg`] API, use [`check_reg_byte`]
503/// * If taint has not been enabled by **your** plugin, this will return false
504pub fn check_reg_num_byte(reg_num: c_int, byte_offset: usize) -> bool {
505 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
506 TAINT_ENABLE.is_completed() && TAINT.taint2_query_reg(reg_num, byte_offset as c_int) > 0
507}
508
509/// Check if a byte in RAM is tainted by any label
510///
511/// ## Example
512///
513/// ```no_run
514/// use panda::taint;
515///
516/// if taint::check_ram(0xffff_0034) {
517/// println!("Variable at 0xffff_0034 is tainted")
518/// }
519/// ```
520///
521/// **Note:** If taint has not been enabled by **your** plugin, this will return false
522pub fn check_ram(addr: target_ptr_t) -> bool {
523 TAINT_ENABLE.is_completed() && TAINT.taint2_query_ram(addr as u64) > 0
524}
525
526/// Check if any of a range of bytes in RAM is tainted by any label
527///
528/// ## Example
529///
530/// ```no_run
531/// use panda::taint;
532///
533/// if taint::check_ram_range(0xffff_0034..0xffff_0038) {
534/// println!("Variable at 0xffff_0034 is tainted")
535/// }
536/// ```
537///
538/// **Note:** If taint has not been enabled by **your** plugin, this will return false
539pub fn check_ram_range(mut addr_range: Range<target_ptr_t>) -> bool {
540 TAINT_ENABLE.is_completed() && addr_range.any(|addr| TAINT.taint2_query_ram(addr as u64) > 0)
541}
542
543pub fn check_laddr(addr: u64, offset: u64) -> bool {
544 TAINT_ENABLE.is_completed() && TAINT.taint2_query_laddr(addr, offset) > 0
545}
546
547/// Get a list of all taint labels applied to a register, excluding duplicates across bytes
548pub fn get_reg(reg: impl Into<Reg>) -> Vec<u32> {
549 let labels: HashSet<u32> = iter_reg_labels(reg).collect();
550
551 labels.into_iter().collect()
552}
553
554/// Get a list of all taint labels applied to a specific byte of a register
555///
556/// ## Panics
557///
558/// This function panics if `byte_offset` is greater than or equal to the size of the register.
559pub fn get_reg_byte(reg: impl Into<Reg>, byte_offset: usize) -> Vec<u32> {
560 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
561 iter_reg_byte_labels(reg, byte_offset).collect()
562}
563
564/// Get a list of all taint labels applied to a byte of memory
565pub fn get_ram(addr: target_ptr_t) -> Vec<u32> {
566 let mut query_result = QueryResult::empty();
567 TAINT.taint2_query_ram_full(addr as u64, &mut query_result);
568
569 if check_ram(addr) {
570 LabelIter {
571 done: query_result.num_labels == 0,
572 query_result,
573 }
574 .collect()
575 } else {
576 Vec::with_capacity(0)
577 }
578}
579
580/// Get a unique list of all taint labels applied to a segment of memory
581pub fn get_ram_range(addr_range: Range<target_ptr_t>) -> Vec<u32> {
582 let labels: HashSet<u32> = iter_ram_labels(addr_range).collect();
583
584 labels.into_iter().collect()
585}
586
587/// Iterate over all the taint labels applied to a given register
588///
589/// **NOTE**: this will repeat labels if they are applied to multiple bytes in
590/// the register. For automatic deduplication behavior, try [`get_reg`].
591pub fn iter_reg_labels(reg: impl Into<Reg>) -> impl Iterator<Item = u32> {
592 let reg_size = std::mem::size_of::<target_ptr_t>();
593
594 let reg = reg.into();
595 (0..reg_size)
596 .map(move |i| iter_reg_byte_labels(reg, i))
597 .flatten()
598}
599
600/// Iterate over all the taint labels applied to a specific byte of a given register
601///
602/// ## Panics
603///
604/// This function panics if `byte_offset` is greater than or equal to the size of the register.
605pub fn iter_reg_byte_labels(reg: impl Into<Reg>, byte_offset: usize) -> impl Iterator<Item = u32> {
606 assert!(byte_offset < std::mem::size_of::<target_ptr_t>());
607
608 let reg = reg.into();
609
610 let mut query_result = QueryResult::empty();
611 TAINT.taint2_query_reg_full(reg as u32, byte_offset as u32, &mut query_result);
612
613 if TAINT.taint2_query_reg(reg as c_int, byte_offset as c_int) > 0 {
614 LabelIter {
615 done: query_result.is_empty_or_invalid(),
616 query_result,
617 }
618 } else {
619 LabelIter {
620 done: true,
621 query_result,
622 }
623 }
624}
625
626/// Iterate over all the taint labels applied to a segment of memory
627///
628/// **NOTE**: this will repeat labels if they are applied to multiple bytes in
629/// the memory range. For automatic deduplication behavior, try [`get_ram_range`].
630pub fn iter_ram_labels(addr_range: Range<target_ptr_t>) -> impl Iterator<Item = u32> {
631 addr_range
632 .map(move |addr| {
633 let mut query_result = QueryResult::empty();
634 TAINT.taint2_query_ram_full(addr as u64, &mut query_result);
635
636 if check_ram(addr) {
637 LabelIter {
638 done: query_result.is_empty_or_invalid(),
639 query_result,
640 }
641 } else {
642 LabelIter {
643 done: true,
644 query_result,
645 }
646 }
647 })
648 .flatten()
649}
650
651#[repr(C)]
652pub struct QueryResult {
653 num_labels: u32,
654 ls: *mut c_void,
655 it_end: *mut c_void,
656 it_curr: *mut c_void,
657 tcn: u32,
658 cb_mask: u8,
659}
660
661impl QueryResult {
662 fn empty() -> Self {
663 Self {
664 num_labels: 0,
665 ls: ptr::null_mut(),
666 it_end: ptr::null_mut(),
667 it_curr: ptr::null_mut(),
668 tcn: 0,
669 cb_mask: 0,
670 }
671 }
672
673 fn is_empty_or_invalid(&self) -> bool {
674 self.num_labels == 0 || self.it_end.is_null() || self.it_curr.is_null()
675 }
676}
677
678pub struct LabelIter {
679 query_result: QueryResult,
680 done: bool,
681}
682
683impl Iterator for LabelIter {
684 type Item = u32;
685
686 fn next(&mut self) -> Option<Self::Item> {
687 if self.done {
688 None
689 } else {
690 Some(TAINT.taint2_query_result_next(&mut self.query_result, &mut self.done))
691 }
692 }
693}
694
695// TODO: sym_enable, sym_label_ram, sym_label_reg