Skip to content

Examples | Iterate through a `struc_t` and its dependencies whilst maintaining their order

Ali Rizvi-Santiago edited this page Nov 18, 2022 · 2 revisions

Simple solver

If you have some structure that you're trying to export to some other language/framework, but it's full of references and is dependant on a ton of other structures/enumerations/unions. You can throw a solver like the following at it so that way you can get them ordered properly before outputting them to some useful format.

import pycosat
class structures:
    @staticmethod
    def collect(st):
        for m in st.members:
            s = m.type
            if isinstance(s, list):
                s, _ = s
            if isinstance(s, tuple):
                s, _ = s
            if isinstance(s, struc.structure_t):
                for item in deps(s):
                    yield item
                yield st, s
            elif struc.has(m.typeinfo):
                s = struc.by(m.typeinfo)
                for item in deps(s):
                    yield item
                yield st, s
            else:
                print('unknown type', m)
            continue
        return

    @staticmethod
    def dependencies(iterable):
        res = {}
        for st, dep in iterable:
            res.setdefault(dep, set())
            res.setdefault(st, set()).add(dep)
        return res

    @staticmethod
    def results(start, dependencies):
        rules = {}
        for dep, items in dependencies.items():
            [ rules.setdefault(item, set()) for item in items ]
        rules.update(dependencies)
        assert(start in rules)

        to, of, variables = {}, {}, [item for item in rules]
        for i, item in enumerate(variables):
            to[item], of[1 + i] = 1 + i, item

        clauses = []
        for item, dependencies in rules.items():
            for dependency in dependencies:
                clauses.append([-to[item], +to[dependency]])
            continue
        clauses.append([+to[start]])

        for solution in pycosat.itersolve(clauses):
            result = [ item for item in solution ]
            yield [ of[item] for item in result ]
        return

mystruc = struc.search('*whatever*')
allstructures = structures.collect(mystruc)
theirdependencies = structures.dependencies(allstructures)
for struc in structures.results(mystruc, theirdependencies):
    print(struc)

Outputting an individual structure/union definition

Useful format? Normally you'd just use mystruc as an object so you can iterate through members and extract types, but to get a contiguous layout of them, you can just use structure.members(mystruc) which will give you the offset, size, and tags for every member (including holes). There's also structure.fragment if you're trying to slice some part of a function frame so you can copy the exact data for some external python.

print('struct ' + mystruc.name + '{')
for offset, size, tags in structure.members(mystruc):
    member = mystruc.by(offset)
    myname = tags.get('__name__', "unnamed_{:x}".format(offset))
    mycomment = "// {!s}".format(tags)
    print('    char %s[%d];          // %s'%(myname, size, mycomment))
print('}')

(note: For brevity, this is not tracking pointers or "complex" types. To do get the structure name for a type, you can use struc.by on a member_t.typeinfo property, pythonic types via member_t.type, or db.t.array to get information about complicated types)