File: error.h

package info (click to toggle)
drgn 0.0.33-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,892 kB
  • sloc: python: 59,081; ansic: 51,400; awk: 423; makefile: 339; sh: 113
file content (175 lines) | stat: -rw-r--r-- 5,031 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later

/**
 * @file
 *
 * Error helpers.
 *
 * See @ref Errors.
 */

#ifndef DRGN_ERROR_H
#define DRGN_ERROR_H

#include "drgn_internal.h"
#include "pp.h"

/**
 * @ingroup Internals
 *
 * @defgroup Errors Errors
 *
 * Common errors.
 *
 * @{
 */

struct drgn_operand_type;

/** Global stop iteration error. */
extern struct drgn_error drgn_stop;

/** Global @ref DRGN_ERROR_OBJECT_ABSENT error. */
extern struct drgn_error drgn_error_object_absent;

/**
 * Return whether an error is fatal, meaning that it should usually be returned
 * to the caller instead of being handled or logged.
 */
static inline bool drgn_error_is_fatal(struct drgn_error *err)
{
	return err == &drgn_enomem;
}

struct string_builder;

/**
 * Append a formatted @ref drgn_error to a @ref string_builder.
 *
 * @return @c true on success, @c false on error (if we couldn't allocate
 * memory).
 */
bool string_builder_append_error(struct string_builder *sb,
				 struct drgn_error *err);

/** Create a @ref drgn_error from the libelf error indicator. */
struct drgn_error *drgn_error_libelf(void)
	__attribute__((__returns_nonnull__));

/** Create a @ref drgn_error from the libdw error indicator. */
struct drgn_error *drgn_error_libdw(void)
	__attribute__((__returns_nonnull__));

/**
 * Create a @ref drgn_error with a type name.
 *
 * The error code will be @ref DRGN_ERROR_TYPE.
 *
 * @param[in] format Format string for the type error. Must contain %s, which
 * will be replaced with the type name, and no other conversion specifications.
 */
struct drgn_error *drgn_type_error(const char *format, struct drgn_type *type)
	__attribute__((__returns_nonnull__));

/**
 * Create a @ref drgn_error with a qualified type name.
 *
 * @sa drgn_type_error().
 */
struct drgn_error *
drgn_qualified_type_error(const char *format,
			  struct drgn_qualified_type qualified_type)
	__attribute__((__returns_nonnull__));

/**
 * Create a @ref drgn_error with two qualified type names.
 *
 * @param[in] format Format string for the type error. Must contain two `%s`,
 * which will be replaced with the two type names, and no other conversion
 * specifications.
 */
struct drgn_error *
drgn_2_qualified_types_error(const char *format,
			     struct drgn_qualified_type qualified_type1,
			     struct drgn_qualified_type qualified_type2)
	__attribute__((__returns_nonnull__));

/**
 * Create a @ref drgn_error for an incomplete type.
 *
 * @sa drgn_type_error().
 */
struct drgn_error *drgn_error_incomplete_type(const char *format,
					      struct drgn_type *type);

/** Create a @ref drgn_error for invalid types to a binary operator. */
struct drgn_error *drgn_error_binary_op(const char *op_name,
					struct drgn_operand_type *type1,
					struct drgn_operand_type *type2)
	__attribute__((__returns_nonnull__));

/** Create a @ref drgn_error for an invalid type to a unary operator. */
struct drgn_error *drgn_error_unary_op(const char *op_name,
				       struct drgn_operand_type *type)
	__attribute__((__returns_nonnull__));

/** Create a @ref drgn_error for a failed symbol lookup. */
struct drgn_error *drgn_error_symbol_not_found(uint64_t address)
	__attribute__((__returns_nonnull__));

/**
 * Scope guard that counts recursive calls and returns with a @ref
 * DRGN_ERROR_RECURSION error if the recursion depth exceeds a limit.
 *
 * ```
 * struct drgn_error *my_recursive_function(int n)
 * {
 *         drgn_recursion_guard(1000, "maximum recursion depth exceeded");
 *         if (n <= 0)
 *                 return NULL;
 *         return my_recursive_function(n - 1);
 * }
 * ```
 *
 * @param[in] limit Maximum recursion depth. For example, 0 means that the
 * function may be called but may not make any recursive calls.
 * @param[in] message Error message if limit is exceeded.
 */
#define drgn_recursion_guard(limit, message)	\
	drgn_recursion_guard_impl(limit, message, PP_UNIQUE(recursion_count))

static inline void drgn_recursion_guard_cleanup(int **guard)
{
	(**guard)--;
}

#define drgn_recursion_guard_impl(limit, message, unique_recursion_count)	\
	static _Thread_local int unique_recursion_count = 0;			\
	if (unique_recursion_count > (limit))					\
		return drgn_error_create(DRGN_ERROR_RECURSION, (message));	\
	unique_recursion_count++;						\
	__attribute__((__cleanup__(drgn_recursion_guard_cleanup), __unused__))	\
	int *PP_UNIQUE(recursion_count_ptr) = &unique_recursion_count

/**
 * Catch a certain kind of @ref drgn_error and free it
 *
 * If @a errp points to a non-@c NULL error whose code matches @a code, then the
 * free the error (if necessary), replace the pointer value with @c NULL, and
 * return @c true. Otherwise, return @c false, and @a err is not modified.
 */
static inline bool drgn_error_catch(struct drgn_error **errp,
				    enum drgn_error_code code)
{
	if (*errp && (*errp)->code == code) {
		drgn_error_destroy(*errp);
		*errp = NULL;
		return true;
	}
	return false;
}

/** @} */

#endif /* DRGN_ERROR_H */