blob: a2c9edbe356c465fbaaed47d0a4f77b0747ee256 [file] [log] [blame]
Eli Benderskye0735d52011-09-08 20:12:44 +03001#-------------------------------------------------------------------------------
2# elftools: common/utils.py
3#
4# Miscellaneous utilities for elftools
5#
6# Eli Bendersky (eliben@gmail.com)
7# This code is in the public domain
8#-------------------------------------------------------------------------------
Eli Benderskyc2074312011-12-17 14:48:42 +02009from contextlib import contextmanager
eliben033b44f2011-09-19 15:48:39 +030010from .exceptions import ELFParseError, ELFError, DWARFError
Eli Bendersky79271e92012-01-27 10:25:47 +020011from .py3compat import int2byte
elibena7c25472011-09-18 17:31:10 +030012from ..construct import ConstructError
Eli Benderskye0735d52011-09-08 20:12:44 +030013
14
Eli Benderskyebe51162011-10-27 17:34:02 +020015def bytelist2string(bytelist):
Eli Bendersky79271e92012-01-27 10:25:47 +020016 """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a bytes object
17 (e.g. b'\x10\x20\x00').
Eli Benderskyebe51162011-10-27 17:34:02 +020018 """
Eli Bendersky79271e92012-01-27 10:25:47 +020019 return b''.join(int2byte(b) for b in bytelist)
Eli Benderskyebe51162011-10-27 17:34:02 +020020
21
Eli Benderskye0735d52011-09-08 20:12:44 +030022def struct_parse(struct, stream, stream_pos=None):
Eli Bendersky3f4de3e2011-09-14 05:58:06 +030023 """ Convenience function for using the given struct to parse a stream.
Eli Benderskye0735d52011-09-08 20:12:44 +030024 If stream_pos is provided, the stream is seeked to this position before
Eli Bendersky3f4de3e2011-09-14 05:58:06 +030025 the parsing is done. Otherwise, the current position of the stream is
26 used.
27 Wraps the error thrown by construct with ELFParseError.
Eli Benderskye0735d52011-09-08 20:12:44 +030028 """
29 try:
30 if stream_pos is not None:
31 stream.seek(stream_pos)
32 return struct.parse_stream(stream)
33 except ConstructError as e:
Martin Panter8586ac12012-12-06 00:00:00 +000034 raise ELFParseError(str(e))
Eli Bendersky89b280a2014-01-18 06:24:23 -080035
Eli Benderskye0735d52011-09-08 20:12:44 +030036
Eli Bendersky4a489752011-11-27 06:34:47 +020037def parse_cstring_from_stream(stream, stream_pos=None):
38 """ Parse a C-string from the given stream. The string is returned without
Eli Benderskya1d61402011-11-28 06:25:52 +020039 the terminating \x00 byte. If the terminating byte wasn't found, None
40 is returned (the stream is exhausted).
Eli Bendersky4a489752011-11-27 06:34:47 +020041 If stream_pos is provided, the stream is seeked to this position before
42 the parsing is done. Otherwise, the current position of the stream is
43 used.
Eli Benderskyccdb5542013-03-31 14:19:21 -070044 Note: a bytes object is returned here, because this is what's read from
45 the binary file.
Eli Bendersky4a489752011-11-27 06:34:47 +020046 """
Eli Bendersky4a489752011-11-27 06:34:47 +020047 if stream_pos is not None:
48 stream.seek(stream_pos)
Eli Benderskya1d61402011-11-28 06:25:52 +020049 CHUNKSIZE = 64
50 chunks = []
51 found = False
52 while True:
53 chunk = stream.read(CHUNKSIZE)
Eli Bendersky79271e92012-01-27 10:25:47 +020054 end_index = chunk.find(b'\x00')
Eli Benderskya1d61402011-11-28 06:25:52 +020055 if end_index >= 0:
56 chunks.append(chunk[:end_index])
57 found = True
58 break
59 else:
60 chunks.append(chunk)
61 if len(chunk) < CHUNKSIZE:
62 break
Eli Bendersky79271e92012-01-27 10:25:47 +020063 return b''.join(chunks) if found else None
Eli Bendersky4a489752011-11-27 06:34:47 +020064
65
eliben116899e2011-09-08 17:15:53 +030066def elf_assert(cond, msg=''):
Eli Benderskye0735d52011-09-08 20:12:44 +030067 """ Assert that cond is True, otherwise raise ELFError(msg)
68 """
eliben44556512011-09-19 12:54:32 +030069 _assert_with_exception(cond, msg, ELFError)
Eli Benderskye0735d52011-09-08 20:12:44 +030070
eliben44556512011-09-19 12:54:32 +030071
72def dwarf_assert(cond, msg=''):
73 """ Assert that cond is True, otherwise raise DWARFError(msg)
74 """
75 _assert_with_exception(cond, msg, DWARFError)
76
77
eliben3b9ad822011-09-22 11:46:26 +030078@contextmanager
79def preserve_stream_pos(stream):
80 """ Usage:
Eli Bendersky89b280a2014-01-18 06:24:23 -080081 # stream has some position FOO (return value of stream.tell())
82 with preserve_stream_pos(stream):
83 # do stuff that manipulates the stream
84 # stream still has position FOO
eliben3b9ad822011-09-22 11:46:26 +030085 """
86 saved_pos = stream.tell()
87 yield
88 stream.seek(saved_pos)
Eli Benderskya1d61402011-11-28 06:25:52 +020089
Eli Benderskyc2074312011-12-17 14:48:42 +020090
91#------------------------- PRIVATE -------------------------
92
93def _assert_with_exception(cond, msg, exception_type):
94 if not cond:
95 raise exception_type(msg)
96