diff --git a/src/Command/Inspector/MemoryCommand.php b/src/Command/Inspector/MemoryCommand.php index 869dbd2f..d150b61b 100644 --- a/src/Command/Inspector/MemoryCommand.php +++ b/src/Command/Inspector/MemoryCommand.php @@ -13,6 +13,7 @@ namespace Reli\Command\Inspector; +use Reli\Inspector\RetryingLoopProvider; use Reli\Inspector\Settings\MemoryProfilerSettings\MemoryProfilerSettingsFromConsoleInput; use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettingsFromConsoleInput; use Reli\Inspector\Settings\TargetProcessSettings\TargetProcessSettingsFromConsoleInput; @@ -72,11 +73,6 @@ public function execute(InputInterface $input, OutputInterface $output): int $target_php_settings ); - if ($memory_profiler_settings->stop_process) { - $this->process_stopper->stop($process_specifier->pid); - defer($scope_guard, fn () => $this->process_stopper->resume($process_specifier->pid)); - } - $eg_address = $this->php_globals_finder->findExecutorGlobals( $process_specifier, $target_php_settings_version_decided @@ -86,6 +82,11 @@ public function execute(InputInterface $input, OutputInterface $output): int $target_php_settings_version_decided ); + if ($memory_profiler_settings->stop_process) { + $this->process_stopper->stop($process_specifier->pid); + defer($scope_guard, fn () => $this->process_stopper->resume($process_specifier->pid)); + } + $collected_memories = $this->memory_locations_collector->collectAll( $process_specifier, $target_php_settings_version_decided, diff --git a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettings.php b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettings.php index 3f1d667d..e6f1bc5e 100644 --- a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettings.php +++ b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettings.php @@ -23,12 +23,14 @@ final class TargetPhpSettings { public const PHP_REGEX_DEFAULT = '.*/((php|php-fpm)(7\.?[01234]|8\.?[0123])?|libphp[78]?.*\.so)$'; public const LIBPTHREAD_REGEX_DEFAULT = '.*/libpthread.*\.so'; + public const ZTS_GLOBALS_REGEX_DEFAULT = self::PHP_REGEX_DEFAULT; public const TARGET_PHP_VERSION_DEFAULT = 'auto'; /** @param TVersion $php_version */ public function __construct( public string $php_regex = self::PHP_REGEX_DEFAULT, public string $libpthread_regex = self::LIBPTHREAD_REGEX_DEFAULT, + public string $zts_globals_regex = self::ZTS_GLOBALS_REGEX_DEFAULT, public string $php_version = self::TARGET_PHP_VERSION_DEFAULT, public ?string $php_path = null, public ?string $libpthread_path = null diff --git a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsException.php b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsException.php index bd3212cc..a0c5a264 100644 --- a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsException.php +++ b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsException.php @@ -19,13 +19,15 @@ final class TargetPhpSettingsException extends InspectorSettingsException { public const PHP_REGEX_IS_NOT_STRING = 3; public const LIBPTHREAD_REGEX_IS_NOT_STRING = 4; - public const PHP_PATH_IS_NOT_STRING = 5; - public const LIBPTHREAD_PATH_IS_NOT_STRING = 6; - public const TARGET_PHP_VERSION_INVALID = 7; + public const ZTS_GLOBALS_REGEX_IS_NOT_STRING = 5; + public const PHP_PATH_IS_NOT_STRING = 6; + public const LIBPTHREAD_PATH_IS_NOT_STRING = 7; + public const TARGET_PHP_VERSION_INVALID = 8; protected const ERRORS = [ self::PHP_REGEX_IS_NOT_STRING => 'php-regex must be a string', self::LIBPTHREAD_REGEX_IS_NOT_STRING => 'libpthread-regex must be a string', + self::ZTS_GLOBALS_REGEX_IS_NOT_STRING => 'zts-globals-regex must be a string', self::PHP_PATH_IS_NOT_STRING => 'php-path must be a string', self::LIBPTHREAD_PATH_IS_NOT_STRING => 'libpthread-path must be a string', self::TARGET_PHP_VERSION_INVALID => 'php-version must be valid version string (eg: v80)', diff --git a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInput.php b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInput.php index 0777e888..7fcd77ab 100644 --- a/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInput.php +++ b/src/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInput.php @@ -40,6 +40,12 @@ public function setOptions(Command $command): void InputOption::VALUE_OPTIONAL, 'regex to find the libpthread.so loaded in the target process' ) + ->addOption( + 'zts-globals-regex', + null, + InputOption::VALUE_OPTIONAL, + 'regex to find the binary containing globals symbols for ZTS loaded in the target process' + ) ->addOption( 'php-version', null, @@ -77,6 +83,13 @@ public function createSettings(InputInterface $input): TargetPhpSettings ); } + $zts_globals_regex = $input->getOption('zts-globals-regex') ?? $php_regex; + if (!is_string($zts_globals_regex)) { + throw TargetPhpSettingsException::create( + TargetPhpSettingsException::ZTS_GLOBALS_REGEX_IS_NOT_STRING + ); + } + $php_version = $input->getOption('php-version') ?? TargetPhpSettings::TARGET_PHP_VERSION_DEFAULT; if ($php_version !== 'auto' and !in_array($php_version, ZendTypeReader::ALL_SUPPORTED_VERSIONS, true)) { throw TargetPhpSettingsException::create( @@ -98,6 +111,13 @@ public function createSettings(InputInterface $input): TargetPhpSettings ); } - return new TargetPhpSettings($php_regex, $libpthread_regex, $php_version, $php_path, $libpthread_path); + return new TargetPhpSettings( + $php_regex, + $libpthread_regex, + $zts_globals_regex, + $php_version, + $php_path, + $libpthread_path + ); } } diff --git a/src/Lib/Elf/Parser/Elf64Parser.php b/src/Lib/Elf/Parser/Elf64Parser.php index 06225f28..62e7d67d 100644 --- a/src/Lib/Elf/Parser/Elf64Parser.php +++ b/src/Lib/Elf/Parser/Elf64Parser.php @@ -26,6 +26,7 @@ use Reli\Lib\Elf\Structure\Elf64\Elf64StringTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; +use Reli\Lib\Integer\UInt64; final class Elf64Parser { @@ -111,16 +112,19 @@ public function parseProgramHeader(ByteReaderInterface $data, Elf64Header $elf_h public function parseDynamicStructureArray( ByteReaderInterface $data, - Elf64ProgramHeaderEntry $pt_dynamic + UInt64 $dynamic_offset, + UInt64 $dynamic_v_addr, ): Elf64DynamicStructureArray { $dynamic_array = []; - $offset = $pt_dynamic->p_offset->lo; + $offset = $dynamic_offset->toInt(); + $v_addr = $dynamic_v_addr->toInt(); do { $d_tag = $this->integer_reader->read64($data, $offset); $d_un = $this->integer_reader->read64($data, $offset + 8); - $dynamic_structure = new Elf64DynamicStructure($d_tag, $d_un); + $dynamic_structure = new Elf64DynamicStructure($offset, $v_addr, $d_tag, $d_un); $dynamic_array[] = $dynamic_structure; $offset += 16; + $v_addr += 16; } while (!$dynamic_structure->isEnd()); return new Elf64DynamicStructureArray(...$dynamic_array); @@ -128,6 +132,7 @@ public function parseDynamicStructureArray( public function parseStringTable( ByteReaderInterface $data, + UInt64 $base_address, Elf64DynamicStructureArray $dynamic_structure_array ): Elf64StringTable { /** @@ -138,7 +143,7 @@ public function parseStringTable( Elf64DynamicStructure::DT_STRTAB => $dt_strtab, Elf64DynamicStructure::DT_STRSZ => $dt_strsz ] = $dynamic_structure_array->findStringTableEntries(); - $offset = $dt_strtab->d_un->toInt(); + $offset = $dt_strtab->d_un->toInt() - $base_address->toInt(); $size = $dt_strsz->d_un->toInt(); $string_table_region = $data->createSliceAsString($offset, $size); @@ -159,6 +164,7 @@ public function parseStringTableFromSectionHeader( public function parseSymbolTableFromDynamic( ByteReaderInterface $data, + UInt64 $base_address, Elf64DynamicStructureArray $dynamic_structure_array, int $number_of_symbols ): Elf64SymbolTable { @@ -171,7 +177,7 @@ public function parseSymbolTableFromDynamic( Elf64DynamicStructure::DT_SYMENT => $dt_syment ] = $dynamic_structure_array->findSymbolTablEntries(); - $start_offset = $dt_symtab->d_un->toInt(); + $start_offset = $dt_symtab->d_un->toInt() - $base_address->toInt(); $entry_size = $dt_syment->d_un->toInt(); return $this->parseSymbolTable($data, $start_offset, $number_of_symbols, $entry_size); @@ -223,13 +229,14 @@ public function parseSymbolTable( */ public function parseGnuHashTable( ByteReaderInterface $data, + Uint64 $base_address, Elf64DynamicStructureArray $dynamic_structure_array ): ?Elf64GnuHashTable { $dt_gnu_hash = $dynamic_structure_array->findGnuHashTableEntry(); if (is_null($dt_gnu_hash)) { return null; } - $offset = $dt_gnu_hash->d_un->toInt(); + $offset = $dt_gnu_hash->d_un->toInt() - $base_address->toInt(); $nbuckets = $this->integer_reader->read32($data, $offset); $symoffset = $this->integer_reader->read32($data, $offset + 4); $bloom_size = $this->integer_reader->read32($data, $offset + 8); diff --git a/src/Lib/Elf/Process/Elf64LazyParseSymbolResolver.php b/src/Lib/Elf/Process/Elf64LazyParseSymbolResolver.php index 34a62e4a..6b931bd2 100644 --- a/src/Lib/Elf/Process/Elf64LazyParseSymbolResolver.php +++ b/src/Lib/Elf/Process/Elf64LazyParseSymbolResolver.php @@ -17,6 +17,7 @@ use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolver; use Reli\Lib\Elf\SymbolResolver\SymbolResolverCreatorInterface; +use Reli\Lib\Integer\UInt64; use Reli\Lib\Process\MemoryMap\ProcessModuleMemoryMap; use Reli\Lib\Process\MemoryReader\MemoryReaderInterface; @@ -57,4 +58,20 @@ public function resolve(string $symbol_name): Elf64SymbolTableEntry } return $this->resolver_cache->resolve($symbol_name); } + + public function getDtDebugAddress(): ?int + { + if (!isset($this->resolver_cache)) { + $this->resolver_cache = $this->loadResolver(); + } + return $this->resolver_cache->getDtDebugAddress(); + } + + public function getBaseAddress(): UInt64 + { + if (!isset($this->resolver_cache)) { + $this->resolver_cache = $this->loadResolver(); + } + return $this->resolver_cache->getBaseAddress(); + } } diff --git a/src/Lib/Elf/Process/LinkMap.php b/src/Lib/Elf/Process/LinkMap.php new file mode 100644 index 00000000..8e5c138e --- /dev/null +++ b/src/Lib/Elf/Process/LinkMap.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Reli\Lib\Elf\Process; + +final class LinkMap +{ + public function __construct( + public int $this_address, + public int $l_addr, + public string $l_name, + public int $l_ld, + public int $l_next_address, + public int $l_prev_address, + ) { + } +} diff --git a/src/Lib/Elf/Process/LinkMapLoader.php b/src/Lib/Elf/Process/LinkMapLoader.php new file mode 100644 index 00000000..be4be2b9 --- /dev/null +++ b/src/Lib/Elf/Process/LinkMapLoader.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Reli\Lib\Elf\Process; + +use Reli\Lib\ByteStream\CDataByteReader; +use Reli\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader; +use Reli\Lib\Process\MemoryReader\MemoryReaderInterface; + +class LinkMapLoader +{ + public function __construct( + private MemoryReaderInterface $memory_reader, + private IntegerByteSequenceReader $integer_reader, + ) { + } + + public function loadFromAddress(int $pid, int $address): LinkMap + { + $bytes = new CDataByteReader($this->memory_reader->read($pid, $address, $this->getSize())); + $l_addr = $this->integer_reader->read64($bytes, 0); + $l_name_address = $this->integer_reader->read64($bytes, 8); + $l_ld = $this->integer_reader->read64($bytes, 16); + $l_next_address = $this->integer_reader->read64($bytes, 24); + $l_prev_address = $this->integer_reader->read64($bytes, 32); + + return new LinkMap( + $address, + $l_addr->toInt(), + $this->readCString($pid, $l_name_address->toInt()), + $l_ld->toInt(), + $l_next_address->toInt(), + $l_prev_address->toInt() + ); + } + + public function searchByName(string $name, int $pid, int $root_address): ?LinkMap + { + $address = $root_address; + do { + $link_map = $this->loadFromAddress($pid, $address); + if ($link_map->l_name === $name) { + return $link_map; + } + $address = $link_map->l_next_address; + } while ($address !== 0); + return null; + } + + private function getSize(): int + { + return 8 // l_addr + + 8 // l_name + + 8 // l_ld + + 8 // l_next + + 8 // l_prev + ; + } + + private function readCString(int $pid, int $address): string + { + $bytes = $this->memory_reader->read($pid, $address, 1); + $str = ''; + while (true) { + /** @var int $c */ + $c = $bytes[0]; + if ($c === 0) { + break; + } + $str .= chr($c); + $address += 1; + $bytes = $this->memory_reader->read($pid, $address, 1); + } + return $str; + } +} diff --git a/src/Lib/Elf/Process/ProcessModuleSymbolReader.php b/src/Lib/Elf/Process/ProcessModuleSymbolReader.php index 556936a6..b0846f78 100644 --- a/src/Lib/Elf/Process/ProcessModuleSymbolReader.php +++ b/src/Lib/Elf/Process/ProcessModuleSymbolReader.php @@ -14,6 +14,8 @@ namespace Reli\Lib\Elf\Process; use FFI\CData; +use Reli\Lib\ByteStream\CDataByteReader; +use Reli\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader; use Reli\Lib\Elf\SymbolResolver\Elf64AllSymbolResolver; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolver; use Reli\Lib\Process\MemoryMap\ProcessModuleMemoryMap; @@ -31,9 +33,10 @@ public function __construct( private Elf64SymbolResolver $symbol_resolver, ProcessModuleMemoryMap $module_memory_map, private MemoryReaderInterface $memory_reader, + private IntegerByteSequenceReader $integer_reader, private ?int $tls_block_address ) { - $this->base_address = $module_memory_map->getBaseAddress(); + $this->base_address = $module_memory_map->getBaseAddress() - $this->symbol_resolver->getBaseAddress()->toInt(); } /** @@ -85,9 +88,44 @@ private function resolveAddressAndSize(string $symbol_name): ?array } $base_address = $this->tls_block_address; } + return [$base_address + $symbol->st_value->toInt(), $symbol->st_size->toInt()]; } + public function getLinkMapAddress(): ?int + { + $dt_debug_address = $this->symbol_resolver->getDtDebugAddress(); + if (is_null($dt_debug_address)) { + return null; + } + $dt_debug_un_pointer = $this->base_address + $dt_debug_address + 8; + $r_debug_pointer = $this->integer_reader->read64( + new CDataByteReader( + $this->memory_reader->read( + $this->pid, + $dt_debug_un_pointer, + 8 + ), + ), + 0, + )->toInt(); + $root_link_map_address_pointer = $r_debug_pointer + 8; + $root_link_map_address = $this->integer_reader->read64( + new CDataByteReader( + $this->memory_reader->read( + $this->pid, + $root_link_map_address_pointer, + 8 + ), + ), + 0, + )->toInt(); + if ($root_link_map_address === 0) { + return null; + } + return $root_link_map_address; + } + public function isAllSymbolResolvable(): bool { return $this->symbol_resolver instanceof Elf64AllSymbolResolver; diff --git a/src/Lib/Elf/Process/ProcessModuleSymbolReaderCreator.php b/src/Lib/Elf/Process/ProcessModuleSymbolReaderCreator.php index 0b335904..9caeba56 100644 --- a/src/Lib/Elf/Process/ProcessModuleSymbolReaderCreator.php +++ b/src/Lib/Elf/Process/ProcessModuleSymbolReaderCreator.php @@ -13,9 +13,13 @@ namespace Reli\Lib\Elf\Process; +use Reli\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader; use Reli\Lib\Elf\Parser\ElfParserException; use Reli\Lib\Elf\SymbolResolver\Elf64CachedSymbolResolver; use Reli\Lib\Elf\SymbolResolver\SymbolResolverCreatorInterface; +use Reli\Lib\Elf\Tls\LibThreadDbTlsFinder; +use Reli\Lib\Elf\Tls\TlsFinderException; +use Reli\Lib\Elf\Tls\X64LinuxThreadPointerRetriever; use Reli\Lib\Process\MemoryMap\ProcessMemoryMap; use Reli\Lib\Process\MemoryMap\ProcessModuleMemoryMap; use Reli\Lib\Process\MemoryReader\MemoryReaderInterface; @@ -26,6 +30,8 @@ public function __construct( private SymbolResolverCreatorInterface $symbol_resolver_creator, private MemoryReaderInterface $memory_reader, private PerBinarySymbolCacheRetriever $per_binary_symbol_cache_retriever, + private IntegerByteSequenceReader $integer_reader, + private LinkMapLoader $link_map_loader, ) { } @@ -34,7 +40,8 @@ public function createModuleReaderByNameRegex( ProcessMemoryMap $process_memory_map, string $regex, ?string $binary_path, - ?int $tls_block_address = null + ?ProcessModuleSymbolReader $libpthread_symbol_reader = null, + ?int $root_link_map_address = null, ): ?ProcessModuleSymbolReader { $memory_areas = $process_memory_map->findByNameRegex($regex); if ($memory_areas === []) { @@ -57,11 +64,32 @@ public function createModuleReaderByNameRegex( BinaryFingerprint::fromProcessModuleMemoryMap($module_memory_map) ), ); + + $tls_block_address = null; + if (!is_null($libpthread_symbol_reader) and !is_null($root_link_map_address)) { + try { + $tls_finder = new LibThreadDbTlsFinder( + $libpthread_symbol_reader, + X64LinuxThreadPointerRetriever::createDefault(), + $this->memory_reader, + $this->integer_reader + ); + $link_map = $this->link_map_loader->searchByName( + $module_name, + $pid, + $root_link_map_address, + ); + $tls_block_address = $tls_finder->findTlsBlock($pid, $link_map?->this_address); + } catch (TlsFinderException $e) { + } + } + return new ProcessModuleSymbolReader( $pid, $symbol_resolver, $module_memory_map, $this->memory_reader, + $this->integer_reader, $tls_block_address ); } diff --git a/src/Lib/Elf/Process/ProcessSymbolReaderInterface.php b/src/Lib/Elf/Process/ProcessSymbolReaderInterface.php index f594e206..4bad0a2b 100644 --- a/src/Lib/Elf/Process/ProcessSymbolReaderInterface.php +++ b/src/Lib/Elf/Process/ProcessSymbolReaderInterface.php @@ -27,4 +27,6 @@ public function read(string $symbol_name): ?CData; * @throws ProcessSymbolReaderException */ public function resolveAddress(string $symbol_name): ?int; + + public function getLinkMapAddress(): ?int; } diff --git a/src/Lib/Elf/Structure/Elf64/Elf64DynamicStructure.php b/src/Lib/Elf/Structure/Elf64/Elf64DynamicStructure.php index af7dca42..31d809b8 100644 --- a/src/Lib/Elf/Structure/Elf64/Elf64DynamicStructure.php +++ b/src/Lib/Elf/Structure/Elf64/Elf64DynamicStructure.php @@ -68,6 +68,8 @@ final class Elf64DynamicStructure public const DF_BIND_NOW = 8; public function __construct( + public int $offset, + public int $v_addr, public UInt64 $d_tag, public UInt64 $d_un ) { @@ -78,6 +80,11 @@ public function isEnd(): bool return $this->d_tag->hi === 0 and $this->d_tag->lo === self::DT_NULL; } + public function isPltGot(): bool + { + return $this->d_tag->hi === 0 and $this->d_tag->lo === self::DT_PLTGOT; + } + public function isHashTable(): bool { return $this->d_tag->hi === 0 and $this->d_tag->lo === self::DT_HASH; diff --git a/src/Lib/Elf/Structure/Elf64/Elf64ProgramHeaderTable.php b/src/Lib/Elf/Structure/Elf64/Elf64ProgramHeaderTable.php index 8505ad03..a223f7b5 100644 --- a/src/Lib/Elf/Structure/Elf64/Elf64ProgramHeaderTable.php +++ b/src/Lib/Elf/Structure/Elf64/Elf64ProgramHeaderTable.php @@ -41,7 +41,7 @@ public function findLoad(): array public function findBaseAddress(): UInt64 { - $base_address = new UInt64(0, 0); + $base_address = new UInt64(0xffff_ffff, 0xffff_ffff); foreach ($this->findLoad() as $pt_load) { if ($pt_load->p_vaddr->hi < $base_address->hi) { $base_address = $pt_load->p_vaddr; @@ -51,6 +51,9 @@ public function findBaseAddress(): UInt64 } } } + if ($base_address->hi === 0xffff_ffff and $base_address->lo === 0xffff_ffff) { + $base_address = new UInt64(0, 0); + } return $base_address; } diff --git a/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderEntry.php b/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderEntry.php index e4cfe762..93335cce 100644 --- a/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderEntry.php +++ b/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderEntry.php @@ -64,4 +64,9 @@ public function isStringTable(): bool { return $this->sh_type === self::SHT_STRTAB; } + + public function isDynamic(): bool + { + return $this->sh_type === self::SHT_DYNAMIC; + } } diff --git a/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderTable.php b/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderTable.php index 7ce228f7..222dda9a 100644 --- a/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderTable.php +++ b/src/Lib/Elf/Structure/Elf64/Elf64SectionHeaderTable.php @@ -44,4 +44,14 @@ public function findStringTableEntry(): ?Elf64SectionHeaderEntry } return null; } + + public function findDynamicEntry(): ?Elf64SectionHeaderEntry + { + foreach ($this->entries as $entry) { + if ($entry->isDynamic()) { + return $entry; + } + } + return null; + } } diff --git a/src/Lib/Elf/SymbolResolver/Elf64CachedSymbolResolver.php b/src/Lib/Elf/SymbolResolver/Elf64CachedSymbolResolver.php index 37bfa7d0..e6712cd0 100644 --- a/src/Lib/Elf/SymbolResolver/Elf64CachedSymbolResolver.php +++ b/src/Lib/Elf/SymbolResolver/Elf64CachedSymbolResolver.php @@ -14,6 +14,7 @@ namespace Reli\Lib\Elf\SymbolResolver; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; +use Reli\Lib\Integer\UInt64; final class Elf64CachedSymbolResolver implements Elf64SymbolResolver { @@ -33,4 +34,14 @@ public function resolve(string $symbol_name): Elf64SymbolTableEntry } return $this->symbol_cache->get($symbol_name); } + + public function getDtDebugAddress(): ?int + { + return $this->resolver->getDtDebugAddress(); + } + + public function getBaseAddress(): UInt64 + { + return $this->resolver->getBaseAddress(); + } } diff --git a/src/Lib/Elf/SymbolResolver/Elf64DynamicSymbolResolver.php b/src/Lib/Elf/SymbolResolver/Elf64DynamicSymbolResolver.php index 42dddd5e..f859959b 100644 --- a/src/Lib/Elf/SymbolResolver/Elf64DynamicSymbolResolver.php +++ b/src/Lib/Elf/SymbolResolver/Elf64DynamicSymbolResolver.php @@ -20,6 +20,7 @@ use Reli\Lib\Elf\Structure\Elf64\Elf64StringTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; +use Reli\Lib\Integer\UInt64; final class Elf64DynamicSymbolResolver implements Elf64SymbolResolver { @@ -30,21 +31,37 @@ public static function load(Elf64Parser $parser, ByteReaderInterface $php_binary { $elf_header = $parser->parseElfHeader($php_binary); $elf_program_header = $parser->parseProgramHeader($php_binary, $elf_header); - $elf_dynamic_array = $parser->parseDynamicStructureArray($php_binary, $elf_program_header->findDynamic()[0]); - $elf_string_table = $parser->parseStringTable($php_binary, $elf_dynamic_array); - $elf_gnu_hash_table = $parser->parseGnuHashTable($php_binary, $elf_dynamic_array); + $base_address = $elf_program_header->findBaseAddress(); + $dynamic_entry = $elf_program_header->findDynamic()[0]; + $elf_dynamic_array = $parser->parseDynamicStructureArray( + $php_binary, + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr, + ); + $elf_string_table = $parser->parseStringTable($php_binary, $base_address, $elf_dynamic_array); + $elf_gnu_hash_table = $parser->parseGnuHashTable($php_binary, $base_address, $elf_dynamic_array); if (is_null($elf_gnu_hash_table)) { throw new ElfParserException('cannot find gnu hash table'); } $elf_symbol_table = $parser->parseSymbolTableFromDynamic( $php_binary, + $base_address, $elf_dynamic_array, $elf_gnu_hash_table->getNumberOfSymbols() ); + + $dt_debug_address = null; + $debug_entry = $elf_dynamic_array->findDebugEntry(); + if (!is_null($debug_entry)) { + $dt_debug_address = $debug_entry->v_addr; + } + return new self( $elf_symbol_table, $elf_gnu_hash_table, - $elf_string_table + $elf_string_table, + $base_address, + $dt_debug_address ); } @@ -52,6 +69,8 @@ public function __construct( private Elf64SymbolTable $symbol_table, private Elf64GnuHashTable $hash_table, private Elf64StringTable $string_table, + private UInt64 $base_address, + private ?int $dt_debug_address = null, ) { } @@ -63,4 +82,14 @@ public function resolve(string $symbol_name): Elf64SymbolTableEntry }); return $this->symbol_table->lookup($index); } + + public function getDtDebugAddress(): ?int + { + return $this->dt_debug_address; + } + + public function getBaseAddress(): UInt64 + { + return $this->base_address; + } } diff --git a/src/Lib/Elf/SymbolResolver/Elf64LinearScanSymbolResolver.php b/src/Lib/Elf/SymbolResolver/Elf64LinearScanSymbolResolver.php index 95517586..f7349f4f 100644 --- a/src/Lib/Elf/SymbolResolver/Elf64LinearScanSymbolResolver.php +++ b/src/Lib/Elf/SymbolResolver/Elf64LinearScanSymbolResolver.php @@ -16,12 +16,15 @@ use Reli\Lib\Elf\Structure\Elf64\Elf64StringTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTable; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; +use Reli\Lib\Integer\UInt64; final class Elf64LinearScanSymbolResolver implements Elf64AllSymbolResolver { public function __construct( private Elf64SymbolTable $symbol_table, private Elf64StringTable $string_table, + private UInt64 $base_address, + private ?int $dt_debug_address, ) { } @@ -36,4 +39,14 @@ public function resolve(string $symbol_name): Elf64SymbolTableEntry } return $all_symbols[Elf64SymbolTable::STN_UNDEF]; } + + public function getDtDebugAddress(): ?int + { + return $this->dt_debug_address; + } + + public function getBaseAddress(): UInt64 + { + return $this->base_address; + } } diff --git a/src/Lib/Elf/SymbolResolver/Elf64SymbolResolver.php b/src/Lib/Elf/SymbolResolver/Elf64SymbolResolver.php index ea9f8a66..8fdbb7e9 100644 --- a/src/Lib/Elf/SymbolResolver/Elf64SymbolResolver.php +++ b/src/Lib/Elf/SymbolResolver/Elf64SymbolResolver.php @@ -14,8 +14,13 @@ namespace Reli\Lib\Elf\SymbolResolver; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; +use Reli\Lib\Integer\UInt64; interface Elf64SymbolResolver { public function resolve(string $symbol_name): Elf64SymbolTableEntry; + + public function getDtDebugAddress(): ?int; + + public function getBaseAddress(): UInt64; } diff --git a/src/Lib/Elf/SymbolResolver/Elf64SymbolResolverCreator.php b/src/Lib/Elf/SymbolResolver/Elf64SymbolResolverCreator.php index c0d77a46..2ccbfab8 100644 --- a/src/Lib/Elf/SymbolResolver/Elf64SymbolResolverCreator.php +++ b/src/Lib/Elf/SymbolResolver/Elf64SymbolResolverCreator.php @@ -41,6 +41,8 @@ public function createLinearScanResolverFromPath(string $path): Elf64LinearScanS } $binary = new StringByteReader($binary_raw); $elf_header = $this->elf_parser->parseElfHeader($binary); + $program_header = $this->elf_parser->parseProgramHeader($binary, $elf_header); + $base_address = $program_header->findBaseAddress(); $section_header = $this->elf_parser->parseSectionHeader($binary, $elf_header); $symbol_table_section_header_entry = $section_header->findSymbolTableEntry(); $string_table_section_header_entry = $section_header->findStringTableEntry(); @@ -58,7 +60,27 @@ public function createLinearScanResolverFromPath(string $path): Elf64LinearScanS $binary, $string_table_section_header_entry ); - return new Elf64LinearScanSymbolResolver($symbol_table, $string_table); + + $dt_debug_address = null; + $dynamic_entry = $section_header->findDynamicEntry(); + if (!is_null($dynamic_entry)) { + $dynamic_array = $this->elf_parser->parseDynamicStructureArray( + $binary, + $dynamic_entry->sh_offset, + $dynamic_entry->sh_addr + ); + $debug_entry = $dynamic_array->findDebugEntry(); + if (!is_null($debug_entry)) { + $dt_debug_address = $debug_entry->v_addr; + } + } + + return new Elf64LinearScanSymbolResolver( + $symbol_table, + $string_table, + $base_address, + $dt_debug_address, + ); } /** @@ -83,29 +105,43 @@ public function createDynamicResolverFromProcessMemory( ProcessModuleMemoryMapInterface $module_memory_map ): Elf64DynamicSymbolResolver { $php_binary = new ProcessMemoryByteReader($memory_reader, $pid, $module_memory_map); - $unrelocated_php_binary = new UnrelocatedProcessMemoryByteReader($php_binary, $module_memory_map); + + $unrelocated_php_binary = $php_binary; $elf_header = $this->elf_parser->parseElfHeader($unrelocated_php_binary); $elf_program_header = $this->elf_parser->parseProgramHeader($unrelocated_php_binary, $elf_header); + $dynamic_entry = $elf_program_header->findDynamic()[0]; $elf_dynamic_array = $this->elf_parser->parseDynamicStructureArray( $unrelocated_php_binary, - $elf_program_header->findDynamic()[0] + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr ); - $elf_string_table = $this->elf_parser->parseStringTable($php_binary, $elf_dynamic_array); - $elf_gnu_hash_table = $this->elf_parser->parseGnuHashTable($php_binary, $elf_dynamic_array); + $base_address = $elf_program_header->findBaseAddress(); + $elf_string_table = $this->elf_parser->parseStringTable($php_binary, $base_address, $elf_dynamic_array); + $elf_gnu_hash_table = $this->elf_parser->parseGnuHashTable($php_binary, $base_address, $elf_dynamic_array); if (is_null($elf_gnu_hash_table)) { throw new ElfParserException('cannot find gnu hash table'); } $elf_symbol_table = $this->elf_parser->parseSymbolTableFromDynamic( $php_binary, + $base_address, $elf_dynamic_array, $elf_gnu_hash_table->getNumberOfSymbols() ); + + $link_map_pointer_address = null; + $debug_entry = $elf_dynamic_array->findDebugEntry(); + if (!is_null($debug_entry)) { + $link_map_pointer_address = $debug_entry->d_un->toInt() + 4; + } + return new Elf64DynamicSymbolResolver( $elf_symbol_table, $elf_gnu_hash_table, - $elf_string_table + $elf_string_table, + $base_address, + $link_map_pointer_address ); } } diff --git a/src/Lib/Elf/Tls/LibThreadDbTlsFinder.php b/src/Lib/Elf/Tls/LibThreadDbTlsFinder.php index a2b138f7..1690b6ed 100644 --- a/src/Lib/Elf/Tls/LibThreadDbTlsFinder.php +++ b/src/Lib/Elf/Tls/LibThreadDbTlsFinder.php @@ -39,20 +39,35 @@ public function __construct( * @throws ProcessSymbolReaderException * @throws TlsFinderException */ - public function findTlsBlock(int $pid, int $module_index): int + public function findTlsBlock(int $pid, ?int $link_map_address): int { $thread_pointer = $this->thread_pointer_retriever->getThreadPointer($pid); [,,$thread_db_pthread_dtvp_offset] = $this->getLibThreadDbDescriptor('_thread_db_pthread_dtvp'); [$thread_db_dtv_dtv_size,,] = $this->getLibThreadDbDescriptor('_thread_db_dtv_dtv'); [,,$thread_db_dtv_t_pointer_val_offset] = $this->getLibThreadDbDescriptor('_thread_db_dtv_t_pointer_val'); -// [,,] = $this->getLibThreadDbDescriptor($pid, '_thread_db_link_map_l_tls_modid'); + [,,$thread_db_link_map_l_tls_modid_offset] = $this->getLibThreadDbDescriptor('_thread_db_link_map_l_tls_modid'); $dtv_pointer_address = $thread_pointer + $thread_db_pthread_dtvp_offset; $dtv_pointer_cdata = $this->memory_reader->read($pid, $dtv_pointer_address, 8); $dtv_pointer = $this->integer_reader->read64(new CDataByteReader($dtv_pointer_cdata), 0)->toInt(); - $dtv_slot = $thread_db_dtv_dtv_size * $module_index; + $module_id = 1; + if (!is_null($link_map_address)) { + $module_id_address = $thread_db_link_map_l_tls_modid_offset + $link_map_address; + $module_id = $this->integer_reader->read32( + new CDataByteReader( + $this->memory_reader->read( + $pid, + $module_id_address, + 4 + ) + ), + 0 + ); + } + + $dtv_slot = $thread_db_dtv_dtv_size * $module_id; $tls_address_pointer = $dtv_pointer + $dtv_slot + $thread_db_dtv_t_pointer_val_offset; $tls_address_cdata = $this->memory_reader->read($pid, $tls_address_pointer, 8); diff --git a/src/Lib/Elf/Tls/TlsFinderInterface.php b/src/Lib/Elf/Tls/TlsFinderInterface.php index d0b3e344..da69a980 100644 --- a/src/Lib/Elf/Tls/TlsFinderInterface.php +++ b/src/Lib/Elf/Tls/TlsFinderInterface.php @@ -15,5 +15,5 @@ interface TlsFinderInterface { - public function findTlsBlock(int $pid, int $module_index): int; + public function findTlsBlock(int $pid, int $link_map_address): int; } diff --git a/src/Lib/PhpProcessReader/PhpGlobalsFinder.php b/src/Lib/PhpProcessReader/PhpGlobalsFinder.php index d64709cf..d7bfd5ce 100644 --- a/src/Lib/PhpProcessReader/PhpGlobalsFinder.php +++ b/src/Lib/PhpProcessReader/PhpGlobalsFinder.php @@ -49,10 +49,14 @@ public function findTsrmLsCache( $target_php_settings )->read('_tsrm_ls_cache'); if (isset($tsrm_ls_cache_cdata)) { - return $this->integer_reader->read64( + $tsrm_ls_cache_address = $this->integer_reader->read64( new CDataByteReader($tsrm_ls_cache_cdata), 0 )->toInt(); + if ($tsrm_ls_cache_address === 0) { + return null; + } + return $tsrm_ls_cache_address; } return null; } @@ -75,6 +79,19 @@ public function getSymbolReader( ); } + public function getZtsGlobalsSymbolReader( + ProcessSpecifier $process_specifier, + TargetPhpSettings $target_php_settings + ): ProcessSymbolReaderInterface { + return $this->php_symbol_reader_creator->create( + $process_specifier->pid, + $target_php_settings->zts_globals_regex, + $target_php_settings->libpthread_regex, + $target_php_settings->php_path, + $target_php_settings->libpthread_path + ); + } + /** * @param TargetPhpSettings> $target_php_settings * @throws ElfParserException @@ -115,7 +132,7 @@ public function findModuleRegistry( ProcessSpecifier $process_specifier, TargetPhpSettings $target_php_settings ): ?int { - $symbol_reader = $this->getSymbolReader( + $symbol_reader = $this->getZtsGlobalsSymbolReader( $process_specifier, $target_php_settings ); @@ -136,7 +153,7 @@ public function findGlobals( case ZendTypeReader::V72: case ZendTypeReader::V73: $id_symbol = $symbol_name . '_id'; - $globals_id_cdata = $this->getSymbolReader($process_specifier, $target_php_settings) + $globals_id_cdata = $this->getZtsGlobalsSymbolReader($process_specifier, $target_php_settings) ->read($id_symbol); if (is_null($globals_id_cdata)) { throw new RuntimeException('global symbol id not found'); @@ -172,7 +189,7 @@ public function findGlobals( case ZendTypeReader::V82: case ZendTypeReader::V83: $offset = $symbol_name . '_offset'; - $globals_offset_cdata = $this->getSymbolReader( + $globals_offset_cdata = $this->getZtsGlobalsSymbolReader( $process_specifier, $target_php_settings )->read($offset); diff --git a/src/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollector.php b/src/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollector.php index 32b39b88..1d946a56 100644 --- a/src/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollector.php +++ b/src/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollector.php @@ -196,11 +196,13 @@ public function resolve(string $type_name): string private function getMainChunkAddress( ProcessSpecifier $process_specifier, TargetPhpSettings $target_php_settings, + int $eg_address, Dereferencer $dereferencer, ): int { $chunk_address = $this->chunk_finder->findAddress( $process_specifier, $target_php_settings, + $eg_address, $dereferencer, ); if (is_null($chunk_address)) { @@ -227,6 +229,7 @@ public function collectAll( $this->getMainChunkAddress( $process_specifier, $target_php_settings, + $eg_address, $dereferencer, ), $zend_type_reader->sizeOf('zend_mm_chunk'), @@ -446,7 +449,9 @@ public function collectZval( $memory_limit_error_details, ); } elseif ($zval->isObject()) { - assert(!is_null($zval->value->obj)); + if ($zval->value->obj === null) { + return null; + } return $this->collectZendObjectPointer( $zval->value->obj, $map_ptr_base, diff --git a/src/Lib/PhpProcessReader/PhpSymbolReaderCreator.php b/src/Lib/PhpProcessReader/PhpSymbolReaderCreator.php index 202316da..67c22c6c 100644 --- a/src/Lib/PhpProcessReader/PhpSymbolReaderCreator.php +++ b/src/Lib/PhpProcessReader/PhpSymbolReaderCreator.php @@ -13,25 +13,20 @@ namespace Reli\Lib\PhpProcessReader; -use Reli\Lib\ByteStream\IntegerByteSequence\IntegerByteSequenceReader; -use Reli\Lib\Elf\Parser\ElfParserException; use Reli\Lib\Elf\Process\ProcessModuleSymbolReader; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\Process\ProcessSymbolReaderException; -use Reli\Lib\Elf\Tls\LibThreadDbTlsFinder; use Reli\Lib\Elf\Tls\TlsFinderException; -use Reli\Lib\Elf\Tls\X64LinuxThreadPointerRetriever; use Reli\Lib\Process\MemoryMap\ProcessMemoryMapCreator; use Reli\Lib\Process\MemoryReader\MemoryReaderException; -use Reli\Lib\Process\MemoryReader\MemoryReaderInterface; + +use function readlink; final class PhpSymbolReaderCreator { public function __construct( - private MemoryReaderInterface $memory_reader, private ProcessModuleSymbolReaderCreator $process_module_symbol_reader_creator, private ProcessMemoryMapCreator $process_memory_map_creator, - private IntegerByteSequenceReader $integer_reader, ) { } @@ -49,25 +44,27 @@ public function create( ): ProcessModuleSymbolReader { $process_memory_map = $this->process_memory_map_creator->getProcessMemoryMap($pid); - $tls_block_address = null; $libpthread_symbol_reader = $this->process_module_symbol_reader_creator->createModuleReaderByNameRegex( $pid, $process_memory_map, $libpthread_finder_regex, $libpthread_binary_path ); + $root_link_map_address = null; if (!is_null($libpthread_symbol_reader)) { - try { - $tls_finder = new LibThreadDbTlsFinder( - $libpthread_symbol_reader, - X64LinuxThreadPointerRetriever::createDefault(), - $this->memory_reader, - $this->integer_reader - ); - $tls_block_address = $tls_finder->findTlsBlock($pid, 1); - } catch (TlsFinderException $e) { - $tls_block_address = null; + $executable_path = readlink("/proc/{$pid}/exe"); + $full_executable_path = "/proc/{$pid}/root{$executable_path}"; + $main_executable_reader = $this->process_module_symbol_reader_creator->createModuleReaderByNameRegex( + $pid, + $process_memory_map, + $executable_path, + $full_executable_path, + $libpthread_symbol_reader, + ); + if (is_null($main_executable_reader)) { + throw new ProcessSymbolReaderException('main executable not found'); } + $root_link_map_address = $main_executable_reader->getLinkMapAddress(); } $php_symbol_reader = $this->process_module_symbol_reader_creator->createModuleReaderByNameRegex( @@ -75,7 +72,8 @@ public function create( $process_memory_map, $php_finder_regex, $php_binar_path, - $tls_block_address + $libpthread_symbol_reader, + $root_link_map_address, ); if (is_null($php_symbol_reader)) { throw new \RuntimeException('php module not found'); diff --git a/src/Lib/PhpProcessReader/PhpVersionDetector.php b/src/Lib/PhpProcessReader/PhpVersionDetector.php index b8a1110a..084fa813 100644 --- a/src/Lib/PhpProcessReader/PhpVersionDetector.php +++ b/src/Lib/PhpProcessReader/PhpVersionDetector.php @@ -89,6 +89,7 @@ public function decidePhpVersion( return new TargetPhpSettings( php_regex: $target_php_settings->php_regex, libpthread_regex: $target_php_settings->libpthread_regex, + zts_globals_regex: $target_php_settings->zts_globals_regex, php_version: $version, php_path: $target_php_settings->php_path, libpthread_path: $target_php_settings->libpthread_path, diff --git a/src/Lib/PhpProcessReader/PhpZendMemoryManagerChunkFinder.php b/src/Lib/PhpProcessReader/PhpZendMemoryManagerChunkFinder.php index 3db0eb76..6ed4c071 100644 --- a/src/Lib/PhpProcessReader/PhpZendMemoryManagerChunkFinder.php +++ b/src/Lib/PhpProcessReader/PhpZendMemoryManagerChunkFinder.php @@ -17,7 +17,6 @@ class PhpZendMemoryManagerChunkFinder public function __construct( private ProcessMemoryMapCreator $process_memory_map_creator, private ZendTypeReaderCreator $zend_type_reader_creator, - private PhpGlobalsFinder $php_globals_finder, ) { } @@ -25,26 +24,19 @@ public function __construct( public function findAddress( ProcessSpecifier $process_specifier, TargetPhpSettings $target_php_settings, + int $eg_address, Dereferencer $dereferencer, ): ?int { $zend_type_reader = $this->zend_type_reader_creator->create($target_php_settings->php_version); $memory_map = $this->process_memory_map_creator->getProcessMemoryMap($process_specifier->pid); - $process_memory_area = $memory_map->findByNameRegex('\[anon:zend_alloc\]'); - $execute_data_address = null; - if (!count($process_memory_area)) { - $eg_address = $this->php_globals_finder->findExecutorGlobals( - $process_specifier, - $target_php_settings - ); - $eg_pointer = new Pointer( - ZendExecutorGlobals::class, - $eg_address, - $zend_type_reader->sizeOf('zend_executor_globals'), - ); - $eg = $dereferencer->deref($eg_pointer); - $execute_data_address = $eg->current_execute_data?->address ?? 0; - $process_memory_area = $memory_map->findByAddress($execute_data_address); - } + $eg_pointer = new Pointer( + ZendExecutorGlobals::class, + $eg_address, + $zend_type_reader->sizeOf('zend_executor_globals'), + ); + $eg = $dereferencer->deref($eg_pointer); + $execute_data_address = $eg->current_execute_data?->address ?? 0; + $process_memory_area = $memory_map->findByAddress($execute_data_address); foreach ($process_memory_area as $area) { $begin = hexdec($area->begin); $end = hexdec($area->end); @@ -56,16 +48,8 @@ public function findAddress( $zend_type_reader->sizeOf('zend_mm_chunk'), ); $zend_mm_chunk = $dereferencer->deref($pointer); - $heap_address = $zend_mm_chunk->heap?->address; if ( - $heap_address === $zend_mm_chunk->heap_slot->getPointer()->address - and $zend_mm_chunk->num === 0 - and $zend_mm_chunk->heap_slot->size > 0 - ) { - return $p; - } elseif ( - isset($execute_data_address) - and $zend_mm_chunk->isInRange($execute_data_address) + $zend_mm_chunk->isInRange($execute_data_address) and !is_null($zend_mm_chunk->heap) ) { $heap = $dereferencer->deref($zend_mm_chunk->heap); diff --git a/tests/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInputTest.php b/tests/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInputTest.php index 280e4b5d..e5b2e50d 100644 --- a/tests/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInputTest.php +++ b/tests/Inspector/Settings/TargetPhpSettings/TargetPhpSettingsFromConsoleInputTest.php @@ -27,6 +27,7 @@ public function testFromConsoleInput(): void $input->expects()->getOption('php-version')->andReturns('v74'); $input->expects()->getOption('php-path')->andReturns('ghi'); $input->expects()->getOption('libpthread-path')->andReturns('jkl'); + $input->expects()->getOption('zts-globals-regex')->andReturns('mno'); $settings = (new TargetPhpSettingsFromConsoleInput())->createSettings($input); @@ -35,6 +36,7 @@ public function testFromConsoleInput(): void $this->assertSame('v74', $settings->php_version); $this->assertSame('ghi', $settings->php_path); $this->assertSame('jkl', $settings->libpthread_path); + $this->assertSame('mno', $settings->zts_globals_regex); } public function testFromConsoleInputDefault(): void @@ -45,6 +47,7 @@ public function testFromConsoleInputDefault(): void $input->expects()->getOption('php-version')->andReturns(null); $input->expects()->getOption('php-path')->andReturns(null); $input->expects()->getOption('libpthread-path')->andReturns(null); + $input->expects()->getOption('zts-globals-regex')->andReturns(null); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } @@ -56,6 +59,7 @@ public function testFromConsoleInputPhpVersionNotSupported(): void $input->expects()->getOption('php-version')->andReturns('v56'); $input->allows()->getOption('php-path')->andReturns(null); $input->allows()->getOption('libpthread-path')->andReturns(null); + $input->allows()->getOption('zts-globals-regex')->andReturns(null); $this->expectException(TargetPhpSettingsException::class); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } @@ -68,6 +72,7 @@ public function testFromConsoleInputPhpRegexNonString(): void $input->allows()->getOption('php-version')->andReturns(null); $input->allows()->getOption('php-path')->andReturns(null); $input->allows()->getOption('libpthread-path')->andReturns(null); + $input->allows()->getOption('zts-globals-regex')->andReturns(null); $this->expectException(TargetPhpSettingsException::class); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } @@ -80,6 +85,7 @@ public function testFromConsoleInputPthreadRegexNonString(): void $input->allows()->getOption('php-version')->andReturns(null); $input->allows()->getOption('php-path')->andReturns(null); $input->allows()->getOption('libpthread-path')->andReturns(null); + $input->allows()->getOption('zts-globals-regex')->andReturns(null); $this->expectException(TargetPhpSettingsException::class); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } @@ -92,6 +98,7 @@ public function testFromConsoleInputPhpPathNonString(): void $input->allows()->getOption('php-version')->andReturns(null); $input->expects()->getOption('php-path')->andReturns(1); $input->allows()->getOption('libpthread-path')->andReturns(null); + $input->allows()->getOption('zts-globals-regex')->andReturns(null); $this->expectException(TargetPhpSettingsException::class); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } @@ -104,6 +111,7 @@ public function testFromConsoleInputPthreadPathNonString(): void $input->allows()->getOption('php-version')->andReturns(null); $input->allows()->getOption('php-path')->andReturns(null); $input->expects()->getOption('libpthread-path')->andReturns(1); + $input->allows()->getOption('zts-globals-regex')->andReturns(null); $this->expectException(TargetPhpSettingsException::class); (new TargetPhpSettingsFromConsoleInput())->createSettings($input); } diff --git a/tests/Lib/Elf/Parser/Elf64ParserTest.php b/tests/Lib/Elf/Parser/Elf64ParserTest.php index e4ba35b0..76920347 100644 --- a/tests/Lib/Elf/Parser/Elf64ParserTest.php +++ b/tests/Lib/Elf/Parser/Elf64ParserTest.php @@ -130,7 +130,12 @@ public function testParseDynamicArray() $test_binary = $this->getTestBinary('test000.so'); $elf_header = $parser->parseElfHeader($test_binary); $program_header_table = $parser->parseProgramHeader($test_binary, $elf_header); - $dynamic_array = $parser->parseDynamicStructureArray($test_binary, $program_header_table->findDynamic()[0]); + $dynamic_entry = $program_header_table->findDynamic()[0]; + $dynamic_array = $parser->parseDynamicStructureArray( + $test_binary, + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr, + ); $this->assertCount(7, $dynamic_array->findAll()); $actual = []; @@ -157,8 +162,14 @@ public function testParseStringTable() $test_binary = $this->getTestBinary('test000.so'); $elf_header = $parser->parseElfHeader($test_binary); $program_header_table = $parser->parseProgramHeader($test_binary, $elf_header); - $dynamic_array = $parser->parseDynamicStructureArray($test_binary, $program_header_table->findDynamic()[0]); - $string_table = $parser->parseStringTable($test_binary, $dynamic_array); + $dynamic_entry = $program_header_table->findDynamic()[0]; + $dynamic_array = $parser->parseDynamicStructureArray( + $test_binary, + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr, + ); + $base_address = $program_header_table->findBaseAddress(); + $string_table = $parser->parseStringTable($test_binary, $base_address, $dynamic_array); $this->assertSame( 'main', $string_table->lookup(1) @@ -171,8 +182,14 @@ public function testParseGnuHashTable() $test_binary = $this->getTestBinary('test000.so'); $elf_header = $parser->parseElfHeader($test_binary); $program_header_table = $parser->parseProgramHeader($test_binary, $elf_header); - $dynamic_array = $parser->parseDynamicStructureArray($test_binary, $program_header_table->findDynamic()[0]); - $gnu_hash_table = $parser->parseGnuHashTable($test_binary, $dynamic_array); + $dynamic_entry = $program_header_table->findDynamic()[0]; + $dynamic_array = $parser->parseDynamicStructureArray( + $test_binary, + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr, + ); + $base_address = $program_header_table->findBaseAddress(); + $gnu_hash_table = $parser->parseGnuHashTable($test_binary, $base_address, $dynamic_array); $this->assertNotNull($gnu_hash_table); $this->assertSame(2, $gnu_hash_table->getNumberOfSymbols()); $index = $gnu_hash_table->lookup('main', fn ($unused) => true); @@ -188,11 +205,18 @@ public function testParseSymbolTable() $test_binary = $this->getTestBinary('test000.so'); $elf_header = $parser->parseElfHeader($test_binary); $program_header_table = $parser->parseProgramHeader($test_binary, $elf_header); - $dynamic_array = $parser->parseDynamicStructureArray($test_binary, $program_header_table->findDynamic()[0]); - $gnu_hash_table = $parser->parseGnuHashTable($test_binary, $dynamic_array); + $dynamic_entry = $program_header_table->findDynamic()[0]; + $dynamic_array = $parser->parseDynamicStructureArray( + $test_binary, + $dynamic_entry->p_offset, + $dynamic_entry->p_vaddr, + ); + $base_address = $program_header_table->findBaseAddress(); + $gnu_hash_table = $parser->parseGnuHashTable($test_binary, $base_address, $dynamic_array); $number_of_symbols = $gnu_hash_table->getNumberOfSymbols(); $symbol_table = $parser->parseSymbolTableFromDynamic( $test_binary, + $base_address, $dynamic_array, $number_of_symbols ); @@ -205,7 +229,8 @@ public function testParseSymbolTable() $this->assertSame(0, $all_symbols[0]->st_value->toInt()); $this->assertSame(0, $all_symbols[0]->st_size->toInt()); - $string_table = $parser->parseStringTable($test_binary, $dynamic_array); + $base_address = $program_header_table->findBaseAddress(); + $string_table = $parser->parseStringTable($test_binary, $base_address, $dynamic_array); $index = $gnu_hash_table->lookup('main', fn ($unused) => true); $main_symbol = $symbol_table->lookup($index); $this->assertSame($all_symbols[1], $main_symbol); diff --git a/tests/Lib/Elf/Process/ProcessModuleSymbolReaderCreatorTest.php b/tests/Lib/Elf/Process/ProcessModuleSymbolReaderCreatorTest.php index d58c5caa..a4fb6c68 100644 --- a/tests/Lib/Elf/Process/ProcessModuleSymbolReaderCreatorTest.php +++ b/tests/Lib/Elf/Process/ProcessModuleSymbolReaderCreatorTest.php @@ -15,6 +15,7 @@ use Mockery; use Reli\BaseTestCase; +use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\ElfParserException; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolver; @@ -52,11 +53,20 @@ public function testCreateModuleReaderByNameRegexFallbackToDynamic() ) ) ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $symbol_reader_creator = new ProcessModuleSymbolReaderCreator( $symbol_resolver_creator, $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader(), + ), ); $process_memory_map = new ProcessMemoryMap([ new ProcessMemoryArea( @@ -111,6 +121,11 @@ function ($actual) { ) ->andReturns($symbol_resolver = Mockery::mock(Elf64SymbolResolver::class)) ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; + $symbol_resolver->expects() ->resolve('test') ->andReturns( @@ -129,6 +144,11 @@ function ($actual) { $symbol_resolver_creator, $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader(), + ), ); $process_memory_map = new ProcessMemoryMap([ new ProcessMemoryArea( @@ -164,6 +184,11 @@ public function testCreateModuleReaderByNameRegexModuleNotFound() $symbol_resolver_creator, $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader(), + ), ); $process_memory_map = new ProcessMemoryMap([]); diff --git a/tests/Lib/Elf/Process/ProcessModuleSymbolReaderTest.php b/tests/Lib/Elf/Process/ProcessModuleSymbolReaderTest.php index ee1d58a8..d303011f 100644 --- a/tests/Lib/Elf/Process/ProcessModuleSymbolReaderTest.php +++ b/tests/Lib/Elf/Process/ProcessModuleSymbolReaderTest.php @@ -16,6 +16,7 @@ use FFI; use Mockery; use Reli\BaseTestCase; +use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Structure\Elf64\Elf64SymbolTableEntry; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolver; use Reli\Lib\Process\MemoryMap\ProcessMemoryArea; @@ -57,7 +58,12 @@ public function testRead() 1, new UInt64(0, 0x1000), new UInt64(0, 8), - )); + )) + ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $return = FFI::new('unsigned char[8]'); $memory_reader = Mockery::mock(MemoryReaderInterface::class); $memory_reader->expects()->read(1, 0x10001000, 8)->andReturns($return); @@ -67,6 +73,7 @@ public function testRead() $symbol_resolver, new ProcessModuleMemoryMap($memory_areas), $memory_reader, + new LittleEndianReader(), null ); $this->assertSame( @@ -109,6 +116,10 @@ public function testReturnNullOnTryingToReadUndefinedSymbol() )) ->twice() ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $process_symbol_reader = new ProcessModuleSymbolReader( @@ -116,6 +127,7 @@ public function testReturnNullOnTryingToReadUndefinedSymbol() $symbol_resolver, new ProcessModuleMemoryMap($memory_areas), $memory_reader, + new LittleEndianReader(), null ); @@ -159,7 +171,12 @@ public function testResolveAddress() 1, new UInt64(0, 0x1000), new UInt64(0, 8), - )); + )) + ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $process_symbol_reader = new ProcessModuleSymbolReader( @@ -167,6 +184,7 @@ public function testResolveAddress() $symbol_resolver, new ProcessModuleMemoryMap($memory_areas), $memory_reader, + new LittleEndianReader(), null ); $address = $process_symbol_reader->resolveAddress('test_symbol'); @@ -204,7 +222,12 @@ public function testReadTlsSymbol() 1, new UInt64(0, 0x1000), new UInt64(0, 8), - )); + )) + ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $process_symbol_reader = new ProcessModuleSymbolReader( @@ -212,6 +235,7 @@ public function testReadTlsSymbol() $symbol_resolver, new ProcessModuleMemoryMap($memory_areas), $memory_reader, + new LittleEndianReader(), 0x10000 ); $this->assertSame( @@ -251,7 +275,12 @@ public function testReadTlsSymbolOnTlsBlockNotSpecified() 1, new UInt64(0, 0x1000), new UInt64(0, 8), - )); + )) + ; + $symbol_resolver->expects() + ->getBaseAddress() + ->andReturns(new UInt64(0, 0)) + ; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $process_symbol_reader = new ProcessModuleSymbolReader( @@ -259,6 +288,7 @@ public function testReadTlsSymbolOnTlsBlockNotSpecified() $symbol_resolver, new ProcessModuleMemoryMap($memory_areas), $memory_reader, + new LittleEndianReader(), null ); $this->expectException(ProcessSymbolReaderException::class); diff --git a/tests/Lib/Elf/Tls/LibThreadDbTlsFinderTest.php b/tests/Lib/Elf/Tls/LibThreadDbTlsFinderTest.php index 636a4734..8375984e 100644 --- a/tests/Lib/Elf/Tls/LibThreadDbTlsFinderTest.php +++ b/tests/Lib/Elf/Tls/LibThreadDbTlsFinderTest.php @@ -28,14 +28,21 @@ public function testFindTls() $_thread_db_pthread_dtvp = \FFI::new('unsigned char[12]'); $_thread_db_dtv_dtv = \FFI::new('unsigned char[12]'); $_thread_db_dtv_t_pointer_val = \FFI::new('unsigned char[12]'); + $_thread_db_link_map_l_tls_modid = \FFI::new('unsigned char[12]'); \FFI::memset($_thread_db_pthread_dtvp, 0, 12); \FFI::memset($_thread_db_dtv_dtv, 0, 12); \FFI::memset($_thread_db_dtv_t_pointer_val, 0, 12); + \FFI::memset($_thread_db_link_map_l_tls_modid, 0, 12); $_thread_db_pthread_dtvp[8] = 8; $_thread_db_dtv_dtv[0] = 64; + $_thread_db_link_map_l_tls_modid[8] = 128; $symbol_reader->expects()->read('_thread_db_pthread_dtvp')->andReturns($_thread_db_pthread_dtvp); $symbol_reader->expects()->read('_thread_db_dtv_dtv')->andReturns($_thread_db_dtv_dtv); $symbol_reader->expects()->read('_thread_db_dtv_t_pointer_val')->andReturns($_thread_db_dtv_t_pointer_val); + $symbol_reader->expects() + ->read('_thread_db_link_map_l_tls_modid') + ->andReturns($_thread_db_link_map_l_tls_modid) + ; $thread_pointer_retriever = Mockery::mock(ThreadPointerRetrieverInterface::class); $thread_pointer_retriever->expects()->getThreadPointer(1)->andReturns(0x10000); @@ -46,10 +53,14 @@ public function testFindTls() $tls_block_address = \FFI::new('unsigned char[8]'); \FFI::memset($tls_block_address, 0, 8); $tls_block_address[2] = 3; + $module_id = \FFI::new('unsigned char[4]'); + \FFI::memset($module_id, 0, 4); + $module_id[0] = 1; $memory_reader = Mockery::mock(MemoryReaderInterface::class); $memory_reader->expects()->read(1, 0x10008, 8)->andReturns($dtv_address); $memory_reader->expects()->read(1, 0x20008, 8)->andReturns($tls_block_address); + $memory_reader->expects()->read(1, 0x40080, 4)->andReturns($module_id); $finder = new LibThreadDbTlsFinder( $symbol_reader, @@ -60,7 +71,7 @@ public function testFindTls() $this->assertSame( 0x30000, - $finder->findTlsBlock(1, 1) + $finder->findTlsBlock(1, 0x40000) ); } diff --git a/tests/Lib/PhpInternals/Types/Zend/ZendArrayTest.php b/tests/Lib/PhpInternals/Types/Zend/ZendArrayTest.php index b021cb4a..0777844b 100644 --- a/tests/Lib/PhpInternals/Types/Zend/ZendArrayTest.php +++ b/tests/Lib/PhpInternals/Types/Zend/ZendArrayTest.php @@ -17,6 +17,7 @@ use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings; use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\Elf64Parser; +use Reli\Lib\Elf\Process\LinkMapLoader; use Reli\Lib\Elf\Process\PerBinarySymbolCacheRetriever; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolverCreator; @@ -78,7 +79,6 @@ public function testFindByKey() fgets($pipes[1]); $child_status = proc_get_status($this->child); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -88,9 +88,13 @@ public function testFindByKey() ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ) ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, diff --git a/tests/Lib/PhpProcessReader/CallTraceReader/CallTraceReaderTest.php b/tests/Lib/PhpProcessReader/CallTraceReader/CallTraceReaderTest.php index 3b55853b..1f5f8c81 100644 --- a/tests/Lib/PhpProcessReader/CallTraceReader/CallTraceReaderTest.php +++ b/tests/Lib/PhpProcessReader/CallTraceReader/CallTraceReaderTest.php @@ -18,6 +18,7 @@ use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings; use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\Elf64Parser; +use Reli\Lib\Elf\Process\LinkMapLoader; use Reli\Lib\Elf\Process\PerBinarySymbolCacheRetriever; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolverCreator; @@ -82,7 +83,6 @@ public function wait() { $child_status = proc_get_status($this->child); $this->assertSame(true, $child_status['running']); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -92,9 +92,13 @@ public function wait() { ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ), ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, diff --git a/tests/Lib/PhpProcessReader/PhpGlobalsFinderTest.php b/tests/Lib/PhpProcessReader/PhpGlobalsFinderTest.php index e55866f4..98752437 100644 --- a/tests/Lib/PhpProcessReader/PhpGlobalsFinderTest.php +++ b/tests/Lib/PhpProcessReader/PhpGlobalsFinderTest.php @@ -17,6 +17,7 @@ use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings; use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\Elf64Parser; +use Reli\Lib\Elf\Process\LinkMapLoader; use Reli\Lib\Elf\Process\PerBinarySymbolCacheRetriever; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolverCreator; @@ -47,7 +48,6 @@ public function testFindModuleRegistry() fgets($pipes[1]); $child_status = proc_get_status($this->child); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -57,9 +57,13 @@ public function testFindModuleRegistry() ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader(), + ), ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, diff --git a/tests/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollectorTest.php b/tests/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollectorTest.php index 545f14e8..2a010af1 100644 --- a/tests/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollectorTest.php +++ b/tests/Lib/PhpProcessReader/PhpMemoryReader/MemoryLocationsCollectorTest.php @@ -20,6 +20,7 @@ use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings; use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\Elf64Parser; +use Reli\Lib\Elf\Process\LinkMapLoader; use Reli\Lib\Elf\Process\PerBinarySymbolCacheRetriever; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolverCreator; @@ -114,7 +115,6 @@ public function wait($input): void { $this->assertSame("a\n", $s); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -124,9 +124,13 @@ public function wait($input): void { ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ) ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, @@ -355,7 +359,6 @@ function f() { $error_json = fgets($pipes[1]); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -365,9 +368,13 @@ function f() { ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ), ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, @@ -503,7 +510,6 @@ public function f() { $error_json = fgets($pipes[1]); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -513,9 +519,13 @@ public function f() { ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ), ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, @@ -665,7 +675,6 @@ public function f() { $error_json = fgets($pipes[1]); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -675,9 +684,13 @@ public function f() { ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ), ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator, diff --git a/tests/Lib/PhpProcessReader/PhpVersionDetectorTest.php b/tests/Lib/PhpProcessReader/PhpVersionDetectorTest.php index 091824d7..41639a26 100644 --- a/tests/Lib/PhpProcessReader/PhpVersionDetectorTest.php +++ b/tests/Lib/PhpProcessReader/PhpVersionDetectorTest.php @@ -17,6 +17,7 @@ use Reli\Inspector\Settings\TargetPhpSettings\TargetPhpSettings; use Reli\Lib\ByteStream\IntegerByteSequence\LittleEndianReader; use Reli\Lib\Elf\Parser\Elf64Parser; +use Reli\Lib\Elf\Process\LinkMapLoader; use Reli\Lib\Elf\Process\PerBinarySymbolCacheRetriever; use Reli\Lib\Elf\Process\ProcessModuleSymbolReaderCreator; use Reli\Lib\Elf\SymbolResolver\Elf64SymbolResolverCreator; @@ -48,7 +49,6 @@ public function testDetectVersion() fgets($pipes[1]); $child_status = proc_get_status($this->child); $php_symbol_reader_creator = new PhpSymbolReaderCreator( - $memory_reader, new ProcessModuleSymbolReaderCreator( new Elf64SymbolResolverCreator( new CatFileReader(), @@ -58,9 +58,13 @@ public function testDetectVersion() ), $memory_reader, new PerBinarySymbolCacheRetriever(), + new LittleEndianReader(), + new LinkMapLoader( + $memory_reader, + new LittleEndianReader() + ) ), ProcessMemoryMapCreator::create(), - new LittleEndianReader() ); $php_globals_finder = new PhpGlobalsFinder( $php_symbol_reader_creator,