1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
/*
libpe - the PE library
Copyright (C) 2010 - 2017 libpe authors
This file is part of libpe.
libpe is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
libpe is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with libpe. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libpe/error.h"
#include "libpe/macros.h"
#include <stdlib.h>
#include <errno.h>
#include <string.h>
// FIX: Since all errors, except the first,
// are negative values, we could change the
// order of the strings in the static array
// to simplify this function.
//
// If you change pe_err_e in libpe/error.h, this
// this must be changed too.
const char *pe_error_msg(pe_err_e error) {
static const char * const errors[] = {
// This is 0
"no error", // LIBPE_E_OK,
// FIX: Strings in reverse...
// ALL those errors are 'negative' (as in libpe/error.h).
// Misc
"no functions found", //LIBPE_E_NO_FUNCIONS_FOUND
"no callbacks found", //LIBPE_E_NO_CALLBACKS_FOUND
// Hashes Errors
"error calculating hash", // LIBPE_E_HASHING_FAILED
// Exports errors
"number of functions not equal to number of names", //LIBPE_E_EXPORTS_FUNC_NEQ_NAMES
"cannot read exports directory", // LIBPE_E_EXPORTS_CANT_READ_DIR
"cannot read relative virtual address", //LIBPE_E_EXPORTS_CANT_READ_RVA
"type punning failed", // LIBPE_E_TYPE_PUNNING_FAILED
"too many sections", // LIBPE_E_TOO_MANY_SECTIONS,
"too many directories", // LIBPE_E_TOO_MANY_DIRECTORIES,
"close() failed", // LIBPE_E_CLOSE_FAILED,
"munmap() failed", // LIBPE_E_MUNMAP_FAILED,
"mmap() failed", // LIBPE_E_MMAP_FAILED,
"unsupported image format", // LIBPE_E_UNSUPPORTED_IMAGE,
"invalid signature", // LIBPE_E_INVALID_SIGNATURE,
"missing OPTIONAL header", // LIBPE_E_MISSING_OPTIONAL_HEADER,
"missing COFF header", // LIBPE_E_MISSING_COFF_HEADER,
"invalid e_lfanew", // LIBPE_E_INVALID_LFANEW,
"not a PE file", // LIBPE_E_NOT_A_PE_FILE,
"not a regular file", // LIBPE_E_NOT_A_FILE,
"fstat() failed", // LIBPE_E_FSTAT_FAILED,
"fdopen() failed", // LIBPE_E_FDOPEN_FAILED,
"open() failed", // LIBPE_E_OPEN_FAILED,
"allocation failure" // LIBPE_E_ALLOCATION_FAILURE,
};
// FIX: Convoluted way to use negative errors! The code below is easier and faster.
// static const size_t index_max = LIBPE_SIZEOF_ARRAY(errors);
// size_t index = index_max + error;
// return (index < index_max)
// ? errors[index]
// : (index == index_max)
// ? errors[0] // LIBPE_E_OK
// : "invalid error code";
unsigned int index = abs(error);
if ( index >= LIBPE_SIZEOF_ARRAY(errors) )
return "invalid error code";
return errors[index];
}
void pe_error_print(FILE *stream, pe_err_e error) {
if (errno == 0) {
fprintf(stream, "ERROR [%d]: %s\n", error, pe_error_msg(error));
} else {
char errmsg[255];
/*
* Quotes from https://linux.die.net/man/3/strerror_r
*
* The strerror_r() function is similar to strerror(), but is thread safe. This function
* is available in two versions: an XSI-compliant version specified in POSIX.1-2001
* (available since glibc 2.3.4, but not POSIX-compliant until glibc 2.13), and a
* GNU-specific version (available since glibc 2.0). The XSI-compliant version is provided
* with the feature test macros settings shown in the SYNOPSIS; otherwise the GNU-specific
* version is provided. If no feature test macros are explicitly defined, then (since
* glibc 2.4) _POSIX_SOURCE is defined by default with the value 200112L, so that the
* XSI-compliant version of strerror_r() is provided by default.
*
* The XSI-compliant strerror_r() is preferred for portable applications. It returns the
* error string in the user-supplied buffer buf of length buflen.
*
* The GNU-specific strerror_r() returns a pointer to a string containing the error
* message. This may be either a pointer to a string that the function stores in buf, or
* a pointer to some (immutable) static string (in which case buf is unused). If the
* function stores a string in buf, then at most buflen bytes are stored (the string may
* be truncated if buflen is too small and errnum is unknown). The string always includes
* a terminating null byte.
*/
// Since we define _GNU_SOURCE in our Makefile, strerror_r should be GNU-compliant.
// However, looks like if you're on macOS, strerror_r is XSI-compliant.
#if defined(__DARWIN_C_LEVEL) // XSI-compliant
/* int ret = */ strerror_r(errno, errmsg, sizeof errmsg);
const char *errmsg_ptr = errmsg;
#elif defined(_GNU_SOURCE) // GNU-specific
const char *errmsg_ptr = strerror_r(errno, errmsg, sizeof errmsg);
#else // Fallback to XSI-compliant
/* int ret = */ strerror_r(errno, errmsg, sizeof errmsg);
const char *errmsg_ptr = errmsg;
#endif
fprintf(stream, "ERROR [%d]: %s (%s)\n", error, pe_error_msg(error),
errmsg_ptr);
}
}
|