Blame src/driver/pe_driver_ctx.c

e2e2c2
/***************************************************************/
e2e2c2
/*  perk: PE Resource Kit                                      */
425fb8
/*  Copyright (C) 2015--2021  SysDeer Technologies, LLC        */
e2e2c2
/*  Released under GPLv2 and GPLv3; see COPYING.PERK.          */
e2e2c2
/***************************************************************/
e2e2c2
81e8b3
#include <stdint.h>
6f882b
#include <unistd.h>
81e8b3
#include <fcntl.h>
c61328
249590
#define ARGV_DRIVER
249590
81e8b3
#include <perk/perk.h>
949bb3
#include <perk/perk_output.h>
b7025c
#include "perk_version.h"
249590
#include "perk_driver_impl.h"
81e8b3
#include "argv/argv.h"
81e8b3
b7025c
/* package info */
b7025c
static const struct pe_source_version pe_src_version = {
b7025c
	PERK_TAG_VER_MAJOR,
b7025c
	PERK_TAG_VER_MINOR,
b7025c
	PERK_TAG_VER_PATCH,
b7025c
	PERK_GIT_VERSION
b7025c
};
b7025c
d7016c
/* default fd context */
d7016c
static const struct pe_fd_ctx pe_default_fdctx = {
d7016c
	.fdin  = STDIN_FILENO,
d7016c
	.fdout = STDOUT_FILENO,
d7016c
	.fderr = STDERR_FILENO,
d7016c
	.fdcwd = AT_FDCWD,
d7016c
	.fddst = AT_FDCWD,
d7016c
	.fdlog = (-1),
d7016c
};
d7016c
1711ab
struct pe_driver_ctx_alloc {
44d7e6
	struct argv_meta *		meta;
c61328
	struct pe_driver_ctx_impl	ctx;
44d7e6
	uint64_t			guard;
44d7e6
	const char *			units[];
81e8b3
};
81e8b3
81e8b3
static uint32_t pe_argv_flags(uint32_t flags)
81e8b3
{
42b537
	uint32_t ret = ARGV_CLONE_VECTOR;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_NONE)
81e8b3
		ret |= ARGV_VERBOSITY_NONE;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_ERRORS)
81e8b3
		ret |= ARGV_VERBOSITY_ERRORS;
81e8b3
81e8b3
	if (flags & PERK_DRIVER_VERBOSITY_STATUS)
81e8b3
		ret |= ARGV_VERBOSITY_STATUS;
81e8b3
81e8b3
	return ret;
81e8b3
}
81e8b3
dd97ea
static int pe_driver_usage(
a85d3e
	int				fdout,
612b7d
	const char *			program,
612b7d
	const char *			arg,
cfa4ad
	const struct argv_option **	optv,
612b7d
	struct argv_meta *		meta)
dd97ea
{
dd97ea
	char header[512];
dd97ea
dd97ea
	snprintf(header,sizeof(header),
dd97ea
		"Usage: %s [options] <file>...\n" "Options:\n",
dd97ea
		program);
dd97ea
a85d3e
	argv_usage(fdout,header,optv,arg);
dd97ea
	argv_free(meta);
dd97ea
dd97ea
	return PERK_USAGE;
dd97ea
}
dd97ea
99763f
static struct pe_driver_ctx_impl * pe_driver_ctx_alloc(
99763f
	struct argv_meta *		meta,
a85d3e
	const struct pe_fd_ctx *	fdctx,
99763f
	const struct pe_common_ctx *	cctx,
99763f
	size_t				nunits)
81e8b3
{
1711ab
	struct pe_driver_ctx_alloc *	ictx;
81e8b3
	size_t				size;
81e8b3
	struct argv_entry *		entry;
81e8b3
	const char **			units;
c9c5f7
	int				elements;
81e8b3
1711ab
	size =  sizeof(struct pe_driver_ctx_alloc);
81e8b3
	size += (nunits+1)*sizeof(const char *);
81e8b3
ffcd00
	if (!(ictx = calloc(1,size)))
81e8b3
		return 0;
81e8b3
a85d3e
	memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx));
a85d3e
	memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
99763f
c9c5f7
	elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
c9c5f7
c9c5f7
	ictx->ctx.errinfp  = &ictx->ctx.erriptr[0];
c9c5f7
	ictx->ctx.erricap  = &ictx->ctx.erriptr[--elements];
c9c5f7
f11c1f
	ictx->meta = meta;
81e8b3
81e8b3
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
81e8b3
		if (!entry->fopt)
81e8b3
			*units++ = entry->arg;
81e8b3
c61328
	ictx->ctx.ctx.units = ictx->units;
c9c5f7
	ictx->ctx.ctx.errv  = ictx->ctx.errinfp;
81e8b3
	return &ictx->ctx;
