Skip to content

data

Data management.

A data is a piece of information that isn't code.

Data

Base class for data.

All data have at least a type and a value. They are referenced inside the program by and to other data and code.

Parameters:

Name Type Description Default
proto_index Index

Index in the protobuf

required
data 'quokka.pb.Quokka.Data'

Protobuf value of the data.

required
program Program

Program backref

required

Attributes:

Name Type Description
proto_index Index

Index in the protobuf

address AddressT

Data address

type 'DataType'

Data type

program Program

Reference to the Program

is_initialized bool

Is the data initialized?

size Optional[int]

Data size (depends on the type usually)

name Optional[str]

Data name (if any)

Source code in quokka/data.py
 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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
class Data:
    """Base class for data.

    All data have at least a type and a value.
    They are referenced inside the program by and to other data and code.

    Parameters:
        proto_index: Index in the protobuf
        data: Protobuf value of the data.
        program: Program backref

    Attributes:
        proto_index: Index in the protobuf
        address: Data address
        type: Data type
        program: Reference to the Program
        is_initialized: Is the data initialized?
        size: Data size (depends on the type usually)
        name: Data name (if any)
    """

    def __init__(
        self, proto_index: Index, data: "quokka.pb.Quokka.Data", program: quokka.Program
    ):
        """Constructor"""
        self.proto_index: Index = proto_index
        self.address: AddressT = program.addresser.absolute(data.offset)
        self.type: "DataType" = DataType.from_proto(data.type)
        self.program: quokka.Program = program

        self.is_initialized: bool = not data.not_initialized

        self.size: Optional[int] = (
            data.size if data.WhichOneof("DataSize") != "no_size" else None
        )
        self._value: Optional[str] = (
            self.program.proto.string_table[data.value_index]
            if data.value_index > 0
            else None
        )
        self.name: Optional[str] = (
            self.program.proto.string_table[data.name_index]
            if data.name_index > 0
            else None
        )

    def __eq__(self, other: Any) -> bool:
        """Check equality between two Data instances"""
        return type(other) is type(self) and other.proto_index == self.proto_index

    @property
    def value(self) -> Any:
        """Data value.

        The value is read in the program binary file.
        """

        # Uninitialized memory
        if not self.is_initialized:
            return None

        address = self.program.addresser.file(self.address)

        if self.type in (
            DataType.ALIGN,
            DataType.POINTER,
            DataType.STRUCT,
            DataType.UNKNOWN,
        ):
            return self._value

        if self.type == DataType.ASCII:
            try:
                return self.program.executable.read_data(
                    address, self.type, size=self.size
                )
            except quokka.exc.NotInFileError:
                logger.error("Try to read a string which is not in file")
                return ""
        else:
            return self.program.executable.read_data(address, self.type)

    @property
    def references(self) -> List[quokka.Reference]:
        """References to/from this data"""
        return self.program.references.resolve_data(self.proto_index)

    @property
    def code_references(self) -> List[quokka.Reference]:
        """Returns code referencing this Data"""
        return [ref for ref in self.references if isinstance(ref.destination, tuple)]

    @property
    def data_references(self) -> List[quokka.Reference]:
        """Returns data references to/from this Data"""
        return [ref for ref in self.references if isinstance(ref.destination, Data)]

code_references: List[quokka.Reference] property

Returns code referencing this Data

data_references: List[quokka.Reference] property

Returns data references to/from this Data

references: List[quokka.Reference] property

References to/from this data

value: Any property

Data value.

The value is read in the program binary file.

__eq__(other)

Check equality between two Data instances

Source code in quokka/data.py
84
85
86
def __eq__(self, other: Any) -> bool:
    """Check equality between two Data instances"""
    return type(other) is type(self) and other.proto_index == self.proto_index

__init__(proto_index, data, program)

Constructor

Source code in quokka/data.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def __init__(
    self, proto_index: Index, data: "quokka.pb.Quokka.Data", program: quokka.Program
):
    """Constructor"""
    self.proto_index: Index = proto_index
    self.address: AddressT = program.addresser.absolute(data.offset)
    self.type: "DataType" = DataType.from_proto(data.type)
    self.program: quokka.Program = program

    self.is_initialized: bool = not data.not_initialized

    self.size: Optional[int] = (
        data.size if data.WhichOneof("DataSize") != "no_size" else None
    )
    self._value: Optional[str] = (
        self.program.proto.string_table[data.value_index]
        if data.value_index > 0
        else None
    )
    self.name: Optional[str] = (
        self.program.proto.string_table[data.name_index]
        if data.name_index > 0
        else None
    )

DataHolder

