Merge pull request #1414 from YaLTeR/fix-elf-symbols

Fix image and symbol resolution on AerynOS and elsewhere
This commit is contained in:
Bartosz Taudul
2026-06-26 14:19:08 +02:00
committed by GitHub
2 changed files with 158 additions and 81 deletions

View File

@@ -237,9 +237,18 @@ private:
if( cache->ContainsImage( startAddress ) ) return 0;
const uint32_t headerCount = info->dlpi_phnum;
assert( headerCount > 0);
const auto endAddress = static_cast<uint64_t>( info->dlpi_addr +
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr + info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz);
assert( headerCount > 0 );
// headers aren't guaranteed to be in address order; find the max
uint64_t endAddress = startAddress;
for( uint32_t i=0; i<headerCount; i++ )
{
const auto& phdr = info->dlpi_phdr[i];
if( phdr.p_type != PT_LOAD ) continue;
const auto phdrEnd = static_cast<uint64_t>( info->dlpi_addr + phdr.p_vaddr + phdr.p_memsz );
endAddress = std::max( phdrEnd, endAddress );
}
ImageEntry image{};
image.m_startAddress = startAddress;

View File

@@ -4356,15 +4356,17 @@ elf_zstd_unpack_seq_decode (int mode,
return 1;
}
/* Decompress a zstd stream from PIN/SIN to POUT/SOUT. Code based on RFC 8878.
/* Decompress a single zstd frame from *PPIN, ending at PINEND, to *PPOUT/SOUT.
Return 1 on success, 0 on error. */
static int
elf_zstd_decompress (const unsigned char *pin, size_t sin,
unsigned char *zdebug_table, unsigned char *pout,
size_t sout)
elf_zstd_decompress_frame (const unsigned char **ppin,
const unsigned char *pinend,
unsigned char *zdebug_table, unsigned char **ppout,
size_t sout)
{
const unsigned char *pinend;
const unsigned char *pin;
unsigned char *pout;
unsigned char *poutstart;
unsigned char *poutend;
struct elf_zstd_seq_decode literal_decode;
@@ -4380,13 +4382,14 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
uint32_t repeated_offset3;
uint16_t *scratch;
unsigned char hdr;
int single_segment;
int has_checksum;
uint64_t content_size;
int last_block;
pinend = pin + sin;
pin = *ppin;
pout = *ppout;
poutstart = pout;
poutend = pout + sout;
literal_decode.table = NULL;
literal_decode.table_bits = -1;
@@ -4412,7 +4415,7 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
repeated_offset2 = 4;
repeated_offset3 = 8;
if (unlikely (sin < 4))
if (unlikely (pinend - pin < 4))
{
elf_uncompress_failed ();
return 0;
@@ -4438,12 +4441,18 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
hdr = *pin++;
/* We expect a single frame. */
if (unlikely ((hdr & (1 << 5)) == 0))
single_segment = (hdr & (1 << 5)) != 0;
if (!single_segment)
{
elf_uncompress_failed ();
return 0;
if (unlikely (pin >= pinend))
{
elf_uncompress_failed ();
return 0;
}
/* skip Window_Descriptor */
pin++;
}
/* Reserved bit must be zero. */
if (unlikely ((hdr & (1 << 3)) != 0))
{
@@ -4460,13 +4469,22 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
switch (hdr >> 6)
{
case 0:
if (unlikely (pin >= pinend))
{
elf_uncompress_failed ();
return 0;
}
content_size = (uint64_t) *pin++;
break;
if (single_segment)
{
if (unlikely (pin >= pinend))
{
elf_uncompress_failed ();
return 0;
}
content_size = (uint64_t) *pin++;
break;
}
else
{
/* no Frame_Content_Size; use the remaining size as the upper bound */
content_size = (uint64_t) sout;
break;
}
case 1:
if (unlikely (pin + 1 >= pinend))
{
@@ -4510,12 +4528,14 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
}
if (unlikely (content_size != (size_t) content_size
|| (size_t) content_size != sout))
|| (size_t) content_size > sout))
{
elf_uncompress_failed ();
return 0;
}
poutend = pout + content_size;
last_block = 0;
while (!last_block)
{
@@ -4634,6 +4654,11 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
pin += 2;
}
pback = NULL;
bits = 0;
literal_state = 0;
offset_state = 0;
match_state = 0;
if (seq_count > 0)
{
int (*pfn)(const struct elf_zstd_fse_entry *,
@@ -4673,28 +4698,28 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
match_fse_table, 9, pfn,
&match_decode))
return 0;
pback = pblockend - 1;
if (!elf_fetch_backward_init (&pback, pin, &val, &bits))
return 0;
bits -= literal_decode.table_bits;
literal_state = ((val >> bits)
& ((1U << literal_decode.table_bits) - 1));
if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
return 0;
bits -= offset_decode.table_bits;
offset_state = ((val >> bits)
& ((1U << offset_decode.table_bits) - 1));
if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
return 0;
bits -= match_decode.table_bits;
match_state = ((val >> bits)
& ((1U << match_decode.table_bits) - 1));
}
pback = pblockend - 1;
if (!elf_fetch_backward_init (&pback, pin, &val, &bits))
return 0;
bits -= literal_decode.table_bits;
literal_state = ((val >> bits)
& ((1U << literal_decode.table_bits) - 1));
if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
return 0;
bits -= offset_decode.table_bits;
offset_state = ((val >> bits)
& ((1U << offset_decode.table_bits) - 1));
if (!elf_fetch_bits_backward (&pback, pin, &val, &bits))
return 0;
bits -= match_decode.table_bits;
match_state = ((val >> bits)
& ((1U << match_decode.table_bits) - 1));
seq = 0;
while (1)
{
@@ -4715,6 +4740,40 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
uint32_t need;
uint32_t add;
if (unlikely (seq >= seq_count))
{
/* Copy remaining literals. */
if (literal_count > 0 && plit != pout)
{
if (unlikely ((size_t)(poutend - pout)
< literal_count))
{
elf_uncompress_failed ();
return 0;
}
if ((size_t)(plit - pout) < literal_count)
{
uint32_t move;
move = plit - pout;
while (literal_count > move)
{
memcpy (pout, plit, move);
pout += move;
plit += move;
literal_count -= move;
}
}
memcpy (pout, plit, literal_count);
}
pout += literal_count;
break;
}
pt = &offset_decode.table[offset_state];
offset_basebits = pt->basebits;
offset_baseline = pt->baseline;
@@ -4952,40 +5011,6 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
}
}
}
if (unlikely (seq >= seq_count))
{
/* Copy remaining literals. */
if (literal_count > 0 && plit != pout)
{
if (unlikely ((size_t)(poutend - pout)
< literal_count))
{
elf_uncompress_failed ();
return 0;
}
if ((size_t)(plit - pout) < literal_count)
{
uint32_t move;
move = plit - pout;
while (literal_count > move)
{
memcpy (pout, plit, move);
pout += move;
plit += move;
literal_count -= move;
}
}
memcpy (pout, plit, literal_count);
}
pout += literal_count;
break;
}
}
pin = pblockend;
@@ -5014,7 +5039,42 @@ elf_zstd_decompress (const unsigned char *pin, size_t sin,
pin += 4;
}
if (pin != pinend)
*ppin = pin;
*ppout = pout;
return 1;
}
/* Decompress a zstd stream from PIN/SIN to POUT/SOUT. Code based on RFC 8878.
Return 1 on success, 0 on error. */
static int
elf_zstd_decompress (const unsigned char *pin, size_t sin,
unsigned char *zdebug_table, unsigned char *pout,
size_t sout)
{
const unsigned char *pinend;
pinend = pin + sin;
while (sin > 0)
{
const unsigned char *pin_frame;
unsigned char *pout_frame;
pin_frame = pin;
pout_frame = pout;
if (!elf_zstd_decompress_frame (&pin_frame, pinend, zdebug_table,
&pout_frame, sout))
return 0;
sin -= pin_frame - pin;
pin = pin_frame;
sout -= pout_frame - pout;
pout = pout_frame;
}
if (sout > 0)
{
elf_uncompress_failed ();
return 0;
@@ -7410,9 +7470,17 @@ phdr_callback_mock (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
ptr->dlpi_addr = info->dlpi_addr;
// calculate the end address as well, so we can quickly determine if a PC is within the range of this image
ptr->dlpi_end_addr = uintptr_t(info->dlpi_addr) + (info->dlpi_phnum ? uintptr_t(
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr +
info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz) : 0);
// headers aren't guaranteed to be in address order; find the max
ptr->dlpi_end_addr = uintptr_t(info->dlpi_addr);
for (uint32_t i = 0; i < info->dlpi_phnum; i++)
{
const auto &phdr = info->dlpi_phdr[i];
if (phdr.p_type != PT_LOAD)
continue;
const auto phdr_end = uintptr_t(info->dlpi_addr + phdr.p_vaddr + phdr.p_memsz);
ptr->dlpi_end_addr = std::max(phdr_end, ptr->dlpi_end_addr);
}
return 0;
}