Skip to content

Commit

Permalink
Docs, check for unsupported platforms
Browse files Browse the repository at this point in the history
  • Loading branch information
lethosor committed Aug 10, 2023
1 parent 3f562df commit 706f0e9
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 4 deletions.
19 changes: 15 additions & 4 deletions devel/scan-vtables.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
-- Scan and dump likely vtable addresses
memscan = require('memscan')

local osType = dfhack.getOSType()
if osType ~= 'linux' then
qerror('unsupported OS: ' .. osType)
end

local df_ranges = {}
for i,mem in ipairs(dfhack.internal.getMemRanges()) do
if mem.read and (
Expand Down Expand Up @@ -30,22 +36,27 @@ for _, range in ipairs(df_ranges) do

local area = memscan.MemoryArea.new(range.start_addr, range.end_addr)
for i = 1, area.uintptr_t.count - 1 do
-- take every pointer-aligned value in memory mapped to the DF executable, and see if it is a valid vtable
-- start by following the logic in Process::doReadClassName() and ensure it doesn't crash
local vtable = area.uintptr_t:idx2addr(i)
local typeinfo = area.uintptr_t[i - 1]
if is_df_addr(typeinfo + 8) then
local typestring = df.reinterpret_cast('uintptr_t', typeinfo + 8)[0]
if is_df_addr(typestring) then
-- rule out false positives by checking that the vtable points to a table of valid pointers
-- TODO: check that the pointers are actually function pointers
local vlen = 0
while is_df_addr(vtable + (8*vlen)) and is_df_addr(df.reinterpret_cast('uintptr_t', vtable + (8*vlen))[0]) do
vlen = vlen + 1
break -- for now, any vtable with one valid function pointer is valid enough
break -- for now, any vtable with one valid pointer is valid enough
end
if vlen > 0 then
-- some false positives can be ruled out if the string.char() call in read_c_string() throws an error for invalid characters
local ok, name = pcall(function()
return memscan.read_c_string(df.reinterpret_cast('char', typestring))--:gsub('^%d+', '')
return memscan.read_c_string(df.reinterpret_cast('char', typestring))
end)
if not ok then
else
if ok then
-- GCC strips the "_Z" prefix from typeinfo names, so add it back
local demangled_name = dfhack.internal.cxxDemangle('_Z' .. name)
if demangled_name and not demangled_name:match('[<>]') and not demangled_name:match('^std::') then
print(("<vtable-address name='%s' value='0x%x'/>"):format(demangled_name, vtable))
Expand Down
24 changes: 24 additions & 0 deletions docs/devel/scan-vtables.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
devel/dump-offsets
==================

.. dfhack-tool::
:summary: Scan for and print likely vtable addresses.
:tags: dev

.. warning::

THIS SCRIPT IS STRICTLY FOR DFHACK DEVELOPERS.

Running this script on a new DF version will NOT MAKE IT RUN CORRECTLY if
any data structures changed, thus possibly leading to CRASHES AND/OR
PERMANENT SAVE CORRUPTION.

This script scans for likely vtables in memory pages mapped to the DF
executable, and prints them in a format ready for inclusion in ``symbols.xml``

Usage
-----

::

devel/scan-vtables

0 comments on commit 706f0e9

Please sign in to comment.