Bases: Mapping

Data bucket

All the data of the program are referenced in this bucket and allow to store them only once.

Attributes:

Name Type Description
proto_data

The protobuf data themselves

program Program

A reference to the Program

Parameters:

Name Type Description Default
proto

The protobuf data

required
program Program

The program

required
TODO

Type hinting for proto parameter (RepeatedCompositeFieldContainer)

Source code in quokka/data.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
class DataHolder(Mapping):
    """Data bucket

    All the data of the program are referenced in this bucket and allow to store them
    only once.

    Attributes:
        proto_data: The protobuf data themselves
        program: A reference to the Program

    Arguments:
        proto: The protobuf data
        program: The program

    TODO:
        Type hinting for proto parameter (RepeatedCompositeFieldContainer)
    """

    def __init__(self, proto, program: quokka.Program):
        """Init method

        Arguments:
            proto: List of data in the protobuf
            program: Backref to the program
        """
        self.proto_data = proto.data
        self.program: quokka.Program = program

    def __setitem__(self, key: Index, value: Data) -> None:
        """Set a data"""
        raise ValueError("Should not be accessed")

    def __delitem__(self, value: Index) -> None:
        """Remove a data from the bucket"""
        raise ValueError("Should not be accessed")

    def __getitem__(self, key: Index) -> Data:
        """Get a data from the bucket.

        Arguments:
            key: Data Index

        Returns:
            A Data
        """
        return Data(key, self.proto_data[key], self.program)

    def get_data(self, address: AddressT) -> Data:
        """Find a data by address

        Iterates over the data to find the one at a specified offset

        Arguments:
            address: Offset to query

        Returns:
            A Data

        Raises:
            ValueError: if no data is found
        """

        # We have to iterate over every data because they are not sorted by offset
        for index, data_proto in enumerate(self.proto_data):
            if data_proto.offset + self.program.base_address == address:
                return self[index]

        raise ValueError(f"No data at offset 0x{address:x}")

    def __len__(self) -> int:
        """Number of data in the program"""
        return len(self.proto_data)

    def __iter__(self):
        """Do not allow the iteration over the data"""
        raise ValueError("Should not be accessed")

__delitem__(value)

Remove a data from the bucket

Source code in quokka/data.py
168
169
170
def __delitem__(self, value: Index) -> None:
    """Remove a data from the bucket"""
    raise ValueError("Should not be accessed")

__getitem__(key)

Get a data from the bucket.

Parameters:

Name Type Description Default
key Index

Data Index

required

Returns:

Type Description
Data

A Data

Source code in quokka/data.py
172
173
174
175
176
177
178
179
180
181
def __getitem__(self, key: Index) -> Data:
    """Get a data from the bucket.

    Arguments:
        key: Data Index

    Returns:
        A Data
    """
    return Data(key, self.proto_data[key], self.program)

__init__(proto, program)

Init method

Parameters:

Name Type Description Default
proto

List of data in the protobuf

required
program Program

Backref to the program

required
Source code in quokka/data.py
154
155
156
157
158
159
160
161
162
def __init__(self, proto, program: quokka.Program):
    """Init method

    Arguments:
        proto: List of data in the protobuf
        program: Backref to the program
    """
    self.proto_data = proto.data
    self.program: quokka.Program = program

__iter__()

Do not allow the iteration over the data

Source code in quokka/data.py
209
210
211
def __iter__(self):
    """Do not allow the iteration over the data"""
    raise ValueError("Should not be accessed")

__len__()

Number of data in the program

Source code in quokka/data.py
205
206
207
def __len__(self) -> int:
    """Number of data in the program"""
    return len(self.proto_data)

__setitem__(key, value)

Set a data

Source code in quokka/data.py
164
165
166
def __setitem__(self, key: Index, value: Data) -> None:
    """Set a data"""
    raise ValueError("Should not be accessed")

get_data(address)

Find a data by address

Iterates over the data to find the one at a specified offset

Parameters:

Name Type Description Default
address AddressT

Offset to query

required

Returns:

Type Description
Data

A Data

Raises:

Type Description
ValueError

if no data is found

Source code in quokka/data.py
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
def get_data(self, address: AddressT) -> Data:
    """Find a data by address

    Iterates over the data to find the one at a specified offset

    Arguments:
        address: Offset to query

    Returns:
        A Data

    Raises:
        ValueError: if no data is found
    """

    # We have to iterate over every data because they are not sorted by offset
    for index, data_proto in enumerate(self.proto_data):
        if data_proto.offset + self.program.base_address == address:
            return self[index]

    raise ValueError(f"No data at offset 0x{address:x}")