-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_windows_pdb.py
197 lines (143 loc) · 7.07 KB
/
test_windows_pdb.py
1
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
from pathlib import Path
from typing import List
import pytest
from pdbpy.codeview import LeafID
from pdbpy.codeview.records.symbols.datasym import DataSym
from pdbpy.codeview.symbols import SymEnum
from pdbpy.msf import MultiStreamFile
from pdbpy.pdb import PDB
from pdbpy.primitivetypes import BasicTypeEnum, BasicTypeInfo, BasicTypeModifier
from pdbpy.streams.debuginformationstream.debuginformationstream import PdbDebugInformationStream
from pdbpy.streams.directorystream import StreamDirectoryStream
from pdbpy.streams.pdbinfo import PdbInfoStream
from pdbpy.streams.symbolsstream import PdbSymbolRecordStream
from pdbpy.streams.typestream.pdbtypestream import PdbTypeStream
from pdbpy.streams.typestream.records import FieldList, Member, Pointer, TypeStructLike
from pdbpy.streams.typestream.records.base import PointerModeEnum, PointerTypeEnum, TypeProperties
from pdbpy.streams.typestream.records.pdbtypehashstream import PdbTypeHashStream
@pytest.fixture
def setup_windows_pdb() -> MultiStreamFile:
with open("example_pdbs/minimal.pdb", "rb") as f:
msf = MultiStreamFile(f)
return msf
@pytest.fixture
def setup_directory_stream(setup_windows_pdb: MultiStreamFile) -> StreamDirectoryStream:
stream = setup_windows_pdb.get("Directory")
return StreamDirectoryStream(stream)
@pytest.fixture
def setup_info_stream(
setup_windows_pdb: MultiStreamFile, setup_directory_stream: StreamDirectoryStream
) -> PdbInfoStream:
pdb_info_file = setup_directory_stream.get_stream_by_index(1)
assert pdb_info_file is not None
info_stream = PdbInfoStream(pdb_info_file)
return info_stream
@pytest.fixture
def setup_type_stream(setup_directory_stream: StreamDirectoryStream) -> PdbTypeStream:
type_info_file = setup_directory_stream.get_stream_by_index(2)
assert type_info_file is not None
type_stream = PdbTypeStream(type_info_file, upfront_memory=False)
type_hash_file = setup_directory_stream.get_stream_by_index(int(type_stream.header.hash_stream_number))
hash_stream = PdbTypeHashStream(type_hash_file, type_stream.header)
type_stream.set_hash_stream(hash_stream)
return type_stream
@pytest.fixture
def setup_debuginformation_stream(setup_directory_stream: StreamDirectoryStream) -> PdbDebugInformationStream:
debug_information_file = setup_directory_stream.get_stream_by_index(3)
assert debug_information_file is not None
debug_infomation_stream = PdbDebugInformationStream(debug_information_file)
return debug_infomation_stream
@pytest.fixture
def setup_symbol_record_stream(
setup_directory_stream: StreamDirectoryStream, setup_debuginformation_stream: PdbDebugInformationStream
) -> PdbSymbolRecordStream:
symbol_record_stream_number = setup_debuginformation_stream.header.symbol_record_stream
# print(symbol_record_stream_number)
symbol_record_stream_file = setup_directory_stream.get_stream_by_index(int(symbol_record_stream_number))
assert symbol_record_stream_file is not None
symbol_record_stream = PdbSymbolRecordStream(symbol_record_stream_file)
return symbol_record_stream
def test_can_open(setup_windows_pdb: MultiStreamFile):
assert setup_windows_pdb is not None
def test_directory_exists(setup_directory_stream: StreamDirectoryStream):
assert setup_directory_stream is not None
def test_directory_info_exists(setup_info_stream: PdbInfoStream):
assert setup_info_stream is not None
def test_directory_type_exists(setup_type_stream: PdbTypeStream):
assert setup_type_stream is not None
def test_debug_information_stream(setup_debuginformation_stream: PdbDebugInformationStream):
assert setup_debuginformation_stream is not None
def test_type_lookup_by_type_index(setup_type_stream: PdbTypeStream):
typeindex = 4100
ptr = setup_type_stream.get_by_type_index(ti=typeindex) # type: ignore
assert ptr.record_type == LeafID.POINTER
assert isinstance(ptr, Pointer)
assert BasicTypeInfo(ptr.reference_type) == (BasicTypeEnum.NarrowCharacter, BasicTypeModifier.NearPointer64)
assert ptr.attributes.kind == PointerTypeEnum.BITS_64
assert ptr.attributes.mode == PointerModeEnum.Normal
def test_type_lookup_by_type_name(setup_type_stream: PdbTypeStream):
for ti, record in setup_type_stream.get_ti_and_record_for_name(name="Yolo"):
assert ti == 4099
assert isinstance(record, TypeStructLike)
assert record.element_count == 3
expected_properties = TypeProperties(has_unique_name=1)
# expected_properties.has_unique_name = 1
assert record.properties == expected_properties
assert record.fields == 4098
assert record.derived == 0
assert record.vshape == 0
assert record.name == "Yolo"
assert record.unique_name == ".?AUYolo@@"
field_record = setup_type_stream.get_by_type_index(ti=record.fields) # type: ignore
assert isinstance(field_record, FieldList)
assert len(field_record.members) == 3
assert all(isinstance(member, Member) for member in field_record.members)
x, y, z = field_record.members
assert x.name == "x"
assert y.name == "y"
assert z.name == "z"
assert BasicTypeInfo(x.field_type) == (BasicTypeEnum.Int32, BasicTypeModifier.Direct)
assert BasicTypeInfo(y.field_type) == (BasicTypeEnum.Float32, BasicTypeModifier.Direct)
assert BasicTypeInfo(z.field_type) == (BasicTypeEnum.Float64, BasicTypeModifier.NearPointer64)
def test_module_information(setup_debuginformation_stream: PdbDebugInformationStream):
for module in setup_debuginformation_stream.modules:
if module.module.lower().endswith(".obj"):
assert module.object.lower().endswith(".lib") or module.object == module.module
# print(module)
# print(setup_debuginformation_stream.header)
def test_symbol_records_stream(setup_symbol_record_stream: PdbSymbolRecordStream, setup_type_stream: PdbTypeStream):
assert setup_symbol_record_stream is not None
symbols: List[str] = []
for symbol in setup_symbol_record_stream.symbols():
if isinstance(symbol, DataSym):
symbols.append(symbol.name)
typ = symbol.typ
if typ > 4096:
t = setup_type_stream.get_by_type_index(typ)
else:
t = BasicTypeInfo(typ)
print(f"{symbol} : {t}")
else:
print(f"Symbol: {symbol}")
expected_symbols = [
"_fltused",
"global_char_ptr_ptr",
"static_global_char_ptr_ptr",
"namespaced_global_char_ptr_ptr",
"export_global_char_ptr_ptr",
]
assert expected_symbols == symbols
def test_symbol_lookup():
pdb = PDB("example_pdbs/addr.pdb")
symbol = pdb.find_symbol("global_variable", types=[SymEnum.S_GDATA32])
assert symbol
assert symbol.name == "global_variable"
if not isinstance(symbol, DataSym):
return
def test_symbol_address():
pdb = PDB("example_pdbs/addr.pdb")
addr = pdb.find_symbol_address("global_variable")
assert addr is not None
addr = f"{addr:016X}"
print(addr)
assert Path("example_pdbs/addr.txt").read_text().strip() == addr