Blame src/driver/mdso_driver_ctx.c

cde03b
/****************************************************************/
cde03b
/*  mdso: midipix dso scavenger                                 */
473806
/*  Copyright (C) 2015--2024  SysDeer Technologies, LLC         */
cde03b
/*  Released under GPLv2 and GPLv3; see COPYING.MDSO.           */
cde03b
/****************************************************************/
cde03b
cde03b
#include <stdint.h>
cde03b
#include <unistd.h>
cde03b
#include <fcntl.h>
938a47
#include <stdbool.h>
938a47
#include <string.h>
938a47
#include <sys/stat.h>
cde03b
cde03b
#define ARGV_DRIVER
cde03b
cde03b
#include <mdso/mdso.h>
8cfad6
#include <mdso/mdso_output.h>
6848b7
#include <mdso/mdso_specs.h>
26498d
#include "mdso_version.h"
cde03b
#include "mdso_driver_impl.h"
cde03b
#include "argv/argv.h"
cde03b
5cdc2a
#define MDSO_LOADER_FLAGS_MASK	(MDSO_FLAG_LOADER_PATH \
313f34
				| MDSO_FLAG_LDSO_LIB   \
5cdc2a
				| MDSO_FLAG_PEB_PATH   \
5cdc2a
				| MDSO_FLAG_SYSTEM32)
5cdc2a
26498d
/* package info */
26498d
static const struct mdso_source_version mdso_src_version = {
26498d
	MDSO_TAG_VER_MAJOR,
26498d
	MDSO_TAG_VER_MINOR,
26498d
	MDSO_TAG_VER_PATCH,
26498d
	MDSO_GIT_VERSION
26498d
};
26498d
6d4598
/* default fd context */
6d4598
static const struct mdso_fd_ctx mdso_default_fdctx = {
6d4598
	.fdin  = STDIN_FILENO,
6d4598
	.fdout = STDOUT_FILENO,
6d4598
	.fderr = STDERR_FILENO,
6d4598
	.fdcwd = AT_FDCWD,
6d4598
	.fddst = AT_FDCWD,
6d4598
	.fdlog = (-1),
6d4598
};
6d4598
cde03b
struct mdso_driver_ctx_alloc {
cde03b
	struct argv_meta *		meta;
cde03b
	struct mdso_driver_ctx_impl	ctx;
cde03b
	uint64_t			guard;
cde03b
	const char *			units[];
cde03b
};
cde03b
cde03b
static uint32_t mdso_argv_flags(uint32_t flags)
cde03b
{
e5b01f
	uint32_t ret = ARGV_CLONE_VECTOR;
cde03b
cde03b
	if (flags & MDSO_DRIVER_VERBOSITY_NONE)
cde03b
		ret |= ARGV_VERBOSITY_NONE;
cde03b
cde03b
	if (flags & MDSO_DRIVER_VERBOSITY_ERRORS)
cde03b
		ret |= ARGV_VERBOSITY_ERRORS;
cde03b
cde03b
	if (flags & MDSO_DRIVER_VERBOSITY_STATUS)
cde03b
		ret |= ARGV_VERBOSITY_STATUS;
cde03b
cde03b
	return ret;
cde03b
}
cde03b
cde03b
static int mdso_driver_usage(
f1dbc6
	int				fdout,
cde03b
	const char *			program,
cde03b
	const char *			arg,
a6c8d0
	const struct argv_option **	optv,
cde03b
	struct argv_meta *		meta)
cde03b
{
cde03b
	char header[512];
cde03b
cde03b
	snprintf(header,sizeof(header),
cde03b
		"Usage: %s [options] <file>...\n" "Options:\n",
cde03b
		program);
cde03b
f1dbc6
	argv_usage(fdout,header,optv,arg);
cde03b
	argv_free(meta);
cde03b
cde03b
	return MDSO_USAGE;
cde03b
}
cde03b
938a47
static struct mdso_driver_ctx_impl * mdso_driver_ctx_alloc(
938a47
	struct argv_meta *		meta,
f1dbc6
	const struct mdso_fd_ctx *	fdctx,
938a47
	const struct mdso_common_ctx *	cctx,
938a47
	size_t				nunits)
