static void elf_file_read_elf_header(struct elf_file_t *elf_file) { struct elf_buffer_t *buffer; Elf32_Ehdr *elf_header; int count; /* Read ELF header */ buffer = &elf_file->buffer; elf_file->header = buffer->ptr; elf_header = elf_file->header; count = elf_buffer_read(buffer, NULL, sizeof(Elf32_Ehdr)); if (count < EI_NIDENT) fatal("%s: not a valid ELF file\n", elf_file->path); /* Check magic characters */ if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' || elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') fatal("%s: not a valid ELF file\n", elf_file->path); /* Check for 32-bit executable (field e_ident[EI_CLASS]) */ if (elf_header->e_ident[4] == 2) fatal("%s: not supported architecture.\n%s", elf_file->path, elf_err_64bit); /* Check that header size is correct */ if (elf_header->e_ehsize != sizeof(Elf32_Ehdr)) fatal("%s: invalid ELF header size", elf_file->path); /* Check endianness */ if (elf_header->e_ident[5] != 1) fatal("%s: ELF file endianness mismatch", elf_file->path); }
/* Read a line from 'buffer'. * The line is placed in 'str', which is a buffer of 'size' bytes. * The function returns the number of bytes read. */ int elf_buffer_read_line(struct elf_buffer_t *buffer, char *str, int size) { int read_count = 0; int write_count = 0; for (;;) { /* If only 1 byte left, use it for null termination */ if (size == 1) { *str = '\0'; break; } /* Copy one character */ read_count = elf_buffer_read(buffer, str, 1); if (!read_count) { *str = '\0'; break; } if (*str == '\n' || *str == '\0') { *str = '\0'; break; } /* Advance string */ size--; str++; write_count++; } return write_count; }
static void elf_file_read_program_headers(struct elf_file_t *elf_file) { struct elf_buffer_t *buffer; struct elf_program_header_t *program_header; Elf32_Ehdr *elf_header; int count; int i; /* Create program header list */ buffer = &elf_file->buffer; elf_header = elf_file->header; elf_file->program_header_list = list_create(); if (!elf_header->e_phnum) return; /* Check program header size */ if (elf_header->e_phentsize != sizeof(Elf32_Phdr)) fatal("%s: program header size %d (should be %d)", elf_file->path, elf_header->e_phentsize, (int) sizeof(Elf32_Phdr)); /* Read program headers */ elf_buffer_seek(buffer, elf_header->e_phoff); for (i = 0; i < elf_header->e_phnum; i++) { /* Allocate program header */ program_header = calloc(1, sizeof(struct elf_program_header_t)); program_header->header = elf_buffer_tell(buffer); /* Advance buffer */ count = elf_buffer_read(buffer, NULL, sizeof(Elf32_Phdr)); if (count < sizeof(Elf32_Phdr)) fatal("%s: unexpected end of file while reading program headers", elf_file->path); /* Add program header to list */ list_add(elf_file->program_header_list, program_header); } /* Dump program headers */ elf_debug("Program headers:\n"); elf_debug("idx type offset vaddr paddr filesz memsz flags align\n"); for (i = 0; i < 80; i++) elf_debug("-"); elf_debug("\n"); for (i = 0; i < list_count(elf_file->program_header_list); i++) { program_header = list_get(elf_file->program_header_list, i); elf_debug("%-3d 0x%-8x 0x%-8x 0x%-8x 0x%-8x %-9u %-9u %-6u %u\n", i, program_header->header->p_type, program_header->header->p_offset, program_header->header->p_vaddr, program_header->header->p_paddr, program_header->header->p_filesz, program_header->header->p_memsz, program_header->header->p_flags, program_header->header->p_align); } elf_debug("\n"); }
static void elf_file_read_section_headers(struct elf_file_t *elf_file) { int i, count; struct elf_buffer_t *buffer; struct elf_section_t *section; Elf32_Ehdr *elf_header; /* Create section list */ elf_file->section_list = list_create(); /* Check section size and number */ buffer = &elf_file->buffer; elf_header = elf_file->header; if (!elf_header->e_shnum || elf_header->e_shentsize != sizeof(Elf32_Shdr)) fatal("%s: number of sections is 0 or section size is not %d", elf_file->path, (int) sizeof(Elf32_Shdr)); /* Read section headers */ elf_buffer_seek(buffer, elf_header->e_shoff); for (i = 0; i < elf_header->e_shnum; i++) { /* Allocate section */ section = xcalloc(1, sizeof(struct elf_section_t)); section->header = elf_buffer_tell(buffer); /* Advance buffer */ count = elf_buffer_read(buffer, NULL, sizeof(Elf32_Shdr)); if (count < sizeof(Elf32_Shdr)) fatal("%s: unexpected end of file while reading section headers", elf_file->path); /* Get section contents, if section type is not SHT_NOBITS (8) */ if (section->header->sh_type != 8) { section->buffer.ptr = buffer->ptr + section->header->sh_offset; section->buffer.size = section->header->sh_size; section->buffer.pos = 0; assert(section->buffer.ptr >= buffer->ptr); if (section->buffer.ptr + section->buffer.size > buffer->ptr + buffer->size) fatal("section %d out of the ELF boundaries (offs=0x%x, size=%u, ELF_size=%u)", i, section->header->sh_offset, section->header->sh_size, buffer->size); } /* Add section to list */ list_add(elf_file->section_list, section); } /* Read string table, and update section names */ assert(elf_header->e_shstrndx < elf_header->e_shnum); elf_file->string_table = list_get(elf_file->section_list, elf_header->e_shstrndx); assert(elf_file->string_table->header->sh_type == 3); for (i = 0; i < list_count(elf_file->section_list); i++) { section = list_get(elf_file->section_list, i); section->name = elf_file->string_table->buffer.ptr + section->header->sh_name; } }
static void elf_file_read_elf_header(struct elf_file_t *elf_file) { struct elf_buffer_t *buffer; Elf32_Ehdr *elf_header; int count; /* Read ELF header */ buffer = &elf_file->buffer; elf_file->header = buffer->ptr; elf_header = elf_file->header; count = elf_buffer_read(buffer, NULL, sizeof(Elf32_Ehdr)); if (count < EI_NIDENT) fatal("%s: not a valid ELF file\n", elf_file->path); /* Check magic characters */ if (elf_header->e_ident[0] != 0x7f || elf_header->e_ident[1] != 'E' || elf_header->e_ident[2] != 'L' || elf_header->e_ident[3] != 'F') fatal("%s: not a valid ELF file\n", elf_file->path); /* Check for 32-bit executable (field e_ident[EI_CLASS]) */ if (elf_header->e_ident[4] == 2) fatal("%s: not supported architecture.\n%s", elf_file->path, err_elf_64bit); /* Check that header size is correct */ if (elf_header->e_ehsize != sizeof(Elf32_Ehdr)) fatal("%s: invalid ELF header size", elf_file->path); /* Check endianness */ if (elf_header->e_ident[5] != 1) fatal("%s: ELF file endianness mismatch", elf_file->path); /* Debug */ elf_debug("ELF header:\n"); elf_debug(" ehdr.e_ident: EI_CLASS=%d, EI_DATA=%d, EI_VERSION=%d\n", elf_header->e_ident[4], elf_header->e_ident[5], elf_header->e_ident[6]); elf_debug(" ehdr.e_type: %d\n", elf_header->e_type); elf_debug(" ehdr.e_machine: %u\n", elf_header->e_machine); elf_debug(" ehdr.e_entry: 0x%x (program entry point)\n", elf_header->e_entry); elf_debug(" ehdr.e_phoff: %u (program header table offset)\n", elf_header->e_phoff); elf_debug(" ehdr.e_shoff: %u (section header table offset)\n", elf_header->e_shoff); elf_debug(" ehdr.e_phentsize: %u\n", elf_header->e_phentsize); elf_debug(" ehdr.e_phnum: %u\n", elf_header->e_phnum); elf_debug(" ehdr.e_shentsize: %u\n", elf_header->e_shentsize); elf_debug(" ehdr.e_shnum: %u\n", elf_header->e_shnum); elf_debug(" ehdr.e_shstrndx: %u\n", (uint32_t) elf_header->e_shstrndx); elf_debug("\n"); }
static void elf_file_read_program_headers(struct elf_file_t *elf_file) { struct elf_buffer_t *buffer; struct elf_program_header_t *program_header; Elf32_Ehdr *elf_header; int count; int i; /* Create program header list */ buffer = &elf_file->buffer; elf_header = elf_file->header; elf_file->program_header_list = list_create(); if (!elf_header->e_phnum) return; /* Check program header size */ if (elf_header->e_phentsize != sizeof(Elf32_Phdr)) fatal("%s: program header size %d (should be %d)", elf_file->path, elf_header->e_phentsize, (int) sizeof(Elf32_Phdr)); /* Read program headers */ elf_buffer_seek(buffer, elf_header->e_phoff); for (i = 0; i < elf_header->e_phnum; i++) { /* Allocate program header */ program_header = xcalloc(1, sizeof(struct elf_program_header_t)); program_header->header = elf_buffer_tell(buffer); /* Advance buffer */ count = elf_buffer_read(buffer, NULL, sizeof(Elf32_Phdr)); if (count < sizeof(Elf32_Phdr)) fatal("%s: unexpected end of file while reading program headers", elf_file->path); /* Add program header to list */ list_add(elf_file->program_header_list, program_header); } }
static void si_bin_file_read_enc_dict(struct si_bin_file_t *bin_file) { struct elf_file_t *elf_file; struct elf_buffer_t *buffer; Elf32_Ehdr *elf_header; struct elf_program_header_t *program_header; struct si_bin_enc_dict_entry_t *enc_dict_entry; struct si_bin_enc_dict_entry_header_t *enc_dict_entry_header; int enc_dict_entry_count; int i; /* ELF header */ elf_file = bin_file->elf_file; elf_header = elf_file->header; buffer = &elf_file->buffer; elf_debug("**\n** Parsing AMD Binary (Internal ELF file)\n** %s\n**\n\n", elf_file->path); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_CLASS], ELFCLASS32); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_DATA], ELFDATA2LSB); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_OSABI], 0x64); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_ABIVERSION], 1); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_type, ET_EXEC); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_machine, 0x7d); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_entry, 0); /* Look for encoding dictionary (program header with type 'PT_LOPROC+2') */ program_header = NULL; for (i = 0; i < list_count(elf_file->program_header_list); i++) { program_header = list_get(elf_file->program_header_list, i); if (program_header->header->p_type == PT_LOPROC + 2) break; } if (i == list_count(elf_file->program_header_list) || !program_header) fatal("%s: no encoding dictionary", elf_file->path); elf_debug("Encoding dictionary found in program header %d\n", i); /* Parse encoding dictionary */ SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_vaddr, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_paddr, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_memsz, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_flags, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_align, 0); assert(program_header->header->p_filesz % sizeof(struct si_bin_enc_dict_entry_header_t) == 0); enc_dict_entry_count = program_header->header->p_filesz / sizeof(struct si_bin_enc_dict_entry_header_t); elf_debug(" -> %d entries\n\n", enc_dict_entry_count); /* Read encoding dictionary entries */ bin_file->enc_dict = list_create(); elf_buffer_seek(buffer, program_header->header->p_offset); for (i = 0; i < enc_dict_entry_count; i++) { /* Create entry */ enc_dict_entry = calloc(1, sizeof(struct si_bin_enc_dict_entry_t)); enc_dict_entry->header = elf_buffer_tell(buffer); elf_buffer_read(buffer, NULL, sizeof(struct si_bin_enc_dict_entry_header_t)); list_add(bin_file->enc_dict, enc_dict_entry); /* Store encoding dictionary entry for Evergreen (code 9) */ if (enc_dict_entry->header->d_machine == 9) { bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } else if (enc_dict_entry->header->d_machine == 26) { /* Southern Islands has code 26 */ bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } } /* Debug */ elf_debug("idx %-15s %-10s %-10s %-10s %-10s\n", "d_machine", "d_type", "d_offset", "d_size", "d_flags"); for (i = 0; i < 80; i++) elf_debug("-"); elf_debug("\n"); for (i = 0; i < list_count(bin_file->enc_dict); i++) { char machine_str[MAX_STRING_SIZE]; enc_dict_entry = list_get(bin_file->enc_dict, i); enc_dict_entry_header = enc_dict_entry->header; snprintf(machine_str, sizeof(machine_str), "%d (%s)", enc_dict_entry_header->d_machine, map_value(&enc_dict_machine_map, enc_dict_entry_header->d_machine - 1)); elf_debug("%3d %-15s 0x%-8x 0x%-8x %-10d 0x%-8x\n", i, machine_str, enc_dict_entry_header->d_type, enc_dict_entry_header->d_offset, enc_dict_entry_header->d_size, enc_dict_entry_header->d_flags); } elf_debug("\n\n"); }
/* Read next note at the current position of the PT_NOTE segment */ static void si_bin_file_read_note_header(struct si_bin_file_t *bin_file, struct si_bin_enc_dict_entry_t *enc_dict_entry) { struct elf_buffer_t *buffer; struct pt_note_header_t *header; void *desc; int count; char *note_type_str; /* Read note header */ buffer = &enc_dict_entry->pt_note_buffer; header = elf_buffer_tell(buffer); count = elf_buffer_read(buffer, NULL, sizeof(struct pt_note_header_t)); if (count < sizeof(struct pt_note_header_t)) fatal("%s: error decoding note header", bin_file->elf_file->path); /* Read note description (payload) */ desc = elf_buffer_tell(buffer); count = elf_buffer_read(buffer, NULL, header->descsz); if (count < header->descsz) fatal("%s: error decoding note description", bin_file->elf_file->path); /* Debug */ note_type_str = map_value(&pt_note_type_map, header->type); elf_debug(" note: type=%d (%s), descsz=%d\n", header->type, note_type_str, header->descsz); /* Analyze note */ switch (header->type) { case 1: /* ELF_NOTE_ATI_PROGINFO */ { int prog_info_count; struct pt_note_prog_info_entry_t *prog_info_entry; int i; /* Get number of entries */ assert(header->descsz % sizeof(struct pt_note_prog_info_entry_t) == 0); prog_info_count = header->descsz / sizeof(struct pt_note_prog_info_entry_t); elf_debug("\tnote including device configuration unique to the program (%d entries)\n", prog_info_count); /* Decode entries */ for (i = 0; i < prog_info_count; i++) { prog_info_entry = desc + i * sizeof(struct pt_note_prog_info_entry_t); elf_debug("\tprog_info_entry: addr=0x%x (%s), value=%u\n", prog_info_entry->address, map_value(&prog_info_entry_map, prog_info_entry->address), prog_info_entry->value); /* Analyze entry */ switch (prog_info_entry->address) { case 0x00002e13: /* COMPUTE_PGM_RSRC2 */ enc_dict_entry->compute_pgm_rsrc2 = (struct si_bin_compute_pgm_rsrc2_t*)&prog_info_entry->value; break; case 0x80000080: /* AMU_ABI_NUM_GPR_USED */ enc_dict_entry->num_gpr_used = prog_info_entry->value; break; case 0x80000082: /* AMU_ABI_LDS_SIZE_USED */ enc_dict_entry->lds_size_used = prog_info_entry->value; break; case 0x80000084: /* AMU_ABI_STACK_SIZE_USED */ enc_dict_entry->stack_size_used = prog_info_entry->value; break; case 0x80001000: /* AMU_ABI_USER_ELEMENT_COUNT */ enc_dict_entry->userElementCount = prog_info_entry->value; i++; /* Analyze user elements */ for(int j = 0; j < 4 * enc_dict_entry->userElementCount; j++) { prog_info_entry = desc + i * sizeof(struct pt_note_prog_info_entry_t); elf_debug("\tprog_info_entry: addr=0x%x (%s), value=%u\n", prog_info_entry->address, map_value(&prog_info_entry_map, prog_info_entry->address), prog_info_entry->value); switch(j % 4) { case 0: enc_dict_entry->userElements[j / 4].dataClass = prog_info_entry->value; break; case 1: enc_dict_entry->userElements[j / 4].apiSlot = prog_info_entry->value; break; case 2: enc_dict_entry->userElements[j / 4].startUserReg = prog_info_entry->value; break; case 3: enc_dict_entry->userElements[j / 4].userRegCount = prog_info_entry->value; break; } i++; } break; } } break; } case 2: /* ELF_NOTE_ATI_INPUTS */ { /* FIXME: Analyze program inputs */ if (header->descsz) warning("%s: pt_note '%s' with descsz != 0 ignored (desc value = 0x%x)", note_type_str, __FUNCTION__, * (unsigned int *) desc); break; } case 3: /* ELF_NOTE_ATI_OUTPUTS */ { /* FIXME: Analyze program inputs */ if (header->descsz) warning("%s: pt_note '%s' with descsz != 0 ignored (desc value = 0x%x)", note_type_str, __FUNCTION__, * (unsigned int *) desc); break; } case 4: /* ELF_NOTE_ATI_CONDOUT */ break; case 5: /* ELF_NOTE_ATI_FLOAT32CONSTS */ case 6: /* ELF_NOTE_ATI_INT32CONSTS */ case 7: /* ELF_NOTE_ATI_BOOL32CONSTS */ { int data_segment_desc_count; struct pt_note_data_segment_desc_t *data_segment_desc; struct si_bin_enc_dict_entry_consts_t *consts; char const_value[MAX_STRING_SIZE]; int j; /* Get number of entries */ consts = enc_dict_entry->consts; assert(header->descsz % sizeof(struct pt_note_data_segment_desc_t) == 0); data_segment_desc_count = header->descsz / sizeof(struct pt_note_data_segment_desc_t); elf_debug("\tnote including data for constant buffers (%d entries)\n", data_segment_desc_count); /* Decode entries */ for (j = 0; j < data_segment_desc_count; j++) { data_segment_desc = desc + j * sizeof(struct pt_note_data_segment_desc_t); if (header->type == 5) snprintf(const_value, sizeof(const_value), "{%g,%g,%g,%g}", consts->float_consts[data_segment_desc->offset][0], consts->float_consts[data_segment_desc->offset][1], consts->float_consts[data_segment_desc->offset][2], consts->float_consts[data_segment_desc->offset][3]); else if (header->type == 6) snprintf(const_value, sizeof(const_value), "{%u,%u,%u,%u}", consts->int_consts[data_segment_desc->offset][0], consts->int_consts[data_segment_desc->offset][1], consts->int_consts[data_segment_desc->offset][2], consts->int_consts[data_segment_desc->offset][3]); else snprintf(const_value, sizeof(const_value), "%d", consts->bool_consts[data_segment_desc->offset]); elf_debug("\tdata_segment_desc[%d]: offset=0x%x, size=%d, value=%s\n", j, data_segment_desc->offset, data_segment_desc->size, const_value); } break; } case 8: /* ELF_NOTE_ATI_EARLYEXIT */ { Elf32_Word early_exit; /* Get 'early_exit' value */ early_exit = header->descsz ? * (uint32_t *) desc : 0; elf_debug("\tearly_exit = %s\n", early_exit ? "TRUE" : "FALSE"); break; } case 9: /* ELF_NOTE_ATI_GLOBAL_BUFFERS */ { Elf32_Word global_buffers; global_buffers = header->descsz ? * (uint32_t *) desc : 0; elf_debug("\tglobal_buffers = %s\n", global_buffers ? "TRUE" : "FALSE"); break; } case 10: /* ELF_NOTE_ATI_CONSTANT_BUFFERS */ { int constant_buffer_count; struct pt_note_constant_buffer_mask_t *constant_buffer_mask; int i; /* Get number of entries */ assert(header->descsz % sizeof(struct pt_note_constant_buffer_mask_t) == 0); constant_buffer_count = header->descsz / sizeof(struct pt_note_constant_buffer_mask_t); elf_debug("\tnote including number and size of constant buffers (%d entries)\n", constant_buffer_count); /* Decode entries */ for (i = 0; i < constant_buffer_count; i++) { constant_buffer_mask = desc + i * sizeof(struct pt_note_constant_buffer_mask_t); elf_debug("\tconstant_buffer[%d].size = %d (vec4f constants)\n", constant_buffer_mask->index, constant_buffer_mask->size); } break; } case 11: /* ELF_NOTE_ATI_INPUT_SAMPLERS */ break; case 12: /* ELF_NOTE_ATI_PERSISTENT_BUFFERS */ { Elf32_Word persistent_buffers; persistent_buffers = header->descsz ? * (uint32_t *) desc : 0; elf_debug("\tpersistent_buffers = %s\n", persistent_buffers ? "TRUE" : "FALSE"); break; } case 13: /* ELF_NOTE_ATI_SCRATCH_BUFFERS */ { Elf32_Word scratch_buffers; scratch_buffers = header->descsz ? * (uint32_t *) desc : 0; elf_debug("\tscratch_buffers = %s\n", scratch_buffers ? "TRUE" : "FALSE"); break; } case 14: /* ELF_NOTE_ATI_SUB_CONSTANT_BUFFERS */ break; case 15: /* ELF_NOTE_ATI_UAV_MAILBOX_SIZE */ break; case 16: /* ELF_NOTE_ATI_UAV */ { int uav_entry_count; struct pt_note_uav_entry_t *uav_entry; int i; assert(header->descsz % sizeof(struct pt_note_uav_entry_t) == 0); uav_entry_count = header->descsz / sizeof(struct pt_note_uav_entry_t); elf_debug("\tnote (%d entries)\n", uav_entry_count); /* Decode entries */ for (i = 0; i < uav_entry_count; i++) { uav_entry = desc + i * sizeof(struct pt_note_uav_entry_t); elf_debug("\tuav_entry[%d].uav = %d [%d, %d, %d]\n", i, uav_entry->id, uav_entry->unknown1, uav_entry->unknown2, uav_entry->unknown3); } break; } case 17: /* ELF_NOTE_ATI_UAV_OP_MASK */ break; default: elf_debug("\tunknown type\n"); } }
static void si_bin_file_read_enc_dict(struct si_bin_file_t *bin_file) { struct elf_file_t *elf_file; struct elf_buffer_t *buffer; Elf32_Ehdr *elf_header; struct elf_program_header_t *program_header; struct si_bin_enc_dict_entry_t *enc_dict_entry; struct si_bin_enc_dict_entry_header_t *enc_dict_entry_header; int enc_dict_entry_count; int i; /* ELF header */ elf_file = bin_file->elf_file; elf_header = elf_file->header; buffer = &elf_file->buffer; elf_debug("**\n** Parsing AMD Binary (Internal ELF file)\n** %s\n**\n\n", elf_file->path); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_CLASS], ELFCLASS32); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_DATA], ELFDATA2LSB); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_OSABI], 0x64); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_ident[EI_ABIVERSION], 1); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_type, ET_EXEC); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_machine, 0x7d); SI_BIN_FILE_NOT_SUPPORTED_NEQ(elf_header->e_entry, 0); /* Look for encoding dictionary (program header with type 'PT_LOPROC+2') */ program_header = NULL; for (i = 0; i < list_count(elf_file->program_header_list); i++) { program_header = list_get(elf_file->program_header_list, i); if (program_header->header->p_type == PT_LOPROC + 2) break; } if (i == list_count(elf_file->program_header_list) || !program_header) fatal("%s: no encoding dictionary", elf_file->path); elf_debug("Encoding dictionary found in program header %d\n", i); /* Parse encoding dictionary */ SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_vaddr, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_paddr, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_memsz, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_flags, 0); SI_BIN_FILE_NOT_SUPPORTED_NEQ(program_header->header->p_align, 0); assert(program_header->header->p_filesz % sizeof(struct si_bin_enc_dict_entry_header_t) == 0); enc_dict_entry_count = program_header->header->p_filesz / sizeof(struct si_bin_enc_dict_entry_header_t); elf_debug(" -> %d entries\n\n", enc_dict_entry_count); /* Read encoding dictionary entries */ bin_file->enc_dict = list_create(); elf_buffer_seek(buffer, program_header->header->p_offset); for (i = 0; i < enc_dict_entry_count; i++) { /* Create entry */ enc_dict_entry = xcalloc(1, sizeof(struct si_bin_enc_dict_entry_t)); enc_dict_entry->header = elf_buffer_tell(buffer); elf_buffer_read(buffer, NULL, sizeof(struct si_bin_enc_dict_entry_header_t)); list_add(bin_file->enc_dict, enc_dict_entry); /* Store encoding dictionary entry for Southern Islands. * Apparently the valid code changes by driver version */ if (enc_dict_entry->header->d_machine == 9) { /* Driver XXX */ elf_debug("machine = %d (tahiti or pitcairn)\n", enc_dict_entry->header->d_machine); bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } else if (enc_dict_entry->header->d_machine == 25) { /* This entry is always present but doesn't seem * useful information. We should probably figure * out what is stored here. */ elf_debug("machine = 25 (skip this entry)\n"); } else if (enc_dict_entry->header->d_machine == 26) { /* Driver XXX */ elf_debug("machine = %d (tahiti or pitcairn)\n", enc_dict_entry->header->d_machine); bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } else if (enc_dict_entry->header->d_machine == 27) { /* Driver 12.4 */ elf_debug("machine = %d (tahiti or pitcairn)\n", enc_dict_entry->header->d_machine); bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } else if (enc_dict_entry->header->d_machine == 28) { elf_debug("machine = %d (capeverde)\n", enc_dict_entry->header->d_machine); bin_file->enc_dict_entry_southern_islands = enc_dict_entry; } else { fatal("%s: unknown machine number (%d)\n", __FUNCTION__, enc_dict_entry->header->d_machine); } } /* Debug */ elf_debug("idx %-15s %-10s %-10s %-10s %-10s\n", "d_machine", "d_type", "d_offset", "d_size", "d_flags"); for (i = 0; i < 80; i++) elf_debug("-"); elf_debug("\n"); for (i = 0; i < list_count(bin_file->enc_dict); i++) { char machine_str[MAX_STRING_SIZE]; enc_dict_entry = list_get(bin_file->enc_dict, i); enc_dict_entry_header = enc_dict_entry->header; snprintf(machine_str, sizeof(machine_str), "%d (%s)", enc_dict_entry_header->d_machine, str_map_value(&enc_dict_machine_map, enc_dict_entry_header->d_machine - 1)); elf_debug("%3d %-15s 0x%-8x 0x%-8x %-10d 0x%-8x\n", i, machine_str, enc_dict_entry_header->d_type, enc_dict_entry_header->d_offset, enc_dict_entry_header->d_size, enc_dict_entry_header->d_flags); } elf_debug("\n\n"); }
struct cuda_function_t *cuda_function_create(struct cuda_module_t *module, char *func_name) { struct cuda_function_t *function; struct elf_file_t *cubin; struct elf_section_t *sec; struct elf_section_t *func_text_sec; struct elf_section_t *func_info_sec; char func_text_sec_name[MAX_STRING_SIZE]; char func_info_sec_name[MAX_STRING_SIZE]; unsigned char inst_bin_byte; char arg_name[MAX_STRING_SIZE]; int i; /* Allocate */ function = xcalloc(1, sizeof(struct cuda_function_t)); /* Initialization */ function->id = list_count(function_list); function->name = xstrdup(func_name); function->module_id = module->id; /* Get cubin */ cubin = module->elf_file; /* Get .text.kernel_name section */ snprintf(func_text_sec_name, sizeof func_text_sec_name, ".text.%s", func_name); for (i = 0; i < list_count(cubin->section_list); ++i) { sec = list_get(cubin->section_list, i); if (!strncmp(sec->name, func_text_sec_name, strlen(func_text_sec_name))) { func_text_sec = list_get(cubin->section_list, i); break; } } assert(i < list_count(cubin->section_list)); /* Get instruction binary */ function->inst_bin_size = func_text_sec->header->sh_size; function->inst_bin = xcalloc(1, function->inst_bin_size); for (i = 0; i < function->inst_bin_size; ++i) { elf_buffer_seek(&(cubin->buffer), func_text_sec->header->sh_offset + i); elf_buffer_read(&(cubin->buffer), &inst_bin_byte, 1); if (i % 8 == 0 || i % 8 == 1 || i % 8 == 2 || i % 8 == 3) { function->inst_bin[i / 8] |= (unsigned long long int)(inst_bin_byte) << (i * 8 + 32); } else { function->inst_bin[i / 8] |= (unsigned long long int)(inst_bin_byte) << (i * 8 - 32); } } /* Get GPR usage */ function->num_gpr = func_text_sec->header->sh_info >> 24; /* Get .nv.info.kernel_name section */ snprintf(func_info_sec_name, MAX_STRING_SIZE, ".nv.info.%s", function->name); for (i = 0; i < list_count(cubin->section_list); ++i) { sec = list_get(cubin->section_list, i); if (!strncmp(sec->name, func_info_sec_name, strlen(func_info_sec_name))) { func_info_sec = list_get(cubin->section_list, i); break; } } assert(i < list_count(cubin->section_list)); /* Get the number of arguments */ function->arg_count = ((unsigned char *)func_info_sec->buffer.ptr)[10] / 4; /* Create arguments */ function->arg_array = xcalloc(function->arg_count, sizeof(struct cuda_function_arg_t *)); for (i = 0; i < function->arg_count; ++i) { snprintf(arg_name, MAX_STRING_SIZE, "arg_%d", i); function->arg_array[i] = cuda_function_arg_create(arg_name); } /* Add function to function list */ list_add(function_list, function); return function; }