Skip to content

Commit db32a20

Browse files
committed
Adapt scripts to new format
1 parent ea934e7 commit db32a20

10 files changed

+94
-558
lines changed

.github/workflows/main.yml

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ jobs:
1414
run: |
1515
python3 ./make_statistics.py
1616
- name: Deploy documentation
17-
if: github.ref == 'refs/heads/main'
1817
uses: JamesIves/[email protected]
1918
with:
2019
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

check_missing_known_nids.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
all_unk_nids = []
1313

1414
# Browse all the export files
15-
filelist = glob.glob('*PSP*/*/Export/**/*.xml', recursive=True)
15+
filelist = glob.glob('PSPLibDoc/**/*.xml', recursive=True)
1616
for (idx, file) in enumerate(filelist):
1717
entries = psp_libdoc.loadPSPLibdoc(file)
1818
# Get the version and module name from the path

convert-all.sh

-7
This file was deleted.

make_statistics.py

+58-37
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def html_library(module, lib, stats_byver, versions):
7474
for status in stats_byver[ver][0]:
7575
if status == "total":
7676
continue
77-
for (nid, _) in stats_byver[ver][0][status]:
77+
for (nid, _, _, _) in stats_byver[ver][0][status]:
7878
status_bynid[nid] = status
7979
cnt = Counter(status_bynid.values())
8080
both_stats = []
@@ -143,11 +143,13 @@ def html_single_library(module, lib, stats_bynid, versions):
143143
output += '</tr>'
144144
# Sort NIDs by the first firmware version they appear in, then by the names associated to them
145145
sorted_nids = []
146+
sources = {}
146147
for v in versions:
147148
ver_nids = []
148149
for nid in stats_bynid:
149150
if v in stats_bynid[nid]:
150-
(_, name) = stats_bynid[nid][v]
151+
(_, name, source) = stats_bynid[nid][v]
152+
sources[name] = source
151153
ver_nids.append((name, nid))
152154
for (_, nid) in sorted(ver_nids):
153155
if nid not in sorted_nids:
@@ -160,13 +162,16 @@ def html_single_library(module, lib, stats_bynid, versions):
160162
if v not in stats_bynid[nid]:
161163
output += "<td></td>"
162164
else:
163-
(status, name) = stats_bynid[nid][v]
165+
(status, name, source) = stats_bynid[nid][v]
164166
show_name = name
167+
source_str = ''
165168
if name == last_name:
166169
show_name = '...'
170+
elif source != '' and source != 'matching':
171+
source_str = ' (source: ' + source + ')'
167172
last_name = name
168173
(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>"""
170175
output += "</tr>"
171176
output += "</table></div></body></html>"
172177
return output
@@ -179,23 +184,27 @@ def make_stats(module, lib, version, obfuscated, cur_nids, prev_nonobf, prev_ok)
179184
nok_nids = []
180185
ok_nids = []
181186
# 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"]
183190
if not obfuscated:
184191
prev_nonobf[nid] = (version, name)
185192
if name.endswith(nid):
186-
unk_nids.append((nid, name))
193+
unk_nids.append(cur_nid)
187194
elif psp_libdoc.compute_nid(name) == nid:
188-
ok_nids.append((nid, name))
195+
ok_nids.append(cur_nid)
189196
else:
190-
nok_nids.append((nid, name))
197+
nok_nids.append(cur_nid)
191198

192199
if obfuscated:
193200
nok_dubious = []
194201
nok_from_prev = []
195202
# If the NIDs have been randomized, it means they cannot be confirmed using the hash,
196203
# but they might come from previous versions of the libraries when the NIDs were not randomized.
197204
# 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"]
199208
if nid in prev_ok or nid in prev_nonobf:
200209
print("WARN: previously seen non-obfuscated:", module, lib, version, nid, name, prev_nonobf[nid], file=sys.stderr)
201210
found_prev = False
@@ -204,47 +213,57 @@ def make_stats(module, lib, version, obfuscated, cur_nids, prev_nonobf, prev_ok)
204213
found_prev = True
205214
break
206215
if not found_prev:
207-
nok_dubious.append((nid, name))
216+
nok_dubious.append(cur_nid)
208217
else:
209-
nok_from_prev.append((nid, name))
218+
nok_from_prev.append(cur_nid)
210219

211220
# For unknown names, differentiate between the ones seen in non-randomized versions, and the ones never seen in one (ie most likely randomized).
212221
unk_nonobf = []
213222
unk_obf = []
214-
for (nid, name) in unk_nids:
223+
for cur_nid in unk_nids:
224+
nid = cur_nid["nid"]
215225
if nid in prev_ok: # could by prev_nonobf, for pure information
216226
print("WARN: previously seen non-obfuscated OK:", module, lib, version, nid, prev_ok[nid], file=sys.stderr)
217227
if nid in prev_nonobf:
218-
unk_nonobf.append((nid, name))
228+
unk_nonobf.append(cur_nid)
219229
else:
220-
unk_obf.append((nid, name))
230+
unk_obf.append(cur_nid)
221231
stats = {"known": ok_nids, "unknown_nonobf": unk_nonobf, "unknown_obf": unk_obf, "nok_from_previous": nok_from_prev, "nok_dubious": nok_dubious}
222232
else:
223233
# 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"]
225237
if nid in prev_ok:
226238
print("WARN: previously seen OK:", module, lib, version, nid, name, prev_ok[nid], file=sys.stderr)
227239
stats = {"known": ok_nids, "unknown": unk_nids, "wrong": nok_nids}
228240

229241
stats['total'] = len(cur_nids)
230242

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"])
233245

234246
return stats
235247

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+
236255
# Make statistics for all the versions of a library, write the single HTML page, and return the row for the main page
237256
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"]])))
239258
# Indicates the NIDs had at least one round of randomization in previous (or current) firmware version
240259
now_obfuscated = False
241260
prev_nonobf = {}
242261
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)}
244263
for (v1, v2) in zip(vers, vers[1:]):
245264
# 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)])
248267
# Check the NIDs which appeared and the ones which disappeared
249268
new_nids = v2_nids - v1_nids
250269
disappear_nids = v1_nids - v2_nids
@@ -258,23 +277,23 @@ def handle_library(module, lib, nids, versions):
258277
# 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
259278
for n in new_nids:
260279
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"]
264283
if psp_libdoc.compute_nid(name) == n and v1 != '5.55': # some exceptions exist for 5.55 (which misses functions from 5.51)
265284
is_obfuscated = False
266285
if is_obfuscated:
267286
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)
269288

270289
# Get the results by NID for the individual pages
271290
stats_bynid = defaultdict(dict)
272291
for v in vers:
273292
for status in stats_byver[v][0]:
274293
if status == "total":
275294
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"])
278297
with open(OUTPUT_HTML + '/modules/' + module + '_' + lib + '.html', 'w') as fd:
279298
fd.write(html_single_library(module, lib, stats_bynid, vers))
280299

@@ -286,26 +305,28 @@ def main():
286305
os.makedirs(OUTPUT_HTML + "/modules", exist_ok=True)
287306

288307
# Parse all the NID export files
289-
filelist = glob.glob('PSP*/*/Export/**/*.xml', recursive=True)
308+
filelist = glob.glob('PSPLibDoc/**/*.xml', recursive=True)
290309

291-
nid_bylib = defaultdict(lambda: defaultdict(set))
292-
lib_info = {}
310+
nid_bylib = defaultdict(lambda: defaultdict(list))
293311
versions = set()
294312

295-
for (idx, file) in enumerate(filelist):
296-
version = file.split('/')[1]
297-
versions.add(version)
313+
for file in filelist:
298314
entries = psp_libdoc.loadPSPLibdoc(file)
299315
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})
302322

303323
versions = list(sorted(versions))
304324

305325
# Output the main and single HTML pages
306326
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)
309330
html_output += html_footer()
310331
with open(OUTPUT_HTML + "/index.html", 'w') as fd:
311332
fd.write(html_output)

psp_libdoc.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def loadPSPLibdoc(xmlFile):
3131
functionName = function.find("NAME").text
3232
versions = [x.text for x in function.findall("VERSIONS/VERSION")]
3333
source_elem = function.find("SOURCE")
34-
source = '' if source_elem is None else source_elem.text
34+
source = '' if source_elem is None else ('' if source_elem.text is None else source_elem.text)
3535
entries.append(NIDEntry(nid=functionNID, name=functionName, prx=prxFile,
3636
prxName=prxName, libraryName=libraryName, libraryFlags=libraryFlags,
3737
versions=versions, source=source))
@@ -110,13 +110,15 @@ def loadPSPExportFile(exportFile):
110110
functionName = functionName.strip()
111111
functionNID = functionNID.strip().upper().removeprefix('0X')
112112
entries.append(NIDEntry(nid=functionNID, name=functionName, prx=" ",
113-
prxName=" ", libraryName=libraryName, libraryFlags=libraryFlags))
113+
prxName=" ", libraryName=libraryName, libraryFlags=libraryFlags,
114+
versions=[], source=""))
114115

115116
elif line.startswith("PSP_EXPORT_FUNC_HASH"):
116117
functionName = line[line.find("(") + 1 : line.find(")")].strip()
117118
functionNID = getNidForString(functionName)
118119
entries.append(NIDEntry(nid=functionNID, name=functionName, prx=" ",
119-
prxName=" ", libraryName=libraryName, libraryFlags=libraryFlags))
120+
prxName=" ", libraryName=libraryName, libraryFlags=libraryFlags,
121+
versions=[], source=""))
120122

121123
elif line.startswith("PSP_EXPORT_END"):
122124
libraryName = " "
@@ -135,7 +137,7 @@ def loadFunctionFile(xmlFile):
135137
functionNID = function.find("NID").text.upper().removeprefix('0X')
136138
functionName =function.find("NAME").text
137139
entries.append(NIDEntry(nid=functionNID, name=functionName, prx=" ",
138-
prxName=" ", libraryName=" ", libraryFlags=" "))
140+
prxName=" ", libraryName=" ", libraryFlags=" ", versions=[], source=""))
139141

140142
return entries
141143

@@ -161,7 +163,7 @@ def loadHLEFunctionFile(inputFile):
161163
functionNID = hleEntry[0].upper().removeprefix('0X')
162164
functionName = hleEntry[2].strip()[1:-1]
163165
entries.append(NIDEntry(nid=functionNID, name=functionName, prx=" ",
164-
prxName=" ", libraryName=libraryName, libraryFlags=" "))
166+
prxName=" ", libraryName=libraryName, libraryFlags=" ", versions=[], source=""))
165167

166168
return entries
167169

0 commit comments

Comments
 (0)