cde03b
{
cde03b
	struct mdso_driver_ctx_alloc *	ictx;
cde03b
	size_t				size;
cde03b
	struct argv_entry *		entry;
cde03b
	const char **			units;
a9007d
	int				elements;
cde03b
cde03b
	size =  sizeof(struct mdso_driver_ctx_alloc);
cde03b
	size += (nunits+1)*sizeof(const char *);
cde03b
bea9e7
	if (!(ictx = calloc(1,size)))
cde03b
		return 0;
cde03b
f1dbc6
	memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx));
f1dbc6
	memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx));
938a47
cde03b
	for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++)
cde03b
		if (!entry->fopt)
cde03b
			*units++ = entry->arg;
cde03b
a9007d
	elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf);
a9007d
a9007d
	ictx->ctx.errinfp  = &ictx->ctx.erriptr[0];
a9007d
	ictx->ctx.erricap  = &ictx->ctx.erriptr[--elements];
a9007d
777073
	ictx->meta = meta;
db4864
	ictx->ctx.fdtmpin = -1;
cde03b
	ictx->ctx.ctx.units = ictx->units;
a9007d
	ictx->ctx.ctx.errv  = ictx->ctx.errinfp;
cde03b
	return &ictx->ctx;
cde03b
}
cde03b
512db4
static int mdso_dstdir_open(int fdcwd, const char * dstdir, const char * asmbase)
938a47
{
938a47
	int fdtop;
938a47
	int fddst;
512db4
	int dirmode = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
938a47
ec6c65
	if (!dstdir)
ec6c65
		fdtop = fdcwd;
ec6c65
ec6c65
	else if ((fdtop = openat(fdcwd,dstdir,O_DIRECTORY)) >= 0)
512db4
		(void)0;
938a47
512db4
	else if (mkdirat(fdcwd,dstdir,dirmode) < 0)
938a47
			return -1;
512db4
512db4
	else if ((fdtop = openat(fdcwd,dstdir,O_DIRECTORY)) < 0)
512db4
		return -1;
512db4
512db4
512db4
	if ((fddst = openat(fdtop,asmbase,O_DIRECTORY)) >= 0)
512db4
		(void)0;
512db4
512db4
	else if (mkdirat(fdtop,asmbase,dirmode))
512db4
		fddst = AT_FDCWD;
512db4
512db4
	else if ((fddst = openat(fdtop,asmbase,O_DIRECTORY)) < 0)
512db4
		fddst = AT_FDCWD;
938a47
938a47
	close(fdtop);
512db4
938a47
	return fddst;
938a47
}
938a47
938a47
static int mdso_get_driver_ctx_fail(
938a47
	struct argv_meta *	meta,
c70c0a
	char *			implib,
938a47
	char *			asmbase,
938a47
	int			fddst)
cde03b
{
512db4
	if (fddst != AT_FDCWD)
938a47
		close(fddst);
938a47
c70c0a
	if (implib)
c70c0a
		free(implib);
c70c0a
938a47
	if (asmbase)
938a47
		free(asmbase);
938a47
cde03b
	argv_free(meta);
512db4
cde03b
	return -1;
cde03b
}
cde03b
cde03b
int mdso_get_driver_ctx(
f1dbc6
	char **				argv,
f1dbc6
	char **				envp,
f1dbc6
	uint32_t			flags,
f1dbc6
	const struct mdso_fd_ctx *	fdctx,
f1dbc6
	struct mdso_driver_ctx **	pctx)
