utils.py
ofrak_patch_maker.toolchain.utils
get_repository_config(section, key=None)
Get config values from toolchain.conf.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
section |
str |
section name in config file |
required |
key |
Optional[str] |
key in |
None |
Returns:
Type | Description |
---|---|
the result of |
Exceptions:
Type | Description |
---|---|
SystemExit |
If |
Source code in ofrak_patch_maker/toolchain/utils.py
def get_repository_config(section: str, key: Optional[str] = None):
"""
Get config values from toolchain.conf.
:param section: section name in config file
:param key: key in `config[section]`
:raises SystemExit: If `config[section]` or `config[section][key]` not found.
:return Union[str, List[Tuple[str, str]]]: the result of ``config.get(section, key)`` or
``config.items(section)``
"""
config = configparser.RawConfigParser()
config_name = "toolchain.conf"
local_config = os.path.join(os.path.dirname(__file__), os.path.pardir)
config_paths = [local_config]
error_by_config_file: Dict[str, Exception] = dict()
for p in config_paths:
conf = os.path.join(p, config_name)
if not os.path.exists(conf):
continue
try:
config.read(conf)
if key:
ret = config.get(section, key)
else:
ret = config.items(section) # type: ignore
return ret
except (configparser.NoSectionError, configparser.NoOptionError) as e:
error_by_config_file[conf] = e
continue
if 0 == len(error_by_config_file):
raise NotFoundError(f"Configuration file {config_name} not found")
elif 1 == len(error_by_config_file):
_config, _e = next(iter(error_by_config_file.items()))
raise NotFoundError(f"Section or option not found in {_config}", _e)
else:
raise NotFoundError(
f"Section {section:s} or option {key:s} not found in any of the configs searched: "
f"{error_by_config_file}"
)
generate_arm_stubs(func_names, out_dir, thumb=False)
Utility function to generate assembly stubs. This is necessary when function calls need to switch between ARM and thumb mode (when code generated by the PatchMaker is ARM and needs to jump to thumb code, or the opposite). With those stubs, the linker has explicit information about the destination mode, so it jumps correctly (exchanging mode or not).
It is not PatchMaker's responsibility to programmatically generate source in this way.
Furthermore, this functionality is much more complex than base_symbols={}
addition implies,
as actual object files are generated and linked against.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
func_names |
Mapping[str, int] |
names to effective address |
required |
out_dir |
str |
object file output directory |
required |
thumb |
bool |
Whether or not to generate thumb stubs |
False |
Returns:
Type | Description |
---|---|
Mapping[str, Tuple[ofrak_patch_maker.toolchain.model.Segment, ofrak_patch_maker.toolchain.model.Segment]] |
maps object file to dummy |
Source code in ofrak_patch_maker/toolchain/utils.py
def generate_arm_stubs(
func_names: Mapping[str, int], out_dir: str, thumb: bool = False
) -> Mapping[str, Tuple[Segment, Segment]]:
"""
Utility function to generate assembly stubs. This is necessary when function calls need to
switch between ARM and thumb mode (when code generated by the PatchMaker is ARM and needs to
jump to thumb code, or the opposite). With those stubs, the linker has explicit information
about the destination mode, so it jumps correctly (exchanging mode or not).
It is not [PatchMaker][ofrak_patch_maker.patch_maker.PatchMaker]'s responsibility to
programmatically generate source in this way.
Furthermore, this functionality is much more complex than `base_symbols={}` addition implies,
as actual object files are generated and linked against.
:param func_names: names to effective address
:param out_dir: object file output directory
:param thumb: Whether or not to generate thumb stubs
:return Dict[str, Tuple[Segment, Segment]: maps object file to dummy
`[text_segment, data segment]`
"""
print(f"Generating ARM stubs...")
names = list(func_names.keys())
addresses = list(func_names.values())
out_dirs = [out_dir] * len(names)
if thumb:
stub_strs = [".thumb_func"] * len(names)
else:
stub_strs = [f".type {name}, %function" for name in names]
args = zip(names, addresses, stub_strs, out_dirs)
workers = math.ceil(0.6 * cpu_count())
with Pool(processes=workers) as pool:
result = pool.starmap(_gen_file, args, chunksize=math.ceil(len(names) / workers))
segment_map: Dict[str, Tuple[Segment, Segment]] = {}
for r in result:
segment_map.update(r)
print(list(r.keys()))
return segment_map