diff options
-rw-r--r-- | project/common.mk | 2 | ||||
-rw-r--r-- | project/tree.mk | 1 | ||||
-rw-r--r-- | src/driver/pe_driver_ctx.c | 203 | ||||
-rw-r--r-- | src/driver/pe_unit_ctx.c | 52 |
4 files changed, 258 insertions, 0 deletions
diff --git a/project/common.mk b/project/common.mk index 012bcb6..d28c6a2 100644 --- a/project/common.mk +++ b/project/common.mk @@ -1,4 +1,6 @@ COMMON_SRCS = \ + src/driver/pe_driver_ctx.c \ + src/driver/pe_unit_ctx.c \ src/logic/pe_get_image_meta.c \ src/logic/pe_map_raw_image.c \ src/output/pe_output_export_symbols.c \ diff --git a/project/tree.mk b/project/tree.mk index 74bcb9b..386d8d5 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,5 +1,6 @@ tree.tag: mkdir -p src + mkdir -p src/driver mkdir -p src/internal mkdir -p src/logic mkdir -p src/output diff --git a/src/driver/pe_driver_ctx.c b/src/driver/pe_driver_ctx.c new file mode 100644 index 0000000..1054ac7 --- /dev/null +++ b/src/driver/pe_driver_ctx.c @@ -0,0 +1,203 @@ +#include <stdint.h> +#include <fcntl.h> +#include <perk/perk.h> +#include "argv/argv.h" + +enum app_tags { + TAG_HELP, + TAG_VERSION, + TAG_OUTPUT, + TAG_EXPSYMS, +}; + +static const struct argv_option options[] = { + {"version", 'v',TAG_VERSION,ARGV_OPTARG_NONE, 0,0, + "show version information"}, + + {"help", 'h',TAG_HELP, ARGV_OPTARG_OPTIONAL, "short|long",0, + "show usage information " + "[listing %s options only]"}, + + {"output", 'o',TAG_OUTPUT, ARGV_OPTARG_REQUIRED, 0,"<file>", + "write output to %s"}, + + {"expsyms", 'e',TAG_EXPSYMS,ARGV_OPTARG_NONE, 0,0, + "print exported symbols" }, + {0} +}; + +struct pe_driver_ctx_impl { + struct argv_meta * meta; + struct pe_symbol_ctx symctx; + struct pe_output_ctx outctx; + struct pe_linker_ctx lnkctx; + struct pe_server_ctx srvctx; + struct pe_driver_ctx ctx; + uint64_t guard; + const char * units[]; +}; + +static uint32_t pe_argv_flags(uint32_t flags) +{ + uint32_t ret = 0; + + if (flags & PERK_DRIVER_VERBOSITY_NONE) + ret |= ARGV_VERBOSITY_NONE; + + if (flags & PERK_DRIVER_VERBOSITY_ERRORS) + ret |= ARGV_VERBOSITY_ERRORS; + + if (flags & PERK_DRIVER_VERBOSITY_STATUS) + ret |= ARGV_VERBOSITY_STATUS; + + return ret; +} + +static struct pe_driver_ctx * pe_driver_ctx_alloc(struct argv_meta * meta, size_t nunits) +{ + struct pe_driver_ctx_impl * ictx; + size_t size; + struct argv_entry * entry; + const char ** units; + + size = sizeof(struct pe_driver_ctx_impl); + size += (nunits+1)*sizeof(const char *); + + if (!(ictx = calloc(size,1))) + return 0; + + ictx->meta = meta; + ictx->ctx.cctx.symctx = &ictx->symctx; + ictx->ctx.cctx.outctx = &ictx->outctx; + ictx->ctx.cctx.lnkctx = &ictx->lnkctx; + ictx->ctx.cctx.srvctx = &ictx->srvctx; + + for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++) + if (!entry->fopt) + *units++ = entry->arg; + + ictx->ctx.units = ictx->units; + return &ictx->ctx; +} + +int pe_get_driver_ctx_fail(struct argv_meta * meta) +{ + argv_free(meta); + return -1; +} + +int pe_get_driver_ctx( + const char ** argv, + const char ** envp, + uint32_t flags, + struct pe_driver_ctx ** pctx) +{ + struct pe_driver_ctx * ctx; + struct argv_meta * meta; + struct argv_entry * entry; + size_t nunits; + uint64_t dflags; + uint64_t fflags; + const char * program; + const char * output; + int fdout; + char header[512]; + + if (!(meta = argv_get(argv,options,pe_argv_flags(flags)))) + return -1; + + dflags = 0; + fflags = 0; + output = 0; + nunits = 0; + program = argv_program_name(argv[0]); + + /* get options, count units */ + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_HELP: + if (flags & PERK_DRIVER_VERBOSITY_USAGE) { + snprintf(header,sizeof(header), + "Usage: %s [options] <file>...\n" "Options:\n", + program); + + argv_usage(stdout,header,options,entry->arg); + argv_free(meta); + return PERK_USAGE; + } + + case TAG_VERSION: + dflags |= PERK_DRIVER_FLAG_VERSION; + break; + + case TAG_OUTPUT: + output = entry->arg; + break; + + case TAG_EXPSYMS: + fflags |= PERK_OUTPUT_FLAG_EXPORT_SYMS; + break; + } + } else + nunits++; + } + + if (output && ((fdout = open(output, + O_CREAT|O_TRUNC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)) + return pe_get_driver_ctx_fail(meta); + + if (!(ctx = pe_driver_ctx_alloc(meta,nunits))) + return pe_get_driver_ctx_fail(meta); + + ctx->program = program; + ctx->cctx.drvflags = dflags; + ctx->cctx.fmtflags = fflags; + ctx->cctx.output = output; + ctx->cctx.fdout = output ? fdout : -1; + + ctx->cctx.fdin = -1; + ctx->cctx.fderr = -1; + ctx->cctx.fdlog = -1; + ctx->cctx.fdsrc = AT_FDCWD; + ctx->cctx.fddst = AT_FDCWD; + ctx->cctx.fdtmp = AT_FDCWD; + + *pctx = ctx; + return PERK_OK; +} + +static void pe_driver_close_fds(struct pe_common_ctx * cctx) +{ + if (cctx->status && cctx->output) + unlinkat(cctx->fddst,cctx->output,0); + + if (cctx->fdout >= 0) + close(cctx->fdout); +} + +static void pe_free_driver_ctx_impl(struct pe_driver_ctx_impl * ictx) +{ + if (ictx->symctx.append) + free(ictx->symctx.append); + + if (ictx->symctx.exclude) + free(ictx->symctx.exclude); + + pe_driver_close_fds(&ictx->ctx.cctx); + argv_free(ictx->meta); + free(ictx); +} + +void pe_free_driver_ctx(struct pe_driver_ctx * ctx) +{ + struct pe_driver_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct pe_driver_ctx_impl,ctx); + ictx = (struct pe_driver_ctx_impl *)addr; + pe_free_driver_ctx_impl(ictx); + } +} diff --git a/src/driver/pe_unit_ctx.c b/src/driver/pe_unit_ctx.c new file mode 100644 index 0000000..5bcac3d --- /dev/null +++ b/src/driver/pe_unit_ctx.c @@ -0,0 +1,52 @@ +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <perk/perk.h> + +static int pe_free_unit_ctx_impl(struct pe_unit_ctx * ctx, int status) +{ + if (ctx) { + pe_free_image_meta(ctx->meta); + pe_unmap_raw_image(&ctx->map); + free(ctx); + } + + return status; +} + +int pe_get_unit_ctx( + struct pe_driver_ctx * dctx, + const char * path, + struct pe_unit_ctx ** pctx) +{ + struct pe_unit_ctx * ctx; + int prot; + + if (!dctx || !(ctx = calloc(sizeof(*ctx),1))) + return -1; + + prot = (dctx->cctx.actflags & PERK_ACTION_FLAG_MAP_READWRITE) + ? PROT_READ | PROT_WRITE + : PROT_READ; + + if (pe_map_raw_image(dctx->cctx.fdin,path,prot,&ctx->map)) + return pe_free_unit_ctx_impl(ctx,-1); + + if (pe_get_image_meta(&ctx->map,&ctx->meta)) + return pe_free_unit_ctx_impl(ctx,-1); + + memcpy(&ctx->cctx,&dctx->cctx, + sizeof(ctx->cctx)); + + ctx->path = path; + ctx->cctx.prot = prot; + + *pctx = ctx; + return 0; +} + +void pe_free_unit_ctx(struct pe_unit_ctx * ctx) +{ + pe_free_unit_ctx_impl(ctx,0); +} |