Source code for libdebug.utils.debugging_utils

#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2023-2024 Gabriele Digregorio, Roberto Alessandro Bertolini. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

from libdebug.data.memory_map import MemoryMap
from libdebug.liblog import liblog
from libdebug.utils.elf_utils import is_pie, resolve_address, resolve_symbol


[docs] def check_absolute_address(address: int, maps: list[MemoryMap]) -> bool: """Checks if the specified address is an absolute address. Returns: bool: True if the specified address is an absolute address, False otherwise. """ return any(vmap.start <= address < vmap.end for vmap in maps)
[docs] def normalize_and_validate_address(address: int, maps: list[MemoryMap]) -> int: """Normalizes and validates the specified address. Returns: int: The normalized address. Throws: ValueError: If the specified address does not belong to any memory map. """ if address < maps[0].start: # The address is lower than the base address of the lowest map. Suppose it is a relative address for a PIE binary. address += maps[0].start for vmap in maps: if vmap.start <= address < vmap.end: return address raise ValueError(f"Address {hex(address)} does not belong to any memory map.")
[docs] def resolve_symbol_in_maps(symbol: str, maps: list[MemoryMap]) -> int: """Returns the address of the specified symbol in the specified memory maps. Args: symbol (str): The symbol whose address should be returned. maps (list[MemoryMap]): The memory maps. Returns: int: The address of the specified symbol in the specified memory maps. Throws: ValueError: If the specified symbol does not belong to any memory map. """ mapped_files = {} if "+" in symbol: symbol, offset_str = symbol.split("+") offset = int(offset_str, 16) else: offset = 0 for vmap in maps: if vmap.backing_file and vmap.backing_file not in mapped_files and vmap.backing_file[0] != "[": mapped_files[vmap.backing_file] = vmap.start for file, base_address in mapped_files.items(): try: address = resolve_symbol(file, symbol) if is_pie(file): address += base_address return address + offset except OSError as e: liblog.debugger(f"Error while resolving symbol {symbol} in {file}: {e}") except ValueError: pass raise ValueError(f"Symbol {symbol} not found in the specified mapped file. Please specify a valid symbol.")
[docs] def resolve_address_in_maps(address: int, maps: list[MemoryMap]) -> str: """Returns the symbol corresponding to the specified address in the specified memory maps. Args: address (int): The address whose symbol should be returned. maps (list[MemoryMap]): The memory maps. Returns: str: The symbol corresponding to the specified address in the specified memory maps. Throws: ValueError: If the specified address does not belong to any memory map. """ mapped_files = {} for vmap in maps: file = vmap.backing_file if not file or file[0] == "[": continue if file not in mapped_files: mapped_files[file] = (vmap.start, vmap.end) else: mapped_files[file] = (mapped_files[file][0], vmap.end) for file, (base_address, top_address) in mapped_files.items(): # Check if the address is in the range of the current section if address < base_address or address >= top_address: continue try: return resolve_address(file, address - base_address) if is_pie(file) else resolve_address(file, address) except OSError as e: liblog.debugger(f"Error while resolving address {hex(address)} in {file}: {e}") except ValueError: pass return hex(address)