/***************************************************************/ /* perk: PE Resource Kit */ /* Copyright (C) 2015--2025 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.PERK. */ /***************************************************************/ #include #include #include #include #include #include #include #include "perk_reader_impl.h" #include "perk_driver_impl.h" #include "perk_dprintf_impl.h" #include "perk_errinfo_impl.h" #define PPRIX64 "%"PRIx64 static const char * pe_sym_type_desc_msb[0x10] = { [PE_IMAGE_SYM_DTYPE_NULL] = "scalar variable, ", [PE_IMAGE_SYM_DTYPE_POINTER] = "pointer to ", [PE_IMAGE_SYM_DTYPE_FUNCTION] = "function returning ", [PE_IMAGE_SYM_DTYPE_ARRAY] = "array of ", }; static const char * pe_sym_type_desc_lsb[0x10] = { [PE_IMAGE_SYM_TYPE_NULL] = "unknown type", [PE_IMAGE_SYM_TYPE_VOID] = "void", [PE_IMAGE_SYM_TYPE_CHAR] = "char", [PE_IMAGE_SYM_TYPE_SHORT] = "short", [PE_IMAGE_SYM_TYPE_INT] = "int", [PE_IMAGE_SYM_TYPE_LONG] = "long", [PE_IMAGE_SYM_TYPE_FLOAT] = "float", [PE_IMAGE_SYM_TYPE_DOUBLE] = "double", [PE_IMAGE_SYM_TYPE_STRUCT] = "struct", [PE_IMAGE_SYM_TYPE_UNION] = "union", [PE_IMAGE_SYM_TYPE_ENUM] = "enum", [PE_IMAGE_SYM_TYPE_MOE] = "enum member", [PE_IMAGE_SYM_TYPE_BYTE] = "byte", [PE_IMAGE_SYM_TYPE_WORD] = "word", [PE_IMAGE_SYM_TYPE_UINT] = "uint", [PE_IMAGE_SYM_TYPE_DWORD] = "dword", }; static const char * pe_sym_storage_class_desc[256] = { [PE_IMAGE_SYM_CLASS_NULL] = "storage class not assigned", [PE_IMAGE_SYM_CLASS_AUTOMATIC] = "automatic (stack) variable", [PE_IMAGE_SYM_CLASS_EXTERNAL] = "external symbol", [PE_IMAGE_SYM_CLASS_STATIC] = "static variable", [PE_IMAGE_SYM_CLASS_REGISTER] = "register variable", [PE_IMAGE_SYM_CLASS_EXTERNAL_DEF] = "externally defined variable", [PE_IMAGE_SYM_CLASS_LABEL] = "label", [PE_IMAGE_SYM_CLASS_UNDEFINED_LABEL] = "undefined label", [PE_IMAGE_SYM_CLASS_MEMBER_OF_STRUCT] = "struct member", [PE_IMAGE_SYM_CLASS_ARGUMENT] = "formal function parameter", [PE_IMAGE_SYM_CLASS_STRUCT_TAG] = "struct tag", [PE_IMAGE_SYM_CLASS_MEMBER_OF_UNION] = "union member", [PE_IMAGE_SYM_CLASS_UNION_TAG] = "union tag", [PE_IMAGE_SYM_CLASS_TYPE_DEFINITION] = "type definition", [PE_IMAGE_SYM_CLASS_UNDEFINED_STATIC] = "undefined (.bss) static data", [PE_IMAGE_SYM_CLASS_ENUM_TAG] = "enum tag", [PE_IMAGE_SYM_CLASS_MEMBER_OF_ENUM] = "enum member", [PE_IMAGE_SYM_CLASS_REGISTER_PARAM] = "register parameter", [PE_IMAGE_SYM_CLASS_BIT_FIELD] = "bit field", [PE_IMAGE_SYM_CLASS_BLOCK] = "a beginning-of-block or end-of-block record", [PE_IMAGE_SYM_CLASS_FUNCTION] = "function record", [PE_IMAGE_SYM_CLASS_END_OF_STRUCT] = "end-of-struct", [PE_IMAGE_SYM_CLASS_FILE] = "file", [PE_IMAGE_SYM_CLASS_SECTION] = "section definition", [PE_IMAGE_SYM_CLASS_WEAK_EXTERN] = "weak external", [PE_IMAGE_SYM_CLASS_CLR_TOKEN] = "CLR token", [PE_IMAGE_SYM_CLASS_END_OF_FUNC] = "end-of-function" }; static int pe_output_symbol_names( const struct pe_driver_ctx * dctx, const struct pe_image_meta * meta, int fdout) { struct pe_meta_coff_symbol * symrec; for (symrec=meta->m_symtbl; symrec->cs_name; symrec++) if (pe_dprintf(fdout,"%s\n",symrec->cs_name) < 0) return PERK_FILE_ERROR(dctx); return 0; } static int pe_output_symbol_names_yaml( const struct pe_driver_ctx * dctx, const struct pe_image_meta * meta, int fdout) { struct pe_meta_coff_symbol * symrec; if (pe_dprintf(fdout," - Symbols:\n") < 0) return PERK_FILE_ERROR(dctx); for (symrec=meta->m_symtbl; symrec->cs_name; symrec++) if (pe_dprintf(fdout," - [ symbol: %s ]\n",symrec->cs_name) < 0) return PERK_FILE_ERROR(dctx); return 0; } static int pe_output_symbol_records_yaml( const struct pe_driver_ctx * dctx, const struct pe_image_meta * meta, int fdout) { struct pe_meta_coff_symbol * symrec; struct pe_meta_sec_hdr * sechdr; const char * secname; const char * classdesc; const char * typedesc[2]; if (pe_dprintf(fdout," - Symbols:\n") < 0) return PERK_FILE_ERROR(dctx); for (symrec=meta->m_symtbl; symrec->cs_name; symrec++) { switch (symrec->cs_section_number) { case PE_IMAGE_SYM_UNDEFINED: secname = "NULL (section is not yet defined)"; break; case PE_IMAGE_SYM_ABSOLUTE: secname = "N/A (symbol is an absolute value)"; break; case PE_IMAGE_SYM_DEBUG: secname = "N/A (debug symbol only)"; break; default: sechdr = &meta->m_sectbl[symrec->cs_section_number - 1]; secname = sechdr->sh_long_name ? sechdr->sh_long_name : sechdr->sh_name; } typedesc[0] = pe_sym_type_desc_msb[(symrec->cs_type >> 4) & 0x03]; typedesc[1] = pe_sym_type_desc_lsb[(symrec->cs_type >> 0) & 0x0f]; if (!(classdesc = pe_sym_storage_class_desc[symrec->cs_storage_class])) classdesc = "UNRECOGNIZED DATA"; if (pe_dprintf(fdout, " - symbol:\n" " - [ name: %s ]\n" " - [ value: 0x%08x ]\n" " - [ crc32: 0x%08x ]\n" " - [ crc64: 0x"PPRIX64" ]\n" " - [ secnum: (%d) ]\n" " - [ secname: %s ]\n" " - [ type: 0x%02X ]\n" " - [ typedesc: %s%s ]\n" " - [ class: %d ]\n" " - [ classname: %s ]\n" " - [ aux-recs: %d ]\n" "\n", symrec->cs_name, symrec->cs_value, symrec->cs_crc32, symrec->cs_crc64, symrec->cs_section_number, secname, symrec->cs_type, typedesc[0],typedesc[1], symrec->cs_storage_class, classdesc, symrec->cs_num_of_aux_recs) < 0) return PERK_FILE_ERROR(dctx); } return 0; } static int pe_output_image_symbols_yaml( const struct pe_driver_ctx * dctx, const struct pe_image_meta * meta, int fdout) { if (dctx->cctx->fmtflags & PERK_PRETTY_VERBOSE) { if (pe_output_symbol_records_yaml(dctx,meta,fdout) < 0) return PERK_NESTED_ERROR(dctx); } else { if (pe_output_symbol_names_yaml(dctx,meta,fdout) < 0) return PERK_NESTED_ERROR(dctx); } return 0; } int pe_output_image_symbols( const struct pe_driver_ctx * dctx, const struct pe_image_meta * meta) { int fdout = pe_driver_fdout(dctx); if (dctx->cctx->fmtflags & PERK_PRETTY_YAML) { if (pe_output_image_symbols_yaml(dctx,meta,fdout) < 0) return PERK_NESTED_ERROR(dctx); } else { if (pe_output_symbol_names(dctx,meta,fdout) < 0) return PERK_NESTED_ERROR(dctx); } return 0; }