@@ -74,7 +74,7 @@ def html_library(module, lib, stats_byver, versions):
74
74
for status in stats_byver [ver ][0 ]:
75
75
if status == "total" :
76
76
continue
77
- for (nid , _ ) in stats_byver [ver ][0 ][status ]:
77
+ for (nid , _ , _ , _ ) in stats_byver [ver ][0 ][status ]:
78
78
status_bynid [nid ] = status
79
79
cnt = Counter (status_bynid .values ())
80
80
both_stats = []
@@ -143,11 +143,13 @@ def html_single_library(module, lib, stats_bynid, versions):
143
143
output += '</tr>'
144
144
# Sort NIDs by the first firmware version they appear in, then by the names associated to them
145
145
sorted_nids = []
146
+ sources = {}
146
147
for v in versions :
147
148
ver_nids = []
148
149
for nid in stats_bynid :
149
150
if v in stats_bynid [nid ]:
150
- (_ , name ) = stats_bynid [nid ][v ]
151
+ (_ , name , source ) = stats_bynid [nid ][v ]
152
+ sources [name ] = source
151
153
ver_nids .append ((name , nid ))
152
154
for (_ , nid ) in sorted (ver_nids ):
153
155
if nid not in sorted_nids :
@@ -160,13 +162,16 @@ def html_single_library(module, lib, stats_bynid, versions):
160
162
if v not in stats_bynid [nid ]:
161
163
output += "<td></td>"
162
164
else :
163
- (status , name ) = stats_bynid [nid ][v ]
165
+ (status , name , source ) = stats_bynid [nid ][v ]
164
166
show_name = name
167
+ source_str = ''
165
168
if name == last_name :
166
169
show_name = '...'
170
+ elif source != '' and source != 'matching' :
171
+ source_str = ' (source: ' + source + ')'
167
172
last_name = name
168
173
(color , desc ) = find_html_status (status )
169
- output += f"""<td class="w3-{ color } "><div class="w3-tooltip">{ show_name } <span style="position:absolute;left:0;bottom:18px" class="w3-text w3-tag">NID is { desc } </span></div></td>"""
174
+ output += f"""<td class="w3-{ color } "><div class="w3-tooltip">{ show_name } { source_str } <span style="position:absolute;left:0;bottom:18px" class="w3-text w3-tag">NID is { desc } </span></div></td>"""
170
175
output += "</tr>"
171
176
output += "</table></div></body></html>"
172
177
return output
@@ -179,23 +184,27 @@ def make_stats(module, lib, version, obfuscated, cur_nids, prev_nonobf, prev_ok)
179
184
nok_nids = []
180
185
ok_nids = []
181
186
# Sort NIDs by category: unknown (name ends with the NID), ok (NID matches the hash) and nok (NID doesn't match the hash)
182
- for (nid , name ) in cur_nids :
187
+ for cur_nid in cur_nids :
188
+ nid = cur_nid ["nid" ]
189
+ name = cur_nid ["name" ]
183
190
if not obfuscated :
184
191
prev_nonobf [nid ] = (version , name )
185
192
if name .endswith (nid ):
186
- unk_nids .append (( nid , name ) )
193
+ unk_nids .append (cur_nid )
187
194
elif psp_libdoc .compute_nid (name ) == nid :
188
- ok_nids .append (( nid , name ) )
195
+ ok_nids .append (cur_nid )
189
196
else :
190
- nok_nids .append (( nid , name ) )
197
+ nok_nids .append (cur_nid )
191
198
192
199
if obfuscated :
193
200
nok_dubious = []
194
201
nok_from_prev = []
195
202
# If the NIDs have been randomized, it means they cannot be confirmed using the hash,
196
203
# but they might come from previous versions of the libraries when the NIDs were not randomized.
197
204
# Here, check if the names were found in previous non-randomized versions of the library.
198
- for (nid , name ) in nok_nids :
205
+ for cur_nid in nok_nids :
206
+ nid = cur_nid ["nid" ]
207
+ name = cur_nid ["name" ]
199
208
if nid in prev_ok or nid in prev_nonobf :
200
209
print ("WARN: previously seen non-obfuscated:" , module , lib , version , nid , name , prev_nonobf [nid ], file = sys .stderr )
201
210
found_prev = False
@@ -204,47 +213,57 @@ def make_stats(module, lib, version, obfuscated, cur_nids, prev_nonobf, prev_ok)
204
213
found_prev = True
205
214
break
206
215
if not found_prev :
207
- nok_dubious .append (( nid , name ) )
216
+ nok_dubious .append (cur_nid )
208
217
else :
209
- nok_from_prev .append (( nid , name ) )
218
+ nok_from_prev .append (cur_nid )
210
219
211
220
# For unknown names, differentiate between the ones seen in non-randomized versions, and the ones never seen in one (ie most likely randomized).
212
221
unk_nonobf = []
213
222
unk_obf = []
214
- for (nid , name ) in unk_nids :
223
+ for cur_nid in unk_nids :
224
+ nid = cur_nid ["nid" ]
215
225
if nid in prev_ok : # could by prev_nonobf, for pure information
216
226
print ("WARN: previously seen non-obfuscated OK:" , module , lib , version , nid , prev_ok [nid ], file = sys .stderr )
217
227
if nid in prev_nonobf :
218
- unk_nonobf .append (( nid , name ) )
228
+ unk_nonobf .append (cur_nid )
219
229
else :
220
- unk_obf .append (( nid , name ) )
230
+ unk_obf .append (cur_nid )
221
231
stats = {"known" : ok_nids , "unknown_nonobf" : unk_nonobf , "unknown_obf" : unk_obf , "nok_from_previous" : nok_from_prev , "nok_dubious" : nok_dubious }
222
232
else :
223
233
# For non-obfuscated modules, it's more simple, just do a safety check to see if there's no NID which was known in previous versions but is wrong or unknown in a later one.
224
- for (nid , name ) in (nok_nids + unk_nids ):
234
+ for cur_nid in (nok_nids + unk_nids ):
235
+ nid = cur_nid ["nid" ]
236
+ name = cur_nid ["name" ]
225
237
if nid in prev_ok :
226
238
print ("WARN: previously seen OK:" , module , lib , version , nid , name , prev_ok [nid ], file = sys .stderr )
227
239
stats = {"known" : ok_nids , "unknown" : unk_nids , "wrong" : nok_nids }
228
240
229
241
stats ['total' ] = len (cur_nids )
230
242
231
- for ( nid , name ) in ok_nids :
232
- prev_ok [nid ] = (version , name )
243
+ for cur_nid in ok_nids :
244
+ prev_ok [cur_nid [ " nid" ]] = (version , cur_nid [ " name" ] )
233
245
234
246
return stats
235
247
248
+ def get_nids_ver (nids , ver ):
249
+ output = []
250
+ for nid in nids :
251
+ if ver in nid ["versions" ]:
252
+ output .append (nid )
253
+ return output
254
+
236
255
# Make statistics for all the versions of a library, write the single HTML page, and return the row for the main page
237
256
def handle_library (module , lib , nids , versions ):
238
- vers = list (sorted (nids . keys ( )))
257
+ vers = list (sorted (set ([ v for nid in nids for v in nid [ "versions" ]] )))
239
258
# Indicates the NIDs had at least one round of randomization in previous (or current) firmware version
240
259
now_obfuscated = False
241
260
prev_nonobf = {}
242
261
prev_ok = {}
243
- stats_byver = {vers [0 ]: (make_stats (module , lib , vers [0 ], now_obfuscated , nids [ vers [0 ]] , prev_nonobf , prev_ok ), False )}
262
+ stats_byver = {vers [0 ]: (make_stats (module , lib , vers [0 ], now_obfuscated , get_nids_ver ( nids , vers [0 ]) , prev_nonobf , prev_ok ), False )}
244
263
for (v1 , v2 ) in zip (vers , vers [1 :]):
245
264
# For each consecutive firmware versions v1 and v2, see their respective NIDs
246
- v1_nids = set ([x [0 ] for x in nids [ v1 ] ])
247
- v2_nids = set ([x [0 ] for x in nids [ v2 ] ])
265
+ v1_nids = set ([x ["nid" ] for x in get_nids_ver ( nids , v1 ) ])
266
+ v2_nids = set ([x ["nid" ] for x in get_nids_ver ( nids , v2 ) ])
248
267
# Check the NIDs which appeared and the ones which disappeared
249
268
new_nids = v2_nids - v1_nids
250
269
disappear_nids = v1_nids - v2_nids
@@ -258,23 +277,23 @@ def handle_library(module, lib, nids, versions):
258
277
# If we find a new NID whose name is known, then it means there cannot have been a randomization here (note this check triggers rarely), except for 5.55 which misses functions from 5.51
259
278
for n in new_nids :
260
279
name = None
261
- for ( x , y ) in nids [ v2 ] :
262
- if x == n :
263
- name = y
280
+ for nid in get_nids_ver ( nids , v2 ) :
281
+ if nid [ "nid" ] == n :
282
+ name = nid [ "name" ]
264
283
if psp_libdoc .compute_nid (name ) == n and v1 != '5.55' : # some exceptions exist for 5.55 (which misses functions from 5.51)
265
284
is_obfuscated = False
266
285
if is_obfuscated :
267
286
now_obfuscated = True
268
- stats_byver [v2 ] = (make_stats (module , lib , v2 , now_obfuscated , nids [ v2 ] , prev_nonobf , prev_ok ), is_obfuscated )
287
+ stats_byver [v2 ] = (make_stats (module , lib , v2 , now_obfuscated , get_nids_ver ( nids , v2 ) , prev_nonobf , prev_ok ), is_obfuscated )
269
288
270
289
# Get the results by NID for the individual pages
271
290
stats_bynid = defaultdict (dict )
272
291
for v in vers :
273
292
for status in stats_byver [v ][0 ]:
274
293
if status == "total" :
275
294
continue
276
- for ( nid , name ) in stats_byver [v ][0 ][status ]:
277
- stats_bynid [nid ] [v ] = (status , name )
295
+ for cur_nid in stats_byver [v ][0 ][status ]:
296
+ stats_bynid [cur_nid [ " nid" ]] [v ] = (status , cur_nid [ " name" ], cur_nid [ "source" ] )
278
297
with open (OUTPUT_HTML + '/modules/' + module + '_' + lib + '.html' , 'w' ) as fd :
279
298
fd .write (html_single_library (module , lib , stats_bynid , vers ))
280
299
@@ -286,26 +305,28 @@ def main():
286
305
os .makedirs (OUTPUT_HTML + "/modules" , exist_ok = True )
287
306
288
307
# Parse all the NID export files
289
- filelist = glob .glob ('PSP*/*/Export /**/*.xml' , recursive = True )
308
+ filelist = glob .glob ('PSPLibDoc /**/*.xml' , recursive = True )
290
309
291
- nid_bylib = defaultdict (lambda : defaultdict (set ))
292
- lib_info = {}
310
+ nid_bylib = defaultdict (lambda : defaultdict (list ))
293
311
versions = set ()
294
312
295
- for (idx , file ) in enumerate (filelist ):
296
- version = file .split ('/' )[1 ]
297
- versions .add (version )
313
+ for file in filelist :
298
314
entries = psp_libdoc .loadPSPLibdoc (file )
299
315
for e in entries :
300
- lib_info [e .libraryName ] = (file .split ('/' )[- 1 ].replace ('xml' , 'prx' ), e .libraryFlags )
301
- nid_bylib [e .libraryName ][version ].add ((e .nid , e .name ))
316
+ cur_ver = [v for v in e .versions if not v .startswith ('vita' )]
317
+ for v in cur_ver :
318
+ versions .add (v )
319
+ if len (cur_ver ) == 0 :
320
+ continue
321
+ nid_bylib [e .prx ][e .libraryName ].append ({"nid" : e .nid , "name" : e .name , "versions" : cur_ver , "source" : e .source })
302
322
303
323
versions = list (sorted (versions ))
304
324
305
325
# Output the main and single HTML pages
306
326
html_output = html_header (versions )
307
- for (lib , libinfo ) in sorted (lib_info .items (), key = lambda x : (x [1 ][0 ], x [0 ])):
308
- html_output += handle_library (libinfo [0 ], lib , nid_bylib [lib ], versions )
327
+ for prx in sorted (nid_bylib ):
328
+ for lib in sorted (nid_bylib [prx ]):
329
+ html_output += handle_library (prx , lib , nid_bylib [prx ][lib ], versions )
309
330
html_output += html_footer ()
310
331
with open (OUTPUT_HTML + "/index.html" , 'w' ) as fd :
311
332
fd .write (html_output )
0 commit comments