cde03b
{
cde03b
	struct mdso_driver_ctx_impl *	ctx;
cde03b
	struct mdso_common_ctx		cctx;
a6c8d0
	const struct argv_option *	optv[MDSO_OPTV_ELEMENTS];
cde03b
	struct argv_meta *		meta;
cde03b
	struct argv_entry *		entry;
7999c7
	struct argv_entry *		machine;
cde03b
	size_t				nunits;
cde03b
	const char *			program;
8cfad6
	const char *			pretty;
c70c0a
	char *				implib;
938a47
	char *				asmbase;
938a47
	char *				dot;
938a47
	int				fddst;
cde03b
292143
	(void)envp;
292143
6d4598
	if (!fdctx)
6d4598
		fdctx = &mdso_default_fdctx;
f1dbc6
a6c8d0
	argv_optv_init(mdso_default_options,optv);
cde03b
6b4bf5
	if (!(meta = argv_get(
6b4bf5
			argv,optv,
6b4bf5
			mdso_argv_flags(flags),
f1dbc6
			fdctx->fderr)))
cde03b
		return -1;
cde03b
0dba1c
	/* cctx init, option defaults */
0dba1c
	memset(&cctx,0,sizeof(cctx));
0dba1c
7999c7
	machine = 0;
cde03b
	nunits	= 0;
8cfad6
	pretty	= 0;
c70c0a
	implib  = 0;
938a47
	asmbase = 0;
cde03b
	program = argv_program_name(argv[0]);
0dba1c
3b54fd
	cctx.drvflags = flags;
0dba1c
	cctx.dsoflags = MDSO_FLAG_LOADER_PATH;
cde03b
cde03b
	if (!argv[1] && (flags & MDSO_DRIVER_VERBOSITY_USAGE))
f1dbc6
		return mdso_driver_usage(
f1dbc6
			fdctx->fderr,
f1dbc6
			program,0,
f1dbc6
			optv,meta);
cde03b
cde03b
	/* get options, count units */
cde03b
	for (entry=meta->entries; entry->fopt || entry->arg; entry++) {
cde03b
		if (entry->fopt) {
cde03b
			switch (entry->tag) {
cde03b
				case TAG_HELP:
cde03b
					if (flags & MDSO_DRIVER_VERBOSITY_USAGE)
f1dbc6
						return mdso_driver_usage(
f1dbc6
							fdctx->fdout,
f1dbc6
							program,
f1dbc6
							entry->arg,
f1dbc6
							optv,meta);
cde03b
7efccc
					break;
7efccc
cde03b
				case TAG_VERSION:
cde03b
					cctx.drvflags |= MDSO_DRIVER_VERSION;
cde03b
					break;
8cfad6
c12a92
				case TAG_ASM:
c12a92
					cctx.drvflags |= MDSO_DRIVER_GENERATE_ASM;
c12a92
					break;
c12a92
3e55ee
				case TAG_OBJ:
3e55ee
					cctx.drvflags |= MDSO_DRIVER_GENERATE_OBJECTS;
3e55ee
					break;
3e55ee
113d3f
				case TAG_CRC:
113d3f
					if (!(strcmp(entry->arg,"64"))) {
113d3f
						cctx.drvflags &= ~(uint64_t)MDSO_DRIVER_COMPUTE_CRC32;
113d3f
						cctx.drvflags |= MDSO_DRIVER_COMPUTE_CRC64;
113d3f
					} else {
113d3f
						cctx.drvflags &= ~(uint64_t)MDSO_DRIVER_COMPUTE_CRC64;
113d3f
						cctx.drvflags |= MDSO_DRIVER_COMPUTE_CRC32;
113d3f
					}
113d3f
113d3f
					break;
113d3f
7c0ec4
				case TAG_QUAD_PTR:
7999c7
					machine = entry;
7999c7
95a954
					if (!(strcmp(entry->arg,"64")))
95a954
						cctx.drvflags |= MDSO_DRIVER_QUAD_PTR;
95a954
					else
95a954
						cctx.drvflags &= ~(uint64_t)MDSO_DRIVER_QUAD_PTR;
7c0ec4
					break;
7c0ec4
c70c0a
				case TAG_IMPLIB:
c70c0a
					cctx.implib = entry->arg;
c70c0a
					break;
c70c0a
6848b7
				case TAG_LIBPATH:
5cdc2a
					cctx.dsoflags &= ~(uint64_t)MDSO_LOADER_FLAGS_MASK;
5cdc2a
6848b7
					if (!(strcmp(entry->arg,"loader")))
6848b7
						cctx.dsoflags |= MDSO_FLAG_LOADER_PATH;
313f34
313f34
					else if (!(strcmp(entry->arg,"ldso")))
313f34
						cctx.dsoflags |= MDSO_FLAG_LDSO_LIB;
313f34
313f34
					else if (!(strcmp(entry->arg,"peb")))
6848b7
						cctx.dsoflags |= MDSO_FLAG_PEB_PATH;
313f34
313f34
					else if (!(strcmp(entry->arg,"system32")))
6848b7
						cctx.dsoflags |= MDSO_FLAG_SYSTEM32;
6848b7
					break;
6848b7
d8c2b3
				case TAG_LIBNAME:
d8c2b3
					cctx.libname = entry->arg;
d8c2b3
					break;
d8c2b3
d8c2b3
				case TAG_DSTDIR:
d8c2b3
					cctx.dstdir = entry->arg;
d8c2b3
					break;
d8c2b3
8cfad6
				case TAG_PRETTY:
8cfad6
					pretty = entry->arg;
8cfad6
					break;
8cfad6
8cfad6
				case TAG_EXPSYMS:
8cfad6
					cctx.fmtflags |= MDSO_OUTPUT_EXPORT_SYMS;
8cfad6
					break;
cde03b
			}
cde03b
		} else
cde03b
			nunits++;
cde03b
	}
cde03b
7999c7
7999c7
	if (!machine && MDSO_DRIVER_PE_HOST && (sizeof(size_t) == 8))
7999c7
		cctx.drvflags |= MDSO_DRIVER_QUAD_PTR;
7999c7
7999c7
	else if (!machine && MDSO_DRIVER_WINNT_HOST && (sizeof(size_t) == 8))
7999c7
		cctx.drvflags |= MDSO_DRIVER_QUAD_PTR;
7999c7
7999c7
	else if (!machine && strstr(program,"64"))
7999c7
		cctx.drvflags |= MDSO_DRIVER_QUAD_PTR;
7999c7
7999c7
5b1ca3
	if (cctx.drvflags & MDSO_DRIVER_VERBOSITY_USAGE)
5b1ca3
		if (!nunits && !(cctx.drvflags & MDSO_DRIVER_VERSION))
5b1ca3
			return mdso_driver_usage(
5b1ca3
				fdctx->fderr,
5b1ca3
				program,0,
5b1ca3
				optv,meta);
57f0fb
8cfad6
	if (pretty && !strcmp(pretty,"yaml"))
8cfad6
		cctx.fmtflags |= MDSO_PRETTY_YAML;
8cfad6
938a47
	if (!cctx.libname)
938a47
		cctx.libname = "win32any";
938a47
c70c0a
	if (cctx.implib && !(implib = strdup(cctx.implib)))
512db4
		return mdso_get_driver_ctx_fail(meta,0,0,AT_FDCWD);
c70c0a
938a47
	if (!(asmbase = strdup(cctx.libname)))
512db4
		return mdso_get_driver_ctx_fail(meta,implib,0,AT_FDCWD);
938a47
938a47
	if ((dot = strchr(asmbase,'.')))
938a47
		*dot = '\0';
938a47
512db4
ec6c65
	if (!cctx.dstdir && !(cctx.drvflags & MDSO_DRIVER_GENERATE_OBJECTS))
512db4
		fddst = AT_FDCWD;
512db4
512db4
	else if ((fddst = mdso_dstdir_open(fdctx->fdcwd,cctx.dstdir,asmbase)) < 0)
512db4
		return mdso_get_driver_ctx_fail(meta,implib,asmbase,AT_FDCWD);
512db4
938a47
f1dbc6
	if (!(ctx = mdso_driver_ctx_alloc(meta,fdctx,&cctx,nunits)))
c70c0a
		return mdso_get_driver_ctx_fail(meta,implib,asmbase,fddst);
cde03b
c70c0a
	ctx->implib		= implib;
938a47
	ctx->asmbase		= asmbase;
938a47
	ctx->cctx.asmbase	= asmbase;
938a47
	ctx->fddst		= fddst;
512db4
cde03b
	ctx->ctx.program	= program;
cde03b
	ctx->ctx.cctx		= &ctx->cctx;
512db4
	ctx->fdctx.fddst	= fddst;
cde03b
cde03b
	*pctx = &ctx->ctx;
512db4
cde03b
	return MDSO_OK;
cde03b
}
cde03b
cde03b
static void mdso_free_driver_ctx_impl(struct mdso_driver_ctx_alloc * ictx)
cde03b
{
512db4
	if (ictx->ctx.fddst != AT_FDCWD)
938a47
		close(ictx->ctx.fddst);
938a47
db4864
	if (ictx->ctx.fdtmpin >= 0)
761416
		unlink(ictx->ctx.tmpname);
761416
761416
	if (ictx->ctx.fdtmpin >= 0)
db4864
		close(ictx->ctx.fdtmpin);
db4864
938a47
	if (ictx->ctx.asmbase)
938a47
		free(ictx->ctx.asmbase);
938a47
c70c0a
	if (ictx->ctx.implib)
c70c0a
		free(ictx->ctx.implib);
c70c0a
cde03b
	argv_free(ictx->meta);
cde03b
	free(ictx);
cde03b
}
cde03b
cde03b
void mdso_free_driver_ctx(struct mdso_driver_ctx * ctx)
cde03b
{
cde03b
	struct mdso_driver_ctx_alloc *	ictx;
cde03b
	uintptr_t			addr;
cde03b
cde03b
	if (ctx) {
4f02fe
		addr = (uintptr_t)ctx - offsetof(struct mdso_driver_ctx_impl,ctx);
4f02fe
		addr = addr - offsetof(struct mdso_driver_ctx_alloc,ctx);
cde03b
		ictx = (struct mdso_driver_ctx_alloc *)addr;
cde03b
		mdso_free_driver_ctx_impl(ictx);
cde03b
	}
cde03b
}
26498d
26498d
const struct mdso_source_version * mdso_source_version(void)
26498d
{
26498d
	return &mdso_src_version;
26498d
}
f1dbc6
f1dbc6
f1dbc6
int mdso_get_driver_fdctx(
f1dbc6
	const struct mdso_driver_ctx *	dctx,
f1dbc6
	struct mdso_fd_ctx *		fdctx)