81e8b3
}
81e8b3
712fa6
static int pe_get_driver_ctx_fail(struct argv_meta * meta)
81e8b3
{
81e8b3
	argv_free(meta);
81e8b3
	return -1;
81e8b3
}
81e8b3
81e8b3
int pe_get_driver_ctx(
a85d3e
	char **				argv,
a85d3e
	char **				envp,
a85d3e
	uint32_t			flags,
a85d3e
	const struct pe_fd_ctx *	fdctx,
a85d3e
	struct pe_driver_ctx ** 	pctx)
81e8b3
{
c61328
	struct pe_driver_ctx_impl *	ctx;
dccbc5
	struct pe_common_ctx		cctx;
cfa4ad
	const struct argv_option *	optv[PERK_OPTV_ELEMENTS];
44d7e6
	struct argv_meta *		meta;
44d7e6
	struct argv_entry *		entry;
44d7e6
	size_t				nunits;
44d7e6
	const char *			program;
44d7e6
	const char *			pretty;
81e8b3
209439
	(void)envp;
209439
d7016c
	if (!fdctx)
d7016c
		fdctx = &pe_default_fdctx;
a85d3e
cfa4ad
	argv_optv_init(pe_default_options,optv);
249590
ae96cc
	if (!(meta = argv_get(
ae96cc
			argv,optv,
ae96cc
			pe_argv_flags(flags),
c7824a
			fdctx->fderr)))
81e8b3
		return -1;
81e8b3
0d3dde
	pretty	= 0;
81e8b3
	nunits	= 0;
81e8b3
	program = argv_program_name(argv[0]);
dccbc5
	memset(&cctx,0,sizeof(cctx));
b70615
	cctx.drvflags = flags;
81e8b3
dd97ea
	if (!argv[1] && (flags & PERK_DRIVER_VERBOSITY_USAGE))
a85d3e
		return pe_driver_usage(
a85d3e
			fdctx->fderr,
a85d3e
			program,
a85d3e
			0,optv,meta);
dd97ea
81e8b3
	/* get options, count units */
81e8b3
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
81e8b3
		if (entry->fopt) {
81e8b3
			switch (entry->tag) {
81e8b3
				case TAG_HELP:
dd97ea
					if (flags & PERK_DRIVER_VERBOSITY_USAGE)
a85d3e
						return pe_driver_usage(
a85d3e
							fdctx->fdout,
a85d3e
							program,entry->arg,
a85d3e
							optv,meta);
ef6791
					break;
81e8b3
81e8b3
				case TAG_VERSION:
dccbc5
					cctx.drvflags |= PERK_DRIVER_VERSION;
81e8b3
					break;
81e8b3
0d3dde
				case TAG_PRETTY:
0d3dde
					pretty = entry->arg;
0d3dde
					break;
0d3dde
cd4ace
				case TAG_CATEGORY:
cd4ace
					cctx.fmtflags |= PERK_OUTPUT_IMAGE_CATEGORY;
665ac3
					break;
665ac3
9d75af
				case TAG_SECTIONS:
9d75af
					cctx.fmtflags |= PERK_OUTPUT_IMAGE_SECTIONS;
9d75af
					break;
9d75af
016925
				case TAG_SYMBOLS:
016925
					cctx.fmtflags |= PERK_OUTPUT_IMAGE_SYMBOLS;
016925
					break;
016925
ecf121
				case TAG_STRINGS:
ecf121
					cctx.fmtflags |= PERK_OUTPUT_IMAGE_STRINGS;
ecf121
					break;
ecf121
81e8b3
				case TAG_EXPSYMS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_EXPORT_SYMS;
81e8b3
					break;
9c5807
9c5807
				case TAG_IMPLIBS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_IMPORT_LIBS;
9c5807
					break;
9c5807
9c5807
				case TAG_IMPSYMS:
dccbc5
					cctx.fmtflags |= PERK_OUTPUT_IMPORT_SYMS;
9c5807
					break;
ee981e
ee981e
				case TAG_DSOLIBS:
ee981e
					cctx.fmtflags |= PERK_OUTPUT_MDSO_LIBS;
ee981e
					break;
ee981e
ee981e
				case TAG_DSOSYMS:
ee981e
					cctx.fmtflags |= PERK_OUTPUT_MDSO_SYMS;
ee981e
					break;
d38fc0
d38fc0
				case TAG_HDRDUMP:
d38fc0
					if (!entry->arg) {
d38fc0
						cctx.hdrdump = 0;
d38fc0
						cctx.hdrdump = ~cctx.hdrdump;
d38fc0
					} else if (!strcmp(entry->arg,"dos")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_IMAGE_DOS_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"image.dos")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_IMAGE_DOS_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_IMAGE_HEADER;
d38fc0
						cctx.hdrdump |= PERK_HDRDUMP_COFF_OBJECT_HEADER;
d38fc0
						cctx.hdrdump |= PERK_HDRDUMP_COFF_OPT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff.image")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_IMAGE_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff.obj")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_OBJECT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff.object")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_OBJECT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff.opt")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_OPT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"coff.optional")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_COFF_OPT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"sectbl")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_SECTION_TABLE;
