Skip to content

Commit c363dab

Browse files
committed
Tidy up coverage classes and methods
1 parent d614855 commit c363dab

File tree

5 files changed

+64
-64
lines changed

5 files changed

+64
-64
lines changed

qiling/extensions/coverage/formats/base.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
#
55

66
from abc import ABC, abstractmethod
7+
from typing import TYPE_CHECKING
78

8-
from qiling import Qiling
9+
10+
if TYPE_CHECKING:
11+
from qiling import Qiling
912

1013

1114
class QlBaseCoverage(ABC):
@@ -15,25 +18,21 @@ class QlBaseCoverage(ABC):
1518
all the methods marked with the @abstractmethod decorator.
1619
"""
1720

21+
FORMAT_NAME: str
22+
1823
def __init__(self, ql: Qiling):
1924
super().__init__()
2025

2126
self.ql = ql
2227

23-
@property
24-
@staticmethod
25-
@abstractmethod
26-
def FORMAT_NAME() -> str:
27-
raise NotImplementedError
28-
2928
@abstractmethod
30-
def activate(self):
29+
def activate(self) -> None:
3130
pass
3231

3332
@abstractmethod
34-
def deactivate(self):
33+
def deactivate(self) -> None:
3534
pass
3635

3736
@abstractmethod
38-
def dump_coverage(self, coverage_file: str):
37+
def dump_coverage(self, coverage_file: str) -> None:
3938
pass

qiling/extensions/coverage/formats/drcov.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6-
from ctypes import Structure
7-
from ctypes import c_uint32, c_uint16
6+
from __future__ import annotations
7+
8+
from ctypes import Structure, c_uint32, c_uint16
9+
from typing import TYPE_CHECKING, BinaryIO
810

911
from .base import QlBaseCoverage
1012

1113

14+
if TYPE_CHECKING:
15+
from qiling import Qiling
16+
17+
1218
# Adapted from https://www.ayrx.me/drcov-file-format
1319
class bb_entry(Structure):
1420
_fields_ = [
@@ -29,36 +35,35 @@ class QlDrCoverage(QlBaseCoverage):
2935

3036
FORMAT_NAME = "drcov"
3137

32-
def __init__(self, ql):
38+
def __init__(self, ql: Qiling):
3339
super().__init__(ql)
3440

3541
self.drcov_version = 2
3642
self.drcov_flavor = 'drcov'
3743
self.basic_blocks = []
3844
self.bb_callback = None
3945

40-
@staticmethod
41-
def block_callback(ql, address, size, self):
42-
for mod_id, mod in enumerate(ql.loader.images):
43-
if mod.base <= address <= mod.end:
44-
ent = bb_entry(address - mod.base, size, mod_id)
45-
self.basic_blocks.append(ent)
46-
break
46+
def activate(self) -> None:
47+
self.bb_callback = self.ql.hook_block(self.block_callback)
4748

48-
def activate(self):
49-
self.bb_callback = self.ql.hook_block(self.block_callback, user_data=self)
49+
def deactivate(self) -> None:
50+
if self.bb_callback:
51+
self.ql.hook_del(self.bb_callback)
5052

51-
def deactivate(self):
52-
self.ql.hook_del(self.bb_callback)
53+
def dump_coverage(self, coverage_file: str) -> None:
54+
def __write_line(bio: BinaryIO, line: str) -> None:
55+
bio.write(f'{line}\n'.encode())
5356

54-
def dump_coverage(self, coverage_file):
5557
with open(coverage_file, "wb") as cov:
56-
cov.write(f"DRCOV VERSION: {self.drcov_version}\n".encode())
57-
cov.write(f"DRCOV FLAVOR: {self.drcov_flavor}\n".encode())
58-
cov.write(f"Module Table: version {self.drcov_version}, count {len(self.ql.loader.images)}\n".encode())
59-
cov.write("Columns: id, base, end, entry, checksum, timestamp, path\n".encode())
58+
__write_line(cov, f"DRCOV VERSION: {self.drcov_version}")
59+
__write_line(cov, f"DRCOV FLAVOR: {self.drcov_flavor}")
60+
__write_line(cov, f"Module Table: version {self.drcov_version}, count {len(self.ql.loader.images)}")
61+
__write_line(cov, "Columns: id, base, end, entry, checksum, timestamp, path")
62+
6063
for mod_id, mod in enumerate(self. ql.loader.images):
61-
cov.write(f"{mod_id}, {mod.base}, {mod.end}, 0, 0, 0, {mod.path}\n".encode())
62-
cov.write(f"BB Table: {len(self.basic_blocks)} bbs\n".encode())
63-
for bb in self.basic_blocks:
64+
__write_line(cov, f"{mod_id}, {mod.base}, {mod.end}, 0, 0, 0, {mod.path}")
65+
66+
__write_line(cov, f"BB Table: {len(self.basic_blocks)} bbs")
67+
68+
for bb in self.basic_blocks.values():
6469
cov.write(bytes(bb))

qiling/extensions/coverage/formats/drcov_exact.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
#
2+
#
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

@@ -17,10 +17,7 @@ class QlDrCoverageExact(QlDrCoverage):
1717

1818
FORMAT_NAME = "drcov_exact"
1919

20-
def __init__(self, ql):
21-
super().__init__(ql)
22-
23-
def activate(self):
20+
def activate(self) -> None:
2421
# We treat every instruction as a block on its own.
2522
self.bb_callback = self.ql.hook_code(self.block_callback, user_data=self)
2623

qiling/extensions/coverage/formats/ezcov.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
#!/usr/bin/env python3
2-
#
2+
#
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
55

6+
from __future__ import annotations
67
from collections import namedtuple
78
from os.path import basename
9+
from typing import TYPE_CHECKING, List
810

911
from .base import QlBaseCoverage
1012

1113

14+
if TYPE_CHECKING:
15+
from qiling import Qiling
16+
17+
1218
# Adapted from https://github.com/nccgroup/Cartographer/blob/main/EZCOV.md#coverage-data
1319
class bb_entry(namedtuple('bb_entry', 'offset size mod_id')):
1420
def csvline(self):
@@ -27,27 +33,24 @@ class QlEzCoverage(QlBaseCoverage):
2733

2834
FORMAT_NAME = "ezcov"
2935

30-
def __init__(self, ql):
36+
def __init__(self, ql: Qiling):
3137
super().__init__(ql)
38+
3239
self.ezcov_version = 1
33-
self.ezcov_flavor = 'ezcov'
34-
self.basic_blocks = []
35-
self.bb_callback = None
40+
self.ezcov_flavor = 'ezcov'
41+
self.basic_blocks: List[bb_entry] = []
42+
self.bb_callback = None
3643

37-
@staticmethod
38-
def block_callback(ql, address, size, self):
39-
mod = ql.loader.find_containing_image(address)
40-
if mod is not None:
41-
ent = bb_entry(address - mod.base, size, basename(mod.path))
42-
self.basic_blocks.append(ent)
44+
def block_callback(self, ql: Qiling, address: int, size: int):
4345

44-
def activate(self):
45-
self.bb_callback = self.ql.hook_block(self.block_callback, user_data=self)
46+
def activate(self) -> None:
47+
self.bb_callback = self.ql.hook_block(self.block_callback)
4648

47-
def deactivate(self):
48-
self.ql.hook_del(self.bb_callback)
49+
def deactivate(self) -> None:
50+
if self.bb_callback:
51+
self.ql.hook_del(self.bb_callback)
4952

50-
def dump_coverage(self, coverage_file):
53+
def dump_coverage(self, coverage_file: str) -> None:
5154
with open(coverage_file, "w") as cov:
5255
cov.write(f"EZCOV VERSION: {self.ezcov_version}\n")
5356
cov.write("# Qiling EZCOV exporter tool\n")
Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python3
2-
#
2+
#
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
# This code structure is copied and modified from the coverage extension
55

@@ -12,24 +12,20 @@ class QlBaseTrace(ABC):
1212
To add support for a new coverage format, just derive from this class and implement
1313
all the methods marked with the @abstractmethod decorator.
1414
"""
15-
15+
16+
FORMAT_NAME: str
17+
1618
def __init__(self):
1719
super().__init__()
1820

19-
@property
20-
@staticmethod
21-
@abstractmethod
22-
def FORMAT_NAME():
23-
raise NotImplementedError
24-
2521
@abstractmethod
26-
def activate(self):
22+
def activate(self) -> None:
2723
pass
2824

2925
@abstractmethod
30-
def deactivate(self):
26+
def deactivate(self) -> None:
3127
pass
3228

3329
@abstractmethod
34-
def dump_trace(self, trace_file):
30+
def dump_trace(self, trace_file: str) -> None:
3531
pass

0 commit comments

Comments
 (0)