summaryrefslogtreecommitdiff
path: root/tools/libdol2asm/data/struct.py
blob: 5f665627a3e7e6ec536d3b1684a40fc72b90890c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
from dataclasses import dataclass, field
from typing import List

from ..builder import AsyncBuilder
from .. import util
from ..types import *
from .base import *
from .identifier import *

@dataclass(eq=False)
class Structure(ArbitraryData):
    members: List[Symbol] = field(default_factory=list)

    def valid_reference(self, addr):
        for field in self.members:
            if field.addr == addr:
                return True
        return False

    def cpp_reference(self, accessor, addr):
        for field in self.members:
            if field.addr == addr:
                offset = field.addr - self.addr
                return f"(((char*)&{self.identifier.label})+0x{offset:X}) /* {field.identifier.name} */"

        raise Dol2ZelException(
            f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")

    def asm_reference(self, addr):
        for field in self.members:
            if field.addr == addr:
                offset = field.addr - self.addr
                return f"{self.identifier.label}+0x{offset:X}"

        return None

    def set_mlts(self, module: int, library: str, translation_unit: str, section: str):
        super().set_mlts(module, library, translation_unit, section)
        for member in self.members:
            member.set_mlts(module, library, translation_unit, section)

    async def export_declaration_head(self, exporter, builder: AsyncBuilder):
        has_data = any([ not not x.data for x in self.members ])
        if not has_data:
            for field in self.members:
                await builder.write(f"\t/* {field.addr:08X} {field.size:04X}+{field.padding:02X} {field.identifier.label} {field.identifier.name} */")

        await super().export_declaration_head(exporter, builder)

    async def export_declaration_body(self, exporter, builder: AsyncBuilder):
        has_data = any([ not not x.data for x in self.members ])
        if has_data:
            await builder.write(f" = {{")
            for field in self.members:
                await builder.write(f"\t/* {field.addr:08X} {field.size:04X}+{field.padding:02X} {field.identifier.label} {field.identifier.name} */")
                await self.export_u8_data(builder, field.data)
                
                if field.padding_data:
                    assert field.padding == len(field.padding_data)
                    await builder.write("\t/* padding */")
                    await self.export_u8_data(builder, field.padding_data)

            if self.padding_data:
                assert self.padding == len(self.padding_data)
                await builder.write("\t/* padding */")
                await self.export_u8_data(builder, self.padding_data)

            await builder.write("};")
        else:
            await builder.write(";")

    @staticmethod
    def create(section, group):
        first = group[0]
        last = group[-1]
        start = first.start
        end = last.end

        members = []
        for field in group:
            members.append(field)

        padding = last.padding
        padding_data = last.padding_data
        last.padding = 0
        last.padding_data = bytes()

        return Structure(Identifier("struct", start, None),
                          addr=start,
                          size=end - start,
                          padding=padding,
                          padding_data=padding_data,
                          data_type = U8,
                          members=members,
                          source=first.source)