d38fc0
					} else if (!strcmp(entry->arg,"section.table")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_SECTION_TABLE;
d38fc0
					} else if (!strcmp(entry->arg,"exphdr")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_EXPORT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"export.header")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_EXPORT_HEADER;
d38fc0
					} else if (!strcmp(entry->arg,"imptbl")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_IMPORT_TABLE;
d38fc0
					} else if (!strcmp(entry->arg,"import.table")) {
d38fc0
						cctx.hdrdump  = PERK_HDRDUMP_IMPORT_TABLE;
d38fc0
					}
d38fc0
					break;
81e8b3
			}
81e8b3
		} else
81e8b3
			nunits++;
81e8b3
	}
81e8b3
99763f
	if (pretty && !strcmp(pretty,"yaml"))
99763f
		cctx.fmtflags |= PERK_PRETTY_YAML;
08a894
	else if (pretty && !strcmp(pretty,"dlltool"))
08a894
		cctx.fmtflags |= PERK_PRETTY_DLLTOOL;
99763f
a85d3e
	if (!(ctx = pe_driver_ctx_alloc(meta,fdctx,&cctx,nunits)))
81e8b3
		return pe_get_driver_ctx_fail(meta);
81e8b3
c61328
	ctx->ctx.program	= program;
99763f
	ctx->ctx.cctx		= &ctx->cctx;
81e8b3
c61328
	*pctx = &ctx->ctx;
81e8b3
	return PERK_OK;
81e8b3
}
81e8b3
1711ab
static void pe_free_driver_ctx_impl(struct pe_driver_ctx_alloc * ictx)
81e8b3
{
81e8b3
	argv_free(ictx->meta);
81e8b3
	free(ictx);
81e8b3
}
81e8b3
81e8b3
void pe_free_driver_ctx(struct pe_driver_ctx * ctx)
81e8b3
{
1711ab
	struct pe_driver_ctx_alloc *	ictx;
81e8b3
	uintptr_t			addr;
81e8b3
81e8b3
	if (ctx) {
95fab3
		addr = (uintptr_t)ctx - offsetof(struct pe_driver_ctx_impl,ctx);
95fab3
		addr = addr - offsetof(struct pe_driver_ctx_alloc,ctx);
1711ab
		ictx = (struct pe_driver_ctx_alloc *)addr;
81e8b3
		pe_free_driver_ctx_impl(ictx);
81e8b3
	}
81e8b3
}
b7025c
b7025c
const struct pe_source_version * pe_source_version(void)
b7025c
{
b7025c
	return &pe_src_version;
b7025c
}
a85d3e
a85d3e
int pe_get_driver_fdctx(
a85d3e
	const struct pe_driver_ctx *	dctx,
a85d3e
	struct pe_fd_ctx *		fdctx)
a85d3e
{
a85d3e
	struct pe_driver_ctx_impl *	ictx;
a85d3e
a85d3e
	ictx = pe_get_driver_ictx(dctx);
a85d3e
a85d3e
	fdctx->fdin  = ictx->fdctx.fdin;
a85d3e
	fdctx->fdout = ictx->fdctx.fdout;
a85d3e
	fdctx->fderr = ictx->fdctx.fderr;
a85d3e
	fdctx->fdlog = ictx->fdctx.fdlog;
a85d3e
	fdctx->fdcwd = ictx->fdctx.fdcwd;
a85d3e
	fdctx->fddst = ictx->fdctx.fddst;
a85d3e
a85d3e
	return 0;
a85d3e
}
a85d3e
a85d3e
int pe_set_driver_fdctx(
a85d3e
	struct pe_driver_ctx *	dctx,
a85d3e
	const struct pe_fd_ctx *	fdctx)
a85d3e
{
a85d3e
	struct pe_driver_ctx_impl *	ictx;
a85d3e
a85d3e
	ictx = pe_get_driver_ictx(dctx);
a85d3e
a85d3e
	ictx->fdctx.fdin  = fdctx->fdin;
a85d3e
	ictx->fdctx.fdout = fdctx->fdout;
a85d3e
	ictx->fdctx.fderr = fdctx->fderr;
a85d3e
	ictx->fdctx.fdlog = fdctx->fdlog;
a85d3e
	ictx->fdctx.fdcwd = fdctx->fdcwd;
a85d3e
	ictx->fdctx.fddst = fdctx->fddst;
a85d3e
a85d3e
	return 0;
a85d3e
}