Blame src/output/pe_output_image_symbols.c

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