xref: /xnu-12377.1.9/bsd/sys/kdebug_kernel.h (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
1 /*
2  * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #ifndef BSD_SYS_KDEBUG_KERNEL_H
30 #define BSD_SYS_KDEBUG_KERNEL_H
31 
32 #include <mach/boolean.h>
33 #include <mach/clock_types.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stddef.h>
37 #include <sys/cdefs.h>
38 
39 __BEGIN_DECLS
40 
41 #ifdef KERNEL
42 
43 /*
44  * To use kdebug in the kernel:
45  *
46  * #include <sys/kdebug_kernel.h>
47  *
48  * #define DBG_NETIPINIT NETDBG_CODE(DBG_NETIP, 1)
49  *
50  * void
51  * ip_init(void)
52  * {
53  *     KDBG(DBG_NETIPINIT | DBG_FUNC_START, 1, 2, 3, 4);
54  *     ...
55  *     KDBG(DBG_NETIPINIT);
56  *     ...
57  *     KDBG(DBG_NETIPINIT | DBG_FUNC_END);
58  * }
59  */
60 
61 #pragma mark - kernel tracepoints
62 
63 /*
64  * The KDBG{,_DEBUG,_RELEASE,_FILTERED} macros are the preferred method of
65  * making tracepoints.
66  *
67  * Kernel pointers must be unslid or permuted using VM_KERNEL_UNSLIDE_OR_PERM.
68  * Do not trace any sensitive data.
69  */
70 
71 /*
72  * Traced on debug and development (and release macOS) kernels.
73  */
74 #define KDBG(x, ...) KDBG_(, x, ## __VA_ARGS__, 4, 3, 2, 1, 0)
75 
76 /*
77  * Traced on debug and development (and release macOS) kernels if explicitly
78  * requested.  Omitted from tracing without a typefilter.
79  */
80 #define KDBG_FILTERED(x, ...) KDBG_(_FILTERED, x, ## __VA_ARGS__, 4, 3, 2, 1, 0)
81 
82 #ifdef KERNEL_PRIVATE
83 
84 /*
85  * Traced on debug and development (and release macOS) kernels, even if the
86  * process filter would reject it.
87  */
88 #define KDBG_RELEASE_NOPROCFILT(x, ...) \
89 	        KDBG_(_RELEASE_NOPROCFILT, x, ## __VA_ARGS__, 4, 3, 2, 1, 0)
90 
91 #endif /* KERNEL_PRIVATE */
92 
93 /*
94  * Traced on debug, development, and release kernels.
95  *
96  * Only use this tracepoint if the events are required for a shipping trace
97  * tool.
98  */
99 #define KDBG_RELEASE(x, ...) KDBG_(_RELEASE, x, ## __VA_ARGS__, 4, 3, 2, 1, 0)
100 
101 /*
102  * Traced only on debug kernels.
103  */
104 #define KDBG_DEBUG(x, ...) KDBG_(_DEBUG, x, ## __VA_ARGS__, 4, 3, 2, 1, 0)
105 
106 #pragma mark - kernel API
107 
108 #ifdef KERNEL_PRIVATE
109 
110 /*
111  * kernel_debug_string provides the same functionality as the
112  * kdebug_trace_string syscall as a KPI.  str_id is an in/out
113  * parameter that, if it's pointing to a string ID of 0, will
114  * receive a generated ID.  If it provides a value in str_id,
115  * then that will be used, instead.
116  *
117  * Returns an errno indicating the type of failure.
118  */
119 int kernel_debug_string(uint32_t debugid, uint64_t *str_id, const char *str);
120 
121 /*
122  * kernel_debug_disable disables event logging, but leaves any buffers
123  * intact.
124  */
125 void kernel_debug_disable(void);
126 
127 #endif /* KERNEL_PRIVATE */
128 
129 /*
130  * Returns true if kdebug is using continuous time for its events, and false
131  * otherwise.
132  */
133 bool kdebug_using_continuous_time(void);
134 
135 /*
136  * Convert an absolute time to a kdebug timestamp.
137  */
138 extern uint64_t kdebug_timestamp_from_absolute(uint64_t abstime);
139 
140 /*
141  * Convert a continuous time to a kdebug timestamp.
142  */
143 extern uint64_t kdebug_timestamp_from_continuous(uint64_t conttime);
144 
145 /*
146  * Capture a kdebug timestamp for the current time.
147  */
148 extern uint64_t kdebug_timestamp(void);
149 
150 /*
151  * Returns true if kdebug will log an event with the provided debugid, and
152  * false otherwise.
153  */
154 bool kdebug_debugid_enabled(uint32_t debugid);
155 
156 /*
157  * Returns true only if the debugid is explicitly enabled by filters.  Returns
158  * false otherwise, including when no filters are active.
159  */
160 bool kdebug_debugid_explicitly_enabled(uint32_t debugid);
161 
162 uint32_t kdebug_commpage_state(void);
163 
164 #pragma mark - Coprocessor/IOP tracing
165 
166 typedef enum {
167 	/* Trace is now enabled. */
168 	KD_CALLBACK_KDEBUG_ENABLED,
169 	/*
170 	 * Trace is being disabled, but events are still accepted for the duration
171 	 * of the callback.
172 	 */
173 	KD_CALLBACK_KDEBUG_DISABLED,
174 	/*
175 	 * Request the latest events from the IOP and block until complete.  Any
176 	 * events that occur prior to this callback being called may be dropped by
177 	 * the trace system.
178 	 */
179 	KD_CALLBACK_SYNC_FLUSH,
180 	/*
181 	 * The typefilter is being used.
182 	 *
183 	 * A read-only pointer to the typefilter is provided as the argument, valid
184 	 * only in the callback.
185 	 */
186 	KD_CALLBACK_TYPEFILTER_CHANGED,
187 	/*
188 	 * The coprocessor should emit data that snapshots the current state of the
189 	 * system.
190 	 */
191 	KD_CALLBACK_SNAPSHOT_STATE,
192 } kd_callback_type;
193 
194 __options_decl(kdebug_coproc_flags_t, uint32_t, {
195 	/*
196 	 * Event timestamps from this coprocessor are in the continuous timebase.
197 	 */
198 	KDCP_CONTINUOUS_TIME = 0x001,
199 });
200 
201 typedef void (*kd_callback_fn)(void *context, kd_callback_type reason,
202     void *arg);
203 
204 /*
205  * Register a coprocessor for participation in tracing.
206  *
207  * The `callback` function will be called with the provided `context` when
208  * necessary, according to the `kd_callback_type`s.
209  *
210  * The positive core ID is returned on success, or -1 on failure.
211  */
212 int kdebug_register_coproc(const char *name, kdebug_coproc_flags_t flags,
213     kd_callback_fn callback, void *context);
214 
215 void kernel_debug_enter(uint32_t coreid, uint32_t debugid, uint64_t timestamp,
216     uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4,
217     uintptr_t threadid);
218 
219 /*
220  * Legacy definitions for the prior IOP tracing.
221  */
222 
223 struct kd_callback {
224 	kd_callback_fn func;
225 	void *context;
226 	/* name of IOP, NUL-terminated */
227 	char iop_name[8];
228 };
229 typedef struct kd_callback kd_callback_t;
230 
231 __kpi_deprecated("use kdebug_register_coproc instead")
232 int kernel_debug_register_callback(kd_callback_t callback);
233 
234 #pragma mark - internals
235 
236 #define KDBG_(f, x, a, b, c, d, n, ...) KDBG##n(f, x, a, b, c, d)
237 #define KDBG0(f, x, a, b, c, d) KERNEL_DEBUG_CONSTANT##f(x, 0, 0, 0, 0, 0)
238 #define KDBG1(f, x, a, b, c, d) KERNEL_DEBUG_CONSTANT##f(x, a, 0, 0, 0, 0)
239 #define KDBG2(f, x, a, b, c, d) KERNEL_DEBUG_CONSTANT##f(x, a, b, 0, 0, 0)
240 #define KDBG3(f, x, a, b, c, d) KERNEL_DEBUG_CONSTANT##f(x, a, b, c, 0, 0)
241 #define KDBG4(f, x, a, b, c, d) KERNEL_DEBUG_CONSTANT##f(x, a, b, c, d, 0)
242 
243 #ifdef XNU_KERNEL_PRIVATE
244 #define KDBG_IMPROBABLE __improbable
245 #else
246 #define KDBG_IMPROBABLE
247 #endif
248 
249 extern unsigned int kdebug_enable;
250 
251 /*
252  * The kernel debug configuration level.  These values control which events are
253  * compiled in under different build configurations.
254  *
255  * Infer the supported kernel debug event level from config option.  Use
256  * (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) as a guard to protect unaudited debug
257  * code.
258  */
259 #define KDEBUG_LEVEL_NONE     0
260 #define KDEBUG_LEVEL_IST      1
261 #define KDEBUG_LEVEL_STANDARD 2
262 #define KDEBUG_LEVEL_FULL     3
263 
264 #if NO_KDEBUG
265 #define KDEBUG_LEVEL KDEBUG_LEVEL_NONE
266 #elif IST_KDEBUG
267 #define KDEBUG_LEVEL KDEBUG_LEVEL_IST
268 #elif KDEBUG
269 #define KDEBUG_LEVEL KDEBUG_LEVEL_FULL
270 #else
271 #define KDEBUG_LEVEL KDEBUG_LEVEL_STANDARD
272 /*
273  * Currently, all other kernel configurations (development, etc) build with
274  * KDEBUG_LEVEL_STANDARD.
275  */
276 #endif
277 
278 /*
279  * KERNEL_DEBUG_CONSTANT_FILTERED events are omitted from tracing unless they
280  * are explicitly requested in the typefilter.  They are not emitted when
281  * tracing without a typefilter.
282  */
283 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD)
284 #define KERNEL_DEBUG_CONSTANT_FILTERED(x, a, b, c, d, ...)           \
285 	do {                                                             \
286 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {   \
287 	                kernel_debug_filtered((x), (uintptr_t)(a), (uintptr_t)(b),  \
288 	                        (uintptr_t)(c), (uintptr_t)(d)); \
289 	        }                                                            \
290 	} while (0)
291 #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) */
292 #define KERNEL_DEBUG_CONSTANT_FILTERED(type, x, a, b, c, d, ...) do {} while (0)
293 #endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) */
294 
295 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
296 #define KERNEL_DEBUG_CONSTANT_RELEASE_NOPROCFILT(x, a, b, c, d, ...)   \
297 	do {                                                               \
298 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {     \
299 	                kernel_debug_flags((x), (uintptr_t)(a), (uintptr_t)(b),    \
300 	                        (uintptr_t)(c), (uintptr_t)(d), KDBG_NON_PROCESS); \
301 	        }                                                              \
302 	} while (0)
303 #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */
304 #define KERNEL_DEBUG_CONSTANT_RELEASE_NOPROCFILT(x, a, b, c, d, ...) \
305 	do { } while (0)
306 #endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */
307 
308 
309 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD)
310 #define KERNEL_DEBUG_CONSTANT(x, a, b, c, d, e)                               \
311 	do {                                                                      \
312 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {            \
313 	                kernel_debug((x), (uintptr_t)(a), (uintptr_t)(b), (uintptr_t)(c), \
314 	                        (uintptr_t)(d),(uintptr_t)(e));                               \
315 	        }                                                                     \
316 	} while (0)
317 
318 /*
319  * DO NOT USE THIS MACRO -- it breaks fundamental assumptions about ktrace and
320  * is only meant to be used by the pthread kext and other points in the kernel
321  * where the thread ID must be provided explicitly.
322  */
323 #define KERNEL_DEBUG_CONSTANT1(x, a, b, c, d, e)                               \
324 	do {                                                                       \
325 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {             \
326 	                kernel_debug1((x), (uintptr_t)(a), (uintptr_t)(b), (uintptr_t)(c), \
327 	                (uintptr_t)(d), (uintptr_t)(e));                                   \
328 	        }                                                                      \
329 	} while (0)
330 
331 #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) */
332 #define KERNEL_DEBUG_CONSTANT(x, a, b, c, d, e) do {} while (0)
333 #define KERNEL_DEBUG_CONSTANT1(x, a, b, c, d, e) do {} while (0)
334 #endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD) */
335 
336 /*
337  * KERNEL_DEBUG_CONSTANT_IST (in-system trace) events provide an audited subset
338  * of tracepoints for userland system tracing tools.  This tracing level was
339  * created by 8857227 to protect fairplayd and other PT_DENY_ATTACH processes.
340  * It has two effects: only KERNEL_DEBUG_CONSTANT_IST() traces are emitted and
341  * any PT_DENY_ATTACH processes will only emit basic traces as defined by the
342  * kernel_debug_filter() routine.
343  */
344 #define KERNEL_DEBUG_CONSTANT_RELEASE(x, a, b, c, d, e) \
345 	KERNEL_DEBUG_CONSTANT_IST(~KDEBUG_ENABLE_PPT, x, a, b, c, d, 0)
346 
347 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST)
348 #define KERNEL_DEBUG_CONSTANT_IST(type, x, a, b, c, d, e)                     \
349 	do {                                                                      \
350 	        if (KDBG_IMPROBABLE(kdebug_enable & (type))) {                        \
351 	                kernel_debug((x), (uintptr_t)(a), (uintptr_t)(b), (uintptr_t)(c), \
352 	                        (uintptr_t)(d), 0);                                           \
353 	        }                                                                     \
354 	} while (0)
355 
356 #define KERNEL_DEBUG_CONSTANT_IST1(x, a, b, c, d, e)                     \
357 	do {                                                                       \
358 	        if (KDBG_IMPROBABLE(kdebug_enable)) {                         \
359 	                kernel_debug1((x), (uintptr_t)(a), (uintptr_t)(b), (uintptr_t)(c), \
360 	                        (uintptr_t)(d), (uintptr_t)(e));                               \
361 	        }                                                                      \
362 	} while (0)
363 
364 #define KERNEL_DEBUG_EARLY(x, a, b, c, d)                                 \
365 	do {                                                                  \
366 	        kernel_debug_early((uint32_t)(x), (uintptr_t)(a), (uintptr_t)(b), \
367 	                (uintptr_t)(c), (uintptr_t)(d));                              \
368 	} while (0)
369 
370 #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */
371 #define KERNEL_DEBUG_CONSTANT_IST(type, x, a, b, c, d, e) do {} while (0)
372 #define KERNEL_DEBUG_CONSTANT_IST1(x, a, b, c, d, e) do {} while (0)
373 #define KERNEL_DEBUG_EARLY(x, a, b, c, d) do {} while (0)
374 #endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_IST) */
375 
376 #if NO_KDEBUG
377 #define __kdebug_constant_only __unused
378 #endif
379 
380 /*
381  * KERNEL_DEBUG events are only traced for DEBUG kernels.
382  */
383 #define KERNEL_DEBUG_CONSTANT_DEBUG(x, a, b, c, d, e) \
384 	KERNEL_DEBUG(x, a, b, c, d, e)
385 
386 #if (KDEBUG_LEVEL >= KDEBUG_LEVEL_FULL)
387 #define __kdebug_only
388 
389 #undef KERNEL_DEBUG
390 #define KERNEL_DEBUG(x, a, b, c, d, e)                                  \
391 	do {                                                                \
392 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {      \
393 	                kernel_debug((uint32_t)(x), (uintptr_t)(a), (uintptr_t)(b), \
394 	                        (uintptr_t)(c), (uintptr_t)(d), (uintptr_t)(e));        \
395 	        }                                                               \
396 	} while (0)
397 
398 /*
399  * DO NOT USE THIS MACRO -- see warning above for KERNEL_DEBUG_CONSTANT1.
400  */
401 #define KERNEL_DEBUG1(x, a, b, c, d, e)                                  \
402 	do {                                                                 \
403 	        if (KDBG_IMPROBABLE(kdebug_enable & ~KDEBUG_ENABLE_PPT)) {       \
404 	                kernel_debug1((uint32_t)(x), (uintptr_t)(a), (uintptr_t)(b), \
405 	                        (uintptr_t)(c), (uintptr_t)(d), (uintptr_t)(e));         \
406 	        }                                                                \
407 	} while (0)
408 
409 #else /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_FULL) */
410 #define __kdebug_only __unused
411 
412 #undef KERNEL_DEBUG
413 #define KERNEL_DEBUG(x, a, b, c, d, e) do {} while (0)
414 #define KERNEL_DEBUG1(x, a, b, c, d, e) do {} while (0)
415 #endif /* (KDEBUG_LEVEL >= KDEBUG_LEVEL_FULL) */
416 
417 void kernel_debug(uint32_t debugid, uintptr_t arg1, uintptr_t arg2,
418     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5);
419 
420 void kernel_debug1(uint32_t debugid, uintptr_t arg1, uintptr_t arg2,
421     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5);
422 
423 __options_decl(kdebug_emit_flags_t, uint64_t, {
424 	KDBG_FILTER_ONLY = 0x01,
425 	KDBG_NON_PROCESS = 0x02,
426 });
427 
428 void kernel_debug_flags(uint32_t debugid, uintptr_t arg1, uintptr_t arg2,
429     uintptr_t arg3, uintptr_t arg4, kdebug_emit_flags_t flags);
430 
431 void kernel_debug_filtered(uint32_t debugid, uintptr_t arg1, uintptr_t arg2,
432     uintptr_t arg3, uintptr_t arg4);
433 
434 #pragma mark - xnu API
435 
436 #ifdef XNU_KERNEL_PRIVATE
437 
438 void kdebug_startup(void);
439 
440 /* Used in early boot to log events. */
441 void kernel_debug_early(uint32_t  debugid, uintptr_t arg1, uintptr_t arg2,
442     uintptr_t arg3, uintptr_t arg4);
443 /* Used in early boot to log strings spanning only a single tracepoint. */
444 void kernel_debug_string_early(const char *message);
445 /* Used to trace strings within kdebug tracepoints on arbitrary eventids. */
446 void kernel_debug_string_simple(uint32_t eventid, const char *str);
447 /* Only used by ktrace to reset kdebug.  ktrace_lock must be held. */
448 extern void kdebug_reset(void);
449 
450 void kdbg_dump_trace_to_file(const char *, bool reenable);
451 
452 enum kdebug_opts {
453 	KDOPT_WRAPPING = 0x1,
454 	KDOPT_ATBOOT = 0x2,
455 };
456 
457 enum kdebug_mode {
458 	KDEBUG_MODE_TRACE = 0x1, /* General purpose tracing.*/
459 	KDEBUG_MODE_TRIAGE = 0x2, /* Collect more information to triage failures / gain insight into in-kernel operations of a thread.*/
460 };
461 
462 
463 int kdbg_bootstrap(bool early_trace, int mode);
464 void kdebug_init(unsigned int n_events, char *filterdesc,
465     enum kdebug_opts opts);
466 void kdebug_trace_start(unsigned int n_events, const char *filterdesc,
467     enum kdebug_opts opts);
468 uint64_t kdebug_wake(void);
469 void kdebug_free_early_buf(void);
470 
471 
472 struct proc;
473 void kdbg_trace_data(struct proc *proc, long *arg_pid, long *arg_uniqueid);
474 
475 __options_decl(kdebug_vfs_lookup_flags_t, uint32_t, {
476 	KDBG_VFSLKUP_LOOKUP = 0x01,
477 	KDBG_VFSLKUP_NOPROCFILT = 0x02,
478 });
479 #define KDBG_VFS_LOOKUP_FLAG_LOOKUP 0x01
480 #define KDBG_VFS_LOOKUP_FLAG_NOPROCFILT 0x02
481 void kdebug_vfs_lookup(const char *path_words, size_t path_len, void *vnp,
482     kdebug_vfs_lookup_flags_t flags);
483 
484 void ktriage_extract(uint64_t thread_id, void *buf, uint32_t bufsz);
485 
486 #endif /* XNU_KERNEL_PRIVATE */
487 
488 #ifdef KERNEL_PRIVATE
489 
490 typedef struct ktriage_strings {
491 	int num_strings;
492 	const char **strings;
493 } ktriage_strings_t;
494 
495 int ktriage_register_subsystem_strings(uint8_t subsystem, ktriage_strings_t *subsystem_strings);
496 int ktriage_unregister_subsystem_strings(uint8_t subsystem);
497 
498 void ktriage_record(uint64_t thread_id, uint64_t debugid, uintptr_t arg);
499 
500 #define NUMPARMS 23
501 void kdebug_lookup_gen_events(long *path_words, int path_len, void *vnp,
502     bool lookup);
503 
504 #pragma mark - EnergyTracing
505 
506 #define KERNEL_DBG_IST_SANE KDBG_RELEASE
507 #define ENTR_KDTRACEFUNC KDBG_RELEASE
508 
509 // value is int64_t, quality is uint32_t
510 #define KERNEL_ENERGYTRACE(opcode, lifespan, id, quality, value)        \
511 	    ENTR_KDTRACE(kEnTrCompKernel, opcode, lifespan, id,         \
512 	                 quality, value)
513 #define KERNEL_ENTR_ASSOCIATE(par_opcode, par_act_id, sub_opcode, sub_act_id) \
514 	    ENTR_KDASSOCIATE(kEnTrCompKernel, par_opcode, par_act_id,   \
515 	                     kEnTrCompKernel, sub_opcode, sub_act_id)
516 
517 #endif /* KERNEL_PRIVATE */
518 
519 #endif /* KERNEL */
520 
521 __END_DECLS
522 
523 #endif /* !defined(BSD_SYS_KDEBUG_KERNEL_H) */
524