in kernel/unwind.c [253:357]
static void init_unwind_hdr(struct unwind_table *table,
void *(*alloc) (unsigned long))
{
const u8 *ptr;
unsigned long tableSize = table->size, hdrSize;
unsigned int n;
const u32 *fde;
struct {
u8 version;
u8 eh_frame_ptr_enc;
u8 fde_count_enc;
u8 table_enc;
unsigned long eh_frame_ptr;
unsigned int fde_count;
struct eh_frame_hdr_table_entry table[];
} __attribute__ ((__packed__)) *header;
if (table->header)
return;
if (table->hdrsz)
pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
table->name);
if (tableSize & (sizeof(*fde) - 1))
return;
for (fde = table->address, n = 0;
tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
const u32 *cie = cie_for_fde(fde, table);
signed ptrType;
if (cie == ¬_fde)
continue;
if (cie == NULL || cie == &bad_cie)
goto ret_err;
ptrType = fde_pointer_type(cie);
if (ptrType < 0)
goto ret_err;
ptr = (const u8 *)(fde + 2);
if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
ptrType)) {
/* FIXME_Rajesh We have 4 instances of null addresses
* instead of the initial loc addr
* return;
*/
WARN(1, "unwinder: FDE->initial_location NULL %p\n",
(const u8 *)(fde + 1) + *fde);
}
++n;
}
if (tableSize || !n)
goto ret_err;
hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
+ 2 * n * sizeof(unsigned long);
header = alloc(hdrSize);
if (!header)
goto ret_err;
header->version = 1;
header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
% __alignof(typeof(header->fde_count)));
header->fde_count = n;
BUILD_BUG_ON(offsetof(typeof(*header), table)
% __alignof(typeof(*header->table)));
for (fde = table->address, tableSize = table->size, n = 0;
tableSize;
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
const u32 *cie = __cie_for_fde(fde);
if (fde[1] == CIE_ID)
continue; /* this is a CIE */
ptr = (const u8 *)(fde + 2);
header->table[n].start = read_pointer(&ptr,
(const u8 *)(fde + 1) +
*fde,
fde_pointer_type(cie));
header->table[n].fde = (unsigned long)fde;
++n;
}
WARN_ON(n != header->fde_count);
sort(header->table,
n,
sizeof(*header->table),
cmp_eh_frame_hdr_table_entries, swap_eh_frame_hdr_table_entries);
table->hdrsz = hdrSize;
smp_wmb();
table->header = (const void *)header;
return;
ret_err:
panic("Attention !!! Dwarf FDE parsing errors\n");
}