1
2class Region:
3    """
4    A region of memory that is mapped in the object's file.
5
6    :ivar offset:       The offset into the file the region starts.
7    :ivar vaddr:        The virtual address.
8    :ivar filesize:     The size of the region in the file.
9    :ivar memsize:      The size of the region when loaded into memory.
10
11    The prefix `v-` on a variable or parameter name indicates that it refers to the virtual, loaded memory space,
12    while a corresponding variable without the `v-` refers to the flat zero-based memory of the file.
13
14    When used next to each other, `addr` and `offset` refer to virtual memory address and file offset, respectively.
15    """
16
17    vaddr: int
18    memsize: int
19    filesize: int
20
21    def __init__(self, offset, vaddr, filesize, memsize):
22        self.vaddr = vaddr
23        self.memsize = memsize
24        self.filesize = filesize
25        self.offset = offset
26
27    def _rebase(self, delta):
28        """
29        Does region rebasing to other base address.
30        Intended for usage by loader's add_object to reflect the rebasing.
31
32        :param int delta: Delta offset between an old and a new image bases
33        """
34        self.vaddr += delta
35
36    def contains_addr(self, addr):
37        """
38        Does this region contain this virtual address?
39        """
40        return self.vaddr <= addr < self.vaddr + self.memsize
41
42    def contains_offset(self, offset):
43        """
44        Does this region contain this offset into the file?
45        """
46        return self.offset <= offset < self.offset + self.filesize
47
48    def addr_to_offset(self, addr):
49        """
50        Convert a virtual memory address into a file offset
51        """
52        offset = addr - self.vaddr + self.offset
53        if not self.contains_offset(offset):
54            return None
55        return offset
56
57    def offset_to_addr(self, offset):
58        """
59        Convert a file offset into a virtual memory address
60        """
61        addr = offset - self.offset + self.vaddr
62        if not self.contains_addr(addr):
63            return None
64        return addr
65
66    def __repr__(self):
67        return '<{} {}>'.format(self.__class__.__name__, ', '.join(['{}=0x{:x}'.format(k, v) for k, v in self.__dict__.items()]))
68
69    @property
70    def max_addr(self):
71        """
72        The maximum virtual address of this region
73        """
74        return self.vaddr + self.memsize - 1
75
76    @property
77    def min_addr(self):
78        """
79        The minimum virtual address of this region
80        """
81        return self.vaddr
82
83    @property
84    def max_offset(self):
85        """
86        The maximum file offset of this region
87        """
88        return self.offset + self.filesize - 1
89
90    def min_offset(self):
91        """
92        The minimum file offset of this region
93        """
94        return self.offset
95
96    # EDG says: Blobs now have segments, and SimOS will get upset if these don't exist.  See simos.py line 107 for
97    # some code you should probably fix if you don't like it.
98    def is_readable(self):
99        # pylint: disable=no-self-use
100        return True
101
102    def is_writable(self):
103        # pylint: disable=no-self-use
104        return True
105
106    def is_executable(self):
107        # pylint: disable=no-self-use
108        return True
109
110class Segment(Region):
111    pass
112
113
114class EmptySegment(Segment):
115    """
116    A segment with no static content, and permissions
117    """
118
119    def __init__(self, vaddr, memsize, is_readable=True, is_writable=True, is_executable=False):
120        super().__init__(0, vaddr, 0, memsize)
121        self._is_readable = is_readable
122        self._is_writable = is_writable
123        self._is_executable = is_executable
124
125    @property
126    def is_executable(self):
127        return self._is_executable
128
129    @property
130    def is_writable(self):
131        return self._is_writable
132
133    @property
134    def is_readable(self):
135        return self._is_readable
136
137    @property
138    def only_contains_uninitialized_data(self):
139        """
140        Whether this section is initialized to zero after the executable is loaded.
141        """
142        return True
143
144
145class Section(Region):
146    """
147    Simple representation of a loaded section.
148
149    :ivar str name:     The name of the section
150    """
151    def __init__(self, name, offset, vaddr, size):
152        """
153        :param str name:    The name of the section
154        :param int offset:  The offset into the binary file this section begins
155        :param int vaddr:   The address in virtual memory this section begins
156        :param int size:    How large this section is
157        """
158        super().__init__(offset, vaddr, size, size)
159        self.name = name
160
161    @property
162    def is_readable(self):
163        """
164        Whether this section has read permissions
165        """
166        raise NotImplementedError()
167
168    @property
169    def is_writable(self):
170        """
171        Whether this section has write permissions
172        """
173        raise NotImplementedError()
174
175    @property
176    def is_executable(self):
177        """
178        Whether this section has execute permissions
179        """
180        raise NotImplementedError()
181
182    @property
183    def only_contains_uninitialized_data(self):
184        """
185        Whether this section is initialized to zero after the executable is loaded.
186        """
187        raise NotImplementedError()
188
189    def __repr__(self):
190        return "<%s | offset %#x, vaddr %#x, size %#x>" % (
191            self.name if self.name else "Unnamed",
192            self.offset,
193            self.vaddr,
194            self.memsize
195        )
196