|
|
68f5d9 |
/***************************************************************/
|
|
|
68f5d9 |
/* perk: PE Resource Kit */
|
|
|
425fb8 |
/* Copyright (C) 2015--2021 SysDeer Technologies, LLC */
|
|
|
68f5d9 |
/* Released under GPLv2 and GPLv3; see COPYING.PERK. */
|
|
|
68f5d9 |
/***************************************************************/
|
|
|
68f5d9 |
|
|
|
68f5d9 |
#include <stdio.h>
|
|
|
68f5d9 |
#include <string.h>
|
|
|
68f5d9 |
#include <errno.h>
|
|
|
68f5d9 |
#include <unistd.h>
|
|
|
68f5d9 |
#include <perk/perk.h>
|
|
|
68f5d9 |
|
|
|
3f9a17 |
#include "perk_driver_impl.h"
|
|
|
3f9a17 |
#include "perk_dprintf_impl.h"
|
|
|
3f9a17 |
|
|
|
68f5d9 |
static const char aclr_reset[] = "\x1b[0m";
|
|
|
68f5d9 |
static const char aclr_bold[] = "\x1b[1m";
|
|
|
68f5d9 |
|
|
|
798729 |
static const char aclr_red[] = "\x1b[31m";
|
|
|
68f5d9 |
static const char aclr_green[] = "\x1b[32m";
|
|
|
68f5d9 |
static const char aclr_blue[] = "\x1b[34m";
|
|
|
68f5d9 |
static const char aclr_magenta[] = "\x1b[35m";
|
|
|
68f5d9 |
|
|
|
4f36c2 |
static const char * const pe_error_strings[PERK_ERR_CAP] = {
|
|
|
0d161c |
[PERK_ERR_FLOW_ERROR] = "flow error: unexpected condition or other",
|
|
|
0d161c |
[PERK_ERR_FLEE_ERROR] = "flees and bugs and cats and mice",
|
|
|
0d161c |
[PERK_ERR_NULL_CONTEXT] = "null driver or unit context",
|
|
|
0d161c |
[PERK_ERR_NULL_IMAGE] = "null image base pointer",
|
|
|
0d161c |
[PERK_ERR_INVALID_CONTEXT] = "invalid driver or unit context",
|
|
|
0d161c |
[PERK_ERR_INVALID_IMAGE] = "invalid PE image",
|
|
|
0d161c |
[PERK_ERR_IMAGE_SIZE_ZERO] = "PE image size cannot be zero",
|
|
|
0d161c |
[PERK_ERR_IMAGE_MALFORMED] = "malformed PE image detected",
|
|
|
0d161c |
[PERK_ERR_BAD_DOS_HEADER] = "bad DOS header",
|
|
|
0d161c |
[PERK_ERR_BAD_COFF_HEADER] = "bad COFF header",
|
|
|
0d161c |
[PERK_ERR_BAD_IMAGE_TYPE] = "bad PE image type",
|
|
|
c63b6d |
[PERK_ERR_UNSUPPORTED_ABI] = "unsupported image abi",
|
|
|
0d161c |
};
|
|
|
0d161c |
|
|
|
68f5d9 |
static const char * pe_output_error_header(const struct pe_error_info * erri)
|
|
|
68f5d9 |
{
|
|
|
f006c4 |
if (erri->eflags & PERK_ERROR_CHILD)
|
|
|
68f5d9 |
return "exec error upon";
|
|
|
68f5d9 |
|
|
|
f006c4 |
else if (erri->eflags & PERK_ERROR_TOP_LEVEL)
|
|
|
68f5d9 |
return "error logged in";
|
|
|
68f5d9 |
|
|
|
f006c4 |
else if (erri->eflags & PERK_ERROR_NESTED)
|
|
|
68f5d9 |
return "< returned to >";
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else
|
|
|
68f5d9 |
return "distorted state";
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
7ac294 |
static const char * pe_output_unit_header(const struct pe_error_info * erri)
|
|
|
7ac294 |
{
|
|
|
7ac294 |
if (!(erri->eflags & PERK_ERROR_CUSTOM))
|
|
|
7ac294 |
return "while opening";
|
|
|
7ac294 |
|
|
|
7ac294 |
else if (erri->elibcode == PERK_ERR_IMAGE_SIZE_ZERO)
|
|
|
7ac294 |
return "while mapping";
|
|
|
7ac294 |
|
|
|
7ac294 |
else
|
|
|
7ac294 |
return "while parsing";
|
|
|
7ac294 |
}
|
|
|
7ac294 |
|
|
|
2b097c |
static const char * pe_output_strerror(
|
|
|
2b097c |
const struct pe_error_info * erri,
|
|
|
2b097c |
char (*errbuf)[256])
|
|
|
68f5d9 |
{
|
|
|
f006c4 |
if (erri->eflags & PERK_ERROR_CUSTOM)
|
|
|
f006c4 |
return ((erri->elibcode < 0) || (erri->elibcode >= PERK_ERR_CAP))
|
|
|
0d161c |
? "internal error: please report to the maintainer"
|
|
|
f006c4 |
: pe_error_strings[erri->elibcode];
|
|
|
68f5d9 |
|
|
|
f006c4 |
else if (erri->eflags & PERK_ERROR_NESTED)
|
|
|
68f5d9 |
return "";
|
|
|
68f5d9 |
|
|
|
f006c4 |
else if (erri->eflags & PERK_ERROR_CHILD)
|
|
|
68f5d9 |
return "(see child process error messages)";
|
|
|
68f5d9 |
|
|
|
f006c4 |
else if (erri->esyscode == ENOBUFS)
|
|
|
68f5d9 |
return "input error: string length exceeds buffer size.";
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else
|
|
|
2b097c |
return strerror_r(erri->esyscode,*errbuf,sizeof(*errbuf))
|
|
|
2b097c |
? "internal error: strerror_r(3) call failed"
|
|
|
2b097c |
: *errbuf;
|
|
|
2b097c |
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
static int pe_output_error_record_plain(
|
|
|
68f5d9 |
const struct pe_driver_ctx * dctx,
|
|
|
68f5d9 |
const struct pe_error_info * erri)
|
|
|
68f5d9 |
{
|
|
|
798729 |
const char * epath;
|
|
|
2b097c |
char errbuf[256];
|
|
|
2b097c |
|
|
|
3f9a17 |
int fderr = pe_driver_fderr(dctx);
|
|
|
2b097c |
const char * errdesc = pe_output_strerror(erri,&errbuf);
|
|
|
68f5d9 |
|
|
|
798729 |
epath = erri->euctx
|
|
|
798729 |
? *erri->euctx->path
|
|
|
798729 |
: erri->eunit;
|
|
|
798729 |
|
|
|
798729 |
if (epath && !(erri->eflags & PERK_ERROR_NESTED))
|
|
|
3f9a17 |
if (pe_dprintf(
|
|
|
3f9a17 |
fderr,
|
|
|
3f9a17 |
"%s: [%s] '%s':\n",
|
|
|
798729 |
dctx->program,
|
|
|
7ac294 |
pe_output_unit_header(erri),
|
|
|
798729 |
epath) < 0)
|
|
|
798729 |
return -1;
|
|
|
798729 |
|
|
|
3f9a17 |
if (pe_dprintf(
|
|
|
3f9a17 |
fderr,
|
|
|
3f9a17 |
"%s: %s %s(), line %d%s%s.\n",
|
|
|
68f5d9 |
dctx->program,
|
|
|
68f5d9 |
pe_output_error_header(erri),
|
|
|
f006c4 |
erri->efunction,
|
|
|
f006c4 |
erri->eline,
|
|
|
68f5d9 |
strlen(errdesc) ? ": " : "",
|
|
|
68f5d9 |
errdesc) < 0)
|
|
|
68f5d9 |
return -1;
|
|
|
68f5d9 |
|
|
|
3f9a17 |
return 0;
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
static int pe_output_error_record_annotated(
|
|
|
68f5d9 |
const struct pe_driver_ctx * dctx,
|
|
|
68f5d9 |
const struct pe_error_info * erri)
|
|
|
68f5d9 |
{
|
|
|
798729 |
const char * epath;
|
|
|
2b097c |
char errbuf[256];
|
|
|
2b097c |
|
|
|
3f9a17 |
int fderr = pe_driver_fderr(dctx);
|
|
|
2b097c |
const char * errdesc = pe_output_strerror(erri,&errbuf);
|
|
|
68f5d9 |
|
|
|
798729 |
epath = erri->euctx
|
|
|
798729 |
? *erri->euctx->path
|
|
|
798729 |
: erri->eunit;
|
|
|
798729 |
|
|
|
798729 |
if (epath && !(erri->eflags & PERK_ERROR_NESTED))
|
|
|
3f9a17 |
if (pe_dprintf(
|
|
|
3f9a17 |
fderr,
|
|
|
7ac294 |
"%s%s%s:%s %s[%s]%s %s%s'%s'%s:\n",
|
|
|
798729 |
|
|
|
798729 |
aclr_bold,aclr_magenta,
|
|
|
798729 |
dctx->program,
|
|
|
798729 |
aclr_reset,
|
|
|
798729 |
|
|
|
798729 |
aclr_bold,
|
|
|
7ac294 |
pe_output_unit_header(erri),
|
|
|
798729 |
aclr_reset,
|
|
|
798729 |
|
|
|
798729 |
aclr_bold,aclr_red,
|
|
|
798729 |
epath,
|
|
|
798729 |
aclr_reset) < 0)
|
|
|
798729 |
return -1;
|
|
|
798729 |
|
|
|
3f9a17 |
if (pe_dprintf(
|
|
|
3f9a17 |
fderr,
|
|
|
68f5d9 |
"%s%s%s:%s %s%s%s %s%s%s()%s, %s%sline %d%s%s%s%s%s.\n",
|
|
|
68f5d9 |
|
|
|
68f5d9 |
aclr_bold,aclr_magenta,
|
|
|
68f5d9 |
dctx->program,
|
|
|
68f5d9 |
aclr_reset,
|
|
|
68f5d9 |
|
|
|
68f5d9 |
aclr_bold,
|
|
|
68f5d9 |
pe_output_error_header(erri),
|
|
|
68f5d9 |
aclr_reset,
|
|
|
68f5d9 |
|
|
|
68f5d9 |
aclr_bold,aclr_blue,
|
|
|
f006c4 |
erri->efunction,
|
|
|
68f5d9 |
aclr_reset,
|
|
|
68f5d9 |
|
|
|
68f5d9 |
aclr_bold,aclr_green,
|
|
|
f006c4 |
erri->eline,
|
|
|
68f5d9 |
aclr_reset,
|
|
|
68f5d9 |
strlen(errdesc) ? ": " : "",
|
|
|
68f5d9 |
|
|
|
68f5d9 |
aclr_bold,
|
|
|
2b097c |
errdesc,
|
|
|
68f5d9 |
aclr_reset) < 0)
|
|
|
68f5d9 |
return -1;
|
|
|
68f5d9 |
|
|
|
3f9a17 |
return 0;
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
int pe_output_error_record(
|
|
|
68f5d9 |
const struct pe_driver_ctx * dctx,
|
|
|
68f5d9 |
const struct pe_error_info * erri)
|
|
|
68f5d9 |
{
|
|
|
68f5d9 |
if (dctx->cctx->drvflags & PERK_DRIVER_ANNOTATE_NEVER)
|
|
|
68f5d9 |
return pe_output_error_record_plain(dctx,erri);
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else if (dctx->cctx->drvflags & PERK_DRIVER_ANNOTATE_ALWAYS)
|
|
|
68f5d9 |
return pe_output_error_record_annotated(dctx,erri);
|
|
|
68f5d9 |
|
|
|
3fe17d |
else if (isatty(pe_driver_fderr(dctx)))
|
|
|
68f5d9 |
return pe_output_error_record_annotated(dctx,erri);
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else
|
|
|
68f5d9 |
return pe_output_error_record_plain(dctx,erri);
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
static int pe_output_error_vector_plain(const struct pe_driver_ctx * dctx)
|
|
|
68f5d9 |
{
|
|
|
68f5d9 |
struct pe_error_info ** perr;
|
|
|
68f5d9 |
|
|
|
68f5d9 |
for (perr=dctx->errv; *perr; perr++)
|
|
|
68f5d9 |
if (pe_output_error_record_plain(dctx,*perr))
|
|
|
68f5d9 |
return -1;
|
|
|
68f5d9 |
|
|
|
68f5d9 |
return 0;
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
static int pe_output_error_vector_annotated(const struct pe_driver_ctx * dctx)
|
|
|
68f5d9 |
{
|
|
|
68f5d9 |
struct pe_error_info ** perr;
|
|
|
68f5d9 |
|
|
|
68f5d9 |
for (perr=dctx->errv; *perr; perr++)
|
|
|
68f5d9 |
if (pe_output_error_record_annotated(dctx,*perr))
|
|
|
68f5d9 |
return -1;
|
|
|
68f5d9 |
|
|
|
68f5d9 |
return 0;
|
|
|
68f5d9 |
}
|
|
|
68f5d9 |
|
|
|
68f5d9 |
int pe_output_error_vector(const struct pe_driver_ctx * dctx)
|
|
|
68f5d9 |
{
|
|
|
68f5d9 |
if (dctx->cctx->drvflags & PERK_DRIVER_ANNOTATE_NEVER)
|
|
|
68f5d9 |
return pe_output_error_vector_plain(dctx);
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else if (dctx->cctx->drvflags & PERK_DRIVER_ANNOTATE_ALWAYS)
|
|
|
68f5d9 |
return pe_output_error_vector_annotated(dctx);
|
|
|
68f5d9 |
|
|
|
3fe17d |
else if (isatty(pe_driver_fderr(dctx)))
|
|
|
68f5d9 |
return pe_output_error_vector_annotated(dctx);
|
|
|
68f5d9 |
|
|
|
68f5d9 |
else
|
|
|
68f5d9 |
return pe_output_error_vector_plain(dctx);
|
|
|
68f5d9 |
}
|