f1dbc6
{
f1dbc6
	struct mdso_driver_ctx_impl *	ictx;
f1dbc6
f1dbc6
	ictx = mdso_get_driver_ictx(dctx);
f1dbc6
f1dbc6
	fdctx->fdin  = ictx->fdctx.fdin;
f1dbc6
	fdctx->fdout = ictx->fdctx.fdout;
f1dbc6
	fdctx->fderr = ictx->fdctx.fderr;
f1dbc6
	fdctx->fdlog = ictx->fdctx.fdlog;
f1dbc6
	fdctx->fdcwd = ictx->fdctx.fdcwd;
f1dbc6
	fdctx->fddst = ictx->fdctx.fddst;
f1dbc6
f1dbc6
	return 0;
f1dbc6
}
f1dbc6
f1dbc6
int mdso_set_driver_fdctx(
f1dbc6
	struct mdso_driver_ctx *	dctx,
f1dbc6
	const struct mdso_fd_ctx *	fdctx)
f1dbc6
{
f1dbc6
	struct mdso_driver_ctx_impl *	ictx;
f1dbc6
f1dbc6
	ictx = mdso_get_driver_ictx(dctx);
f1dbc6
f1dbc6
	ictx->fdctx.fdin  = fdctx->fdin;
f1dbc6
	ictx->fdctx.fdout = fdctx->fdout;
f1dbc6
	ictx->fdctx.fderr = fdctx->fderr;
f1dbc6
	ictx->fdctx.fdlog = fdctx->fdlog;
f1dbc6
	ictx->fdctx.fdcwd = fdctx->fdcwd;
512db4
512db4
	if (ictx->fdctx.fddst == fdctx->fddst) {
512db4
		(void)0;
512db4
512db4
	} else if (ictx->fddst == AT_FDCWD) {
512db4
		ictx->fdctx.fddst = fdctx->fddst;
512db4
512db4
	} else {
512db4
		close(ictx->fddst);
512db4
		ictx->fddst       = AT_FDCWD;
512db4
		ictx->fdctx.fddst = fdctx->fddst;
512db4
	}
f1dbc6
f1dbc6
	return 0;
f1dbc6
}