Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2013-2017 Nest Labs, Inc.
5 : *
6 : * Licensed under the Apache License, Version 2.0 (the "License");
7 : * you may not use this file except in compliance with the License.
8 : * You may obtain a copy of the License at
9 : *
10 : * http://www.apache.org/licenses/LICENSE-2.0
11 : *
12 : * Unless required by applicable law or agreed to in writing, software
13 : * distributed under the License is distributed on an "AS IS" BASIS,
14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : * See the License for the specific language governing permissions and
16 : * limitations under the License.
17 : */
18 : #include <lib/core/ErrorStr.h>
19 :
20 : #include <lib/core/CHIPConfig.h>
21 : #include <lib/core/CHIPError.h>
22 : #include <lib/support/DLLUtil.h>
23 :
24 : #include <inttypes.h>
25 : #include <stdio.h>
26 :
27 : namespace chip {
28 :
29 : /**
30 : * Buffer to store the formatted error string.
31 : */
32 : #if CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
33 : static thread_local ErrorStrStorage sErrorStr;
34 : #else // CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
35 : static ErrorStrStorage sErrorStr;
36 : #endif // CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE
37 :
38 : /**
39 : * Linked-list of error formatter functions.
40 : */
41 : static ErrorFormatter * sErrorFormatterList = nullptr;
42 :
43 : /**
44 : * This routine returns a human-readable NULL-terminated C string
45 : * describing the provided error.
46 : *
47 : * If CHIP_SYSTEM_CONFIG_THREAD_LOCAL_STORAGE is enabled, this function uses
48 : * thread-local storage to store the formatted error string. Otherwise, it uses
49 : * a global static buffer.
50 : *
51 : * @param[in] err The error for format and describe.
52 : * @param[in] withSourceLocation Whether or not to include the source
53 : * location in the output string. Only used if CHIP_CONFIG_ERROR_SOURCE &&
54 : * !CHIP_CONFIG_SHORT_ERROR_STR. Defaults to true.
55 : *
56 : * @return A pointer to a NULL-terminated C string describing the
57 : * provided error.
58 : */
59 5880 : DLL_EXPORT const char * ErrorStr(CHIP_ERROR err, bool withSourceLocation)
60 : {
61 5880 : return ErrorStr(err, withSourceLocation, sErrorStr);
62 : }
63 :
64 : /**
65 : * This routine writes a human-readable NULL-terminated C string into the buf
66 : * which describes the provided error.
67 : *
68 : * @param[in] err The error for format and describe.
69 : * @param[in] withSourceLocation Whether or not to include the source
70 : * @param[in] storage ErrorStrStorage to write into
71 : * location in the output string. Only used if CHIP_CONFIG_ERROR_SOURCE &&
72 : * !CHIP_CONFIG_SHORT_ERROR_STR. Defaults to true.
73 : *
74 : * @return A pointer to a NULL-terminated C string describing the
75 : * provided error.
76 : */
77 6133 : DLL_EXPORT const char * ErrorStr(CHIP_ERROR err, bool withSourceLocation, ErrorStrStorage & storage)
78 : {
79 6133 : char * formattedError = storage.buff;
80 6133 : uint16_t formattedSpace = storage.kBufferSize;
81 :
82 : #if CHIP_CONFIG_ERROR_SOURCE && !CHIP_CONFIG_SHORT_ERROR_STR
83 :
84 6133 : if (const char * const file = err.GetFile(); withSourceLocation && file != nullptr)
85 : {
86 694 : int n = snprintf(formattedError, formattedSpace, "%s:%u: ", file, err.GetLine());
87 694 : if (n > formattedSpace)
88 : {
89 0 : n = formattedSpace;
90 : }
91 694 : formattedError += n;
92 694 : formattedSpace = static_cast<uint16_t>(formattedSpace - n);
93 : }
94 : #endif // CHIP_CONFIG_ERROR_SOURCE && !CHIP_CONFIG_SHORT_ERROR_STR
95 :
96 6133 : if (err == CHIP_NO_ERROR)
97 : {
98 5165 : (void) snprintf(formattedError, formattedSpace, CHIP_NO_ERROR_STRING);
99 5165 : return storage.buff;
100 : }
101 :
102 : // Search the registered error formatter for one that will format the given
103 : // error code.
104 1749 : for (const ErrorFormatter * errFormatter = sErrorFormatterList; errFormatter != nullptr; errFormatter = errFormatter->Next)
105 : {
106 1627 : if (errFormatter->FormatError(formattedError, formattedSpace, err))
107 : {
108 846 : return storage.buff;
109 : }
110 : }
111 :
112 : // Use a default formatting if no formatter found.
113 122 : FormatError(formattedError, formattedSpace, nullptr, err, nullptr);
114 122 : return storage.buff;
115 : }
116 :
117 : /**
118 : * Add a new error formatter function to the global list of error formatters.
119 : *
120 : * @param[in] errFormatter An ErrorFormatter structure containing a
121 : * pointer to the new error function. Note
122 : * that a pointer to the supplied ErrorFormatter
123 : * structure will be retained by the function.
124 : * Thus the memory for the structure must
125 : * remain reserved.
126 : */
127 945 : DLL_EXPORT void RegisterErrorFormatter(ErrorFormatter * errFormatter)
128 : {
129 : // Do nothing if a formatter with the same format function is already in the list.
130 1835 : for (ErrorFormatter * existingFormatter = sErrorFormatterList; existingFormatter != nullptr;
131 890 : existingFormatter = existingFormatter->Next)
132 : {
133 1558 : if (existingFormatter->FormatError == errFormatter->FormatError)
134 : {
135 668 : return;
136 : }
137 : }
138 :
139 : // Add the formatter to the global list.
140 277 : errFormatter->Next = sErrorFormatterList;
141 277 : sErrorFormatterList = errFormatter;
142 : }
143 :
144 : /**
145 : * Remove an error formatter function from the global list of error formatters.
146 : *
147 : * @param[in] errFormatter An ErrorFormatter structure containing a
148 : * pointer to the new error function.
149 : */
150 11 : DLL_EXPORT void DeregisterErrorFormatter(ErrorFormatter * errFormatter)
151 : {
152 : // Remove the formatter if present
153 30 : for (ErrorFormatter ** lfp = &sErrorFormatterList; *lfp != nullptr;)
154 : {
155 : // Remove the formatter from the global list, if found.
156 19 : if (*lfp == errFormatter)
157 : {
158 10 : *lfp = errFormatter->Next;
159 : }
160 : else
161 : {
162 9 : lfp = &(*lfp)->Next;
163 : }
164 : }
165 11 : }
166 :
167 : #if !CHIP_CONFIG_CUSTOM_ERROR_FORMATTER
168 :
169 : /**
170 : * Generates a human-readable NULL-terminated C string describing the provided error.
171 : *
172 : * @param[in] buf Buffer into which the error string will be placed.
173 : * @param[in] bufSize Size of the supplied buffer in bytes.
174 : * @param[in] subsys A short string describing the subsystem that originated
175 : * the error, or NULL if the origin of the error is
176 : * unknown/unavailable. This string should be 10
177 : * characters or less.
178 : * @param[in] err The error to be formatted.
179 : * @param[in] desc A string describing the cause or meaning of the error,
180 : * or NULL if no such information is available.
181 : */
182 973 : DLL_EXPORT void FormatError(char * buf, uint16_t bufSize, const char * subsys, CHIP_ERROR err, const char * desc)
183 : {
184 : #if CHIP_CONFIG_SHORT_ERROR_STR
185 :
186 : if (subsys == nullptr)
187 : {
188 : (void) snprintf(buf, bufSize, "Error " CHIP_CONFIG_SHORT_FORM_ERROR_VALUE_FORMAT, err.AsInteger());
189 : }
190 : else
191 : {
192 : (void) snprintf(buf, bufSize, "Error %s:" CHIP_CONFIG_SHORT_FORM_ERROR_VALUE_FORMAT, subsys, err.AsInteger());
193 : }
194 :
195 : #else // CHIP_CONFIG_SHORT_ERROR_STR
196 :
197 973 : const char * subsysSep = " ";
198 973 : const char * descSep = ": ";
199 :
200 973 : if (subsys == nullptr)
201 : {
202 124 : subsys = "";
203 124 : subsysSep = "";
204 : }
205 973 : if (desc == nullptr)
206 : {
207 124 : desc = "";
208 124 : descSep = "";
209 : }
210 :
211 973 : (void) snprintf(buf, bufSize, "%s%sError 0x%08" PRIX32 "%s%s", subsys, subsysSep, err.AsInteger(), descSep, desc);
212 :
213 : #endif // CHIP_CONFIG_SHORT_ERROR_STR
214 973 : }
215 :
216 : #endif // CHIP_CONFIG_CUSTOM_ERROR_FORMATTER
217 :
218 : } // namespace chip
|