| 18 | |
| 19 | |
| 20 | class QlOsUtils: |
| 21 | ELLIPSIS_PREF = r'__qlva_' |
| 22 | |
| 23 | def __init__(self, ql: Qiling): |
| 24 | self.ql = ql |
| 25 | |
| 26 | @staticmethod |
| 27 | def as_signed(value: int, nbits: int) -> int: |
| 28 | """Transform an unsigned integer value into its 2's complement signed value |
| 29 | equivalent. This method has no effect on signed integers. |
| 30 | |
| 31 | Args: |
| 32 | value: an unsigned integer to transform |
| 33 | nbits: value bit size |
| 34 | |
| 35 | Returns: a signed integer |
| 36 | """ |
| 37 | |
| 38 | # truncate value to specified bit size |
| 39 | value &= (1 << nbits) - 1 |
| 40 | |
| 41 | msb = 1 << (nbits - 1) |
| 42 | |
| 43 | return -(value & ~(msb - 1)) | value |
| 44 | |
| 45 | def read_string(self, address: int, encoding: str, maxlen: int = 0) -> str: |
| 46 | """Read a null-terminated string from memory. |
| 47 | |
| 48 | Args: |
| 49 | address : starting address |
| 50 | encoding: string encoding to use |
| 51 | maxlen : limit number of characters to read before reaching null terminator, |
| 52 | 0 for unlimited length |
| 53 | |
| 54 | Returns: decoded string |
| 55 | """ |
| 56 | |
| 57 | terminator = '\x00'.encode(encoding) |
| 58 | |
| 59 | data = bytearray() |
| 60 | charlen = len(terminator) |
| 61 | strlen = 0 |
| 62 | |
| 63 | while True: |
| 64 | char = self.ql.mem.read(address, charlen) |
| 65 | |
| 66 | if char == terminator: |
| 67 | break |
| 68 | |
| 69 | data += char |
| 70 | strlen += 1 |
| 71 | |
| 72 | if strlen == maxlen: |
| 73 | break |
| 74 | |
| 75 | address += charlen |
| 76 | |
| 77 | s = data.decode(encoding, errors='backslashreplace') |