Add an API to read external target memory.

ReadExternalTargetMemory reads bytes out of the target's address space:
process_vm_readv for live bytes (gated like ptrace access), falling back
to the target's on-disk image located by scanning /proc/<pid>/maps
directly - the caller runs while the symbol thread may be rebuilding the
shared image cache on refresh.
This commit is contained in:
Bartosz Taudul
2026-08-30 16:16:57 +02:00
parent 1f1d3ab856
commit d8a011630d
2 changed files with 71 additions and 0 deletions

View File

@@ -351,6 +351,7 @@ void DestroyImageCaches()
# include <fcntl.h>
# include <signal.h>
# include <sys/stat.h>
# include <sys/uio.h>
# include <unistd.h>
static constexpr uint32_t ExtPT_LOAD = 1;
@@ -702,6 +703,74 @@ uint64_t GetExternalTargetExeTime()
return s_externalTargetExeMtime;
}
static bool FindExternalMapping( pid_t pid, uint64_t addr, uint64_t& mapStart, uint64_t& mapEnd, uint64_t& fileOff, char* path, size_t pathSize )
{
char mapPath[64];
snprintf( mapPath, sizeof( mapPath ), "/proc/%d/maps", (int)pid );
FILE* f = fopen( mapPath, "r" );
if( !f ) return false;
bool found = false;
char line[1024];
while( fgets( line, sizeof( line ), f ) )
{
uint64_t start, end, offset;
uint32_t devMaj, devMin;
uint64_t inode;
char perms[8];
int consumed = 0;
if( sscanf( line, "%lx-%lx %7s %lx %x:%x %lu %n", &start, &end, perms, &offset, &devMaj, &devMin, &inode, &consumed ) < 7 ) continue;
if( !strchr( perms, 'x' ) ) continue;
if( addr < start || addr >= end ) continue;
char* pathname = line + consumed;
while( *pathname == ' ' || *pathname == '\t' ) pathname++;
size_t plen = strlen( pathname );
while( plen > 0 && ( pathname[plen-1] == '\n' || pathname[plen-1] == '\r' ) ) plen--;
pathname[plen] = '\0';
if( plen >= 10 && strncmp( pathname + plen - 10, " (deleted)", 10 ) == 0 ) plen -= 10;
if( plen == 0 || pathname[0] != '/' ) continue;
if( plen >= pathSize ) plen = pathSize - 1;
memcpy( path, pathname, plen );
path[plen] = '\0';
mapStart = start;
mapEnd = end;
fileOff = offset + ( addr - start );
found = true;
break;
}
fclose( f );
return found;
}
size_t ReadExternalTargetMemory( uint64_t addr, uint32_t size, char* buf )
{
const auto pid = (pid_t)GetExternalTargetPid();
if( pid == 0 || size == 0 ) return 0;
struct iovec local = { buf, size };
struct iovec remote = { (void*)addr, size };
if( process_vm_readv( pid, &local, 1, &remote, 1, 0 ) == (ssize_t)size ) return size;
uint64_t mapStart = 0, mapEnd = 0, fileOff = 0;
char path[1024] = {};
if( FindExternalMapping( pid, addr, mapStart, mapEnd, fileOff, path, sizeof( path ) ) && addr + size <= mapEnd )
{
const int fd = OpenExternalImageFile( path, mapStart, mapEnd );
if( fd >= 0 )
{
const ssize_t rd = pread( fd, buf, size, (off_t)fileOff );
close( fd );
if( rd == (ssize_t)size ) return size;
}
}
return 0;
}
#endif // __linux__

View File

@@ -93,6 +93,8 @@ bool InitExternalTarget( pid_t targetPid );
uint32_t GetExternalTargetPid();
const char* GetExternalTargetName();
uint64_t GetExternalTargetExeTime();
size_t ReadExternalTargetMemory( uint64_t addr, uint32_t size, char* buf );
#endif
#ifdef TRACY_DEBUGINFOD