Skip to content

Commit 3624f0d

Browse files
committed
Docs, check for unsupported platforms
1 parent 3f562df commit 3624f0d

File tree

2 files changed

+39
-4
lines changed

2 files changed

+39
-4
lines changed

devel/scan-vtables.lua

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
-- Scan and dump likely vtable addresses
12
memscan = require('memscan')
23

4+
local osType = dfhack.getOSType()
5+
if osType ~= 'linux' then
6+
qerror('unsupported OS: ' .. osType)
7+
end
8+
39
local df_ranges = {}
410
for i,mem in ipairs(dfhack.internal.getMemRanges()) do
511
if mem.read and (
@@ -30,22 +36,27 @@ for _, range in ipairs(df_ranges) do
3036

3137
local area = memscan.MemoryArea.new(range.start_addr, range.end_addr)
3238
for i = 1, area.uintptr_t.count - 1 do
39+
-- take every pointer-aligned value in memory mapped to the DF executable, and see if it is a valid vtable
40+
-- start by following the logic in Process::doReadClassName() and ensure it doesn't crash
3341
local vtable = area.uintptr_t:idx2addr(i)
3442
local typeinfo = area.uintptr_t[i - 1]
3543
if is_df_addr(typeinfo + 8) then
3644
local typestring = df.reinterpret_cast('uintptr_t', typeinfo + 8)[0]
3745
if is_df_addr(typestring) then
46+
-- rule out false positives by checking that the vtable points to a table of valid pointers
47+
-- TODO: check that the pointers are actually function pointers
3848
local vlen = 0
3949
while is_df_addr(vtable + (8*vlen)) and is_df_addr(df.reinterpret_cast('uintptr_t', vtable + (8*vlen))[0]) do
4050
vlen = vlen + 1
41-
break -- for now, any vtable with one valid function pointer is valid enough
51+
break -- for now, any vtable with one valid pointer is valid enough
4252
end
4353
if vlen > 0 then
54+
-- some false positives can be ruled out if the string.char() call in read_c_string() throws an error for invalid characters
4455
local ok, name = pcall(function()
45-
return memscan.read_c_string(df.reinterpret_cast('char', typestring))--:gsub('^%d+', '')
56+
return memscan.read_c_string(df.reinterpret_cast('char', typestring))
4657
end)
47-
if not ok then
48-
else
58+
if ok then
59+
-- GCC strips the "_Z" prefix from typeinfo names, so add it back
4960
local demangled_name = dfhack.internal.cxxDemangle('_Z' .. name)
5061
if demangled_name and not demangled_name:match('[<>]') and not demangled_name:match('^std::') then
5162
print(("<vtable-address name='%s' value='0x%x'/>"):format(demangled_name, vtable))

docs/devel/scan-vtables.rst

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
devel/scan-vtables
2+
==================
3+
4+
.. dfhack-tool::
5+
:summary: Scan for and print likely vtable addresses.
6+
:tags: dev
7+
8+
.. warning::
9+
10+
THIS SCRIPT IS STRICTLY FOR DFHACK DEVELOPERS.
11+
12+
Running this script on a new DF version will NOT MAKE IT RUN CORRECTLY if
13+
any data structures changed, thus possibly leading to CRASHES AND/OR
14+
PERMANENT SAVE CORRUPTION.
15+
16+
This script scans for likely vtables in memory pages mapped to the DF
17+
executable, and prints them in a format ready for inclusion in ``symbols.xml``
18+
19+
Usage
20+
-----
21+
22+
::
23+
24+
devel/scan-vtables

0 commit comments

Comments
 (0)