blob: e0a4cfef6e8d8a9298ccb7dfbd669adf867d7bcd [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
elibena7c25472011-09-18 17:31:10 +030011from ..construct import ConstructError
Eli Benderskye0735d52011-09-08 20:12:44 +030012
13
Eli Benderskyebe51162011-10-27 17:34:02 +020014def bytelist2string(bytelist):
15 """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a string
16 (e.g. '\x10\x20\x00').
17 """
18 return ''.join(chr(b) for b in bytelist)
19
20
Eli Benderskye0735d52011-09-08 20:12:44 +030021def struct_parse(struct, stream, stream_pos=None):
Eli Bendersky3f4de3e2011-09-14 05:58:06 +030022 """ Convenience function for using the given struct to parse a stream.
Eli Benderskye0735d52011-09-08 20:12:44 +030023 If stream_pos is provided, the stream is seeked to this position before
Eli Bendersky3f4de3e2011-09-14 05:58:06 +030024 the parsing is done. Otherwise, the current position of the stream is
25 used.
26 Wraps the error thrown by construct with ELFParseError.
Eli Benderskye0735d52011-09-08 20:12:44 +030027 """
28 try:
29 if stream_pos is not None:
30 stream.seek(stream_pos)
31 return struct.parse_stream(stream)
32 except ConstructError as e:
33 raise ELFParseError(e.message)
34
35
Eli Bendersky4a489752011-11-27 06:34:47 +020036def parse_cstring_from_stream(stream, stream_pos=None):
37 """ Parse a C-string from the given stream. The string is returned without
Eli Benderskya1d61402011-11-28 06:25:52 +020038 the terminating \x00 byte. If the terminating byte wasn't found, None
39 is returned (the stream is exhausted).
Eli Bendersky4a489752011-11-27 06:34:47 +020040 If stream_pos is provided, the stream is seeked to this position before
41 the parsing is done. Otherwise, the current position of the stream is
42 used.
43 """
Eli Bendersky4a489752011-11-27 06:34:47 +020044 if stream_pos is not None:
45 stream.seek(stream_pos)
Eli Benderskya1d61402011-11-28 06:25:52 +020046 CHUNKSIZE = 64
47 chunks = []
48 found = False
49 while True:
50 chunk = stream.read(CHUNKSIZE)
51 end_index = chunk.find('\x00')
52 if end_index >= 0:
53 chunks.append(chunk[:end_index])
54 found = True
55 break
56 else:
57 chunks.append(chunk)
58 if len(chunk) < CHUNKSIZE:
59 break
60 return ''.join(chunks) if found else None
Eli Bendersky4a489752011-11-27 06:34:47 +020061
62
eliben116899e2011-09-08 17:15:53 +030063def elf_assert(cond, msg=''):
Eli Benderskye0735d52011-09-08 20:12:44 +030064 """ Assert that cond is True, otherwise raise ELFError(msg)
65 """
eliben44556512011-09-19 12:54:32 +030066 _assert_with_exception(cond, msg, ELFError)
Eli Benderskye0735d52011-09-08 20:12:44 +030067
eliben44556512011-09-19 12:54:32 +030068
69def dwarf_assert(cond, msg=''):
70 """ Assert that cond is True, otherwise raise DWARFError(msg)
71 """
72 _assert_with_exception(cond, msg, DWARFError)
73
74
eliben3b9ad822011-09-22 11:46:26 +030075@contextmanager
76def preserve_stream_pos(stream):
77 """ Usage:
78
79 # stream has some position FOO (return value of stream.tell())
80 with preserve_stream_pos(stream):
81 # do stuff that manipulates the stream
82 # stream still has position FOO
83 """
84 saved_pos = stream.tell()
85 yield
86 stream.seek(saved_pos)
Eli Benderskya1d61402011-11-28 06:25:52 +020087
Eli Benderskyc2074312011-12-17 14:48:42 +020088
89#------------------------- PRIVATE -------------------------
90
91def _assert_with_exception(cond, msg, exception_type):
92 if not cond:
93 raise exception_type(msg)
94