File: error.c

package info (click to toggle)
pev 0.81-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,016 kB
  • sloc: ansic: 20,531; xml: 558; makefile: 450; sh: 397; python: 40
file content (112 lines) | stat: -rwxr-xr-x 4,771 bytes parent folder | download | duplicates (2)
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
/*
    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 <errno.h>
#include <string.h>

const char *pe_error_msg(pe_err_e error) {
	static const char * const errors[] = {
		"no error", // LIBPE_E_OK,
		"allocation failure", // LIBPE_E_ALLOCATION_FAILURE,
		"open() failed", // LIBPE_E_OPEN_FAILED,
		"fdopen() failed", // LIBPE_E_FDOPEN_FAILED,
		"fstat() failed", // LIBPE_E_FSTAT_FAILED,
		"not a regular file", // LIBPE_E_NOT_A_FILE,
		"not a PE file", // LIBPE_E_NOT_A_PE_FILE,
		"invalid e_lfanew", // LIBPE_E_INVALID_LFANEW,
		"missing COFF header", // LIBPE_E_MISSING_COFF_HEADER,
		"missing OPTIONAL header", // LIBPE_E_MISSING_OPTIONAL_HEADER,
		"invalid signature", // LIBPE_E_INVALID_SIGNATURE,
		"unsupported image format", // LIBPE_E_UNSUPPORTED_IMAGE,
		"mmap() failed", // LIBPE_E_MMAP_FAILED,
		"munmap() failed", // LIBPE_E_MUNMAP_FAILED,
		"close() failed", // LIBPE_E_CLOSE_FAILED,
		"too many directories", // LIBPE_E_TOO_MANY_DIRECTORIES,
		"too many sections", // LIBPE_E_TOO_MANY_SECTIONS,
		"type punning failed", // LIBPE_E_TYPE_PUNNING_FAILED
		// Exports errors
		"cannot read relative virtual address", //LIBPE_E_EXPORTS_CANT_READ_RVA
		"cannot read exports directory", // LIBPE_E_EXPORTS_CANT_READ_DIR
		"number of functions not equal to number of names", //LIBPE_E_EXPORTS_FUNC_NEQ_NAMES
		// Hashes Errors
		"error calculating hash", // LIBPE_E_HASHING_FAILED
		// Misc
		"no callbacks found", //LIBPE_E_NO_CALLBACKS_FOUND
		"no functions found", //LIBPE_E_NO_FUNCIONS_FOUND
	};
	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";
}

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];
		memset(errmsg, 0, sizeof(errmsg));

		/*
		 * 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);
	}
}