Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | S390 Debug Feature |
2 | ================== | |
3 | ||
4 | files: arch/s390/kernel/debug.c | |
5 | include/asm-s390/debug.h | |
6 | ||
7 | Description: | |
8 | ------------ | |
9 | The goal of this feature is to provide a kernel debug logging API | |
10 | where log records can be stored efficiently in memory, where each component | |
11 | (e.g. device drivers) can have one separate debug log. | |
12 | One purpose of this is to inspect the debug logs after a production system crash | |
13 | in order to analyze the reason for the crash. | |
a2ffd275 | 14 | If the system still runs but only a subcomponent which uses dbf fails, |
66a464db MH |
15 | it is possible to look at the debug logs on a live system via the Linux |
16 | debugfs filesystem. | |
1da177e4 LT |
17 | The debug feature may also very useful for kernel and driver development. |
18 | ||
19 | Design: | |
20 | ------- | |
21 | Kernel components (e.g. device drivers) can register themselves at the debug | |
22 | feature with the function call debug_register(). This function initializes a | |
23 | debug log for the caller. For each debug log exists a number of debug areas | |
24 | where exactly one is active at one time. Each debug area consists of contiguous | |
25 | pages in memory. In the debug areas there are stored debug entries (log records) | |
26 | which are written by event- and exception-calls. | |
27 | ||
28 | An event-call writes the specified debug entry to the active debug | |
29 | area and updates the log pointer for the active area. If the end | |
30 | of the active debug area is reached, a wrap around is done (ring buffer) | |
31 | and the next debug entry will be written at the beginning of the active | |
32 | debug area. | |
33 | ||
34 | An exception-call writes the specified debug entry to the log and | |
35 | switches to the next debug area. This is done in order to be sure | |
36 | that the records which describe the origin of the exception are not | |
37 | overwritten when a wrap around for the current area occurs. | |
38 | ||
39 | The debug areas itselve are also ordered in form of a ring buffer. | |
40 | When an exception is thrown in the last debug area, the following debug | |
41 | entries are then written again in the very first area. | |
42 | ||
43 | There are three versions for the event- and exception-calls: One for | |
44 | logging raw data, one for text and one for numbers. | |
45 | ||
46 | Each debug entry contains the following data: | |
47 | ||
48 | - Timestamp | |
49 | - Cpu-Number of calling task | |
50 | - Level of debug entry (0...6) | |
51 | - Return Address to caller | |
52 | - Flag, if entry is an exception or not | |
53 | ||
54 | The debug logs can be inspected in a live system through entries in | |
66a464db | 55 | the debugfs-filesystem. Under the toplevel directory "s390dbf" there is |
1da177e4 | 56 | a directory for each registered component, which is named like the |
66a464db MH |
57 | corresponding component. The debugfs normally should be mounted to |
58 | /sys/kernel/debug therefore the debug feature can be accessed unter | |
59 | /sys/kernel/debug/s390dbf. | |
1da177e4 LT |
60 | |
61 | The content of the directories are files which represent different views | |
62 | to the debug log. Each component can decide which views should be | |
63 | used through registering them with the function debug_register_view(). | |
64 | Predefined views for hex/ascii, sprintf and raw binary data are provided. | |
65 | It is also possible to define other views. The content of | |
66a464db | 66 | a view can be inspected simply by reading the corresponding debugfs file. |
1da177e4 | 67 | |
670e9f34 | 68 | All debug logs have an actual debug level (range from 0 to 6). |
1da177e4 LT |
69 | The default level is 3. Event and Exception functions have a 'level' |
70 | parameter. Only debug entries with a level that is lower or equal | |
71 | than the actual level are written to the log. This means, when | |
72 | writing events, high priority log entries should have a low level | |
73 | value whereas low priority entries should have a high one. | |
66a464db MH |
74 | The actual debug level can be changed with the help of the debugfs-filesystem |
75 | through writing a number string "x" to the 'level' debugfs file which is | |
1da177e4 | 76 | provided for every debug log. Debugging can be switched off completely |
66a464db | 77 | by using "-" on the 'level' debugfs file. |
1da177e4 LT |
78 | |
79 | Example: | |
80 | ||
66a464db | 81 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/level |
1da177e4 LT |
82 | |
83 | It is also possible to deactivate the debug feature globally for every | |
84 | debug log. You can change the behavior using 2 sysctl parameters in | |
85 | /proc/sys/s390dbf: | |
992caacf ML |
86 | There are currently 2 possible triggers, which stop the debug feature |
87 | globally. The first possibility is to use the "debug_active" sysctl. If | |
1da177e4 LT |
88 | set to 1 the debug feature is running. If "debug_active" is set to 0 the |
89 | debug feature is turned off. | |
90 | The second trigger which stops the debug feature is an kernel oops. | |
91 | That prevents the debug feature from overwriting debug information that | |
92 | happened before the oops. After an oops you can reactivate the debug feature | |
93 | by piping 1 to /proc/sys/s390dbf/debug_active. Nevertheless, its not | |
94 | suggested to use an oopsed kernel in an production environment. | |
95 | If you want to disallow the deactivation of the debug feature, you can use | |
96 | the "debug_stoppable" sysctl. If you set "debug_stoppable" to 0 the debug | |
97 | feature cannot be stopped. If the debug feature is already stopped, it | |
98 | will stay deactivated. | |
99 | ||
100 | Kernel Interfaces: | |
101 | ------------------ | |
102 | ||
103 | ---------------------------------------------------------------------------- | |
66a464db | 104 | debug_info_t *debug_register(char *name, int pages, int nr_areas, |
1da177e4 LT |
105 | int buf_size); |
106 | ||
66a464db MH |
107 | Parameter: name: Name of debug log (e.g. used for debugfs entry) |
108 | pages: number of pages, which will be allocated per area | |
1da177e4 LT |
109 | nr_areas: number of debug areas |
110 | buf_size: size of data area in each debug entry | |
111 | ||
112 | Return Value: Handle for generated debug area | |
113 | NULL if register failed | |
114 | ||
115 | Description: Allocates memory for a debug log | |
116 | Must not be called within an interrupt handler | |
117 | ||
118 | --------------------------------------------------------------------------- | |
119 | void debug_unregister (debug_info_t * id); | |
120 | ||
121 | Parameter: id: handle for debug log | |
122 | ||
123 | Return Value: none | |
124 | ||
125 | Description: frees memory for a debug log | |
126 | Must not be called within an interrupt handler | |
127 | ||
128 | --------------------------------------------------------------------------- | |
129 | void debug_set_level (debug_info_t * id, int new_level); | |
130 | ||
131 | Parameter: id: handle for debug log | |
132 | new_level: new debug level | |
133 | ||
134 | Return Value: none | |
135 | ||
136 | Description: Sets new actual debug level if new_level is valid. | |
137 | ||
138 | --------------------------------------------------------------------------- | |
66a464db | 139 | void debug_stop_all(void); |
1da177e4 LT |
140 | |
141 | Parameter: none | |
142 | ||
143 | Return Value: none | |
144 | ||
145 | Description: stops the debug feature if stopping is allowed. Currently | |
146 | used in case of a kernel oops. | |
147 | ||
148 | --------------------------------------------------------------------------- | |
149 | debug_entry_t* debug_event (debug_info_t* id, int level, void* data, | |
150 | int length); | |
151 | ||
152 | Parameter: id: handle for debug log | |
153 | level: debug level | |
154 | data: pointer to data for debug entry | |
155 | length: length of data in bytes | |
156 | ||
157 | Return Value: Address of written debug entry | |
158 | ||
159 | Description: writes debug entry to active debug area (if level <= actual | |
160 | debug level) | |
161 | ||
162 | --------------------------------------------------------------------------- | |
163 | debug_entry_t* debug_int_event (debug_info_t * id, int level, | |
164 | unsigned int data); | |
165 | debug_entry_t* debug_long_event(debug_info_t * id, int level, | |
166 | unsigned long data); | |
167 | ||
168 | Parameter: id: handle for debug log | |
169 | level: debug level | |
170 | data: integer value for debug entry | |
171 | ||
172 | Return Value: Address of written debug entry | |
173 | ||
174 | Description: writes debug entry to active debug area (if level <= actual | |
175 | debug level) | |
176 | ||
177 | --------------------------------------------------------------------------- | |
178 | debug_entry_t* debug_text_event (debug_info_t * id, int level, | |
179 | const char* data); | |
180 | ||
181 | Parameter: id: handle for debug log | |
182 | level: debug level | |
183 | data: string for debug entry | |
184 | ||
185 | Return Value: Address of written debug entry | |
186 | ||
187 | Description: writes debug entry in ascii format to active debug area | |
188 | (if level <= actual debug level) | |
189 | ||
190 | --------------------------------------------------------------------------- | |
191 | debug_entry_t* debug_sprintf_event (debug_info_t * id, int level, | |
192 | char* string,...); | |
193 | ||
194 | Parameter: id: handle for debug log | |
195 | level: debug level | |
196 | string: format string for debug entry | |
197 | ...: varargs used as in sprintf() | |
198 | ||
199 | Return Value: Address of written debug entry | |
200 | ||
201 | Description: writes debug entry with format string and varargs (longs) to | |
202 | active debug area (if level $<=$ actual debug level). | |
203 | floats and long long datatypes cannot be used as varargs. | |
204 | ||
205 | --------------------------------------------------------------------------- | |
206 | ||
207 | debug_entry_t* debug_exception (debug_info_t* id, int level, void* data, | |
208 | int length); | |
209 | ||
210 | Parameter: id: handle for debug log | |
211 | level: debug level | |
212 | data: pointer to data for debug entry | |
213 | length: length of data in bytes | |
214 | ||
215 | Return Value: Address of written debug entry | |
216 | ||
217 | Description: writes debug entry to active debug area (if level <= actual | |
218 | debug level) and switches to next debug area | |
219 | ||
220 | --------------------------------------------------------------------------- | |
221 | debug_entry_t* debug_int_exception (debug_info_t * id, int level, | |
222 | unsigned int data); | |
223 | debug_entry_t* debug_long_exception(debug_info_t * id, int level, | |
224 | unsigned long data); | |
225 | ||
226 | Parameter: id: handle for debug log | |
227 | level: debug level | |
228 | data: integer value for debug entry | |
229 | ||
230 | Return Value: Address of written debug entry | |
231 | ||
232 | Description: writes debug entry to active debug area (if level <= actual | |
233 | debug level) and switches to next debug area | |
234 | ||
235 | --------------------------------------------------------------------------- | |
236 | debug_entry_t* debug_text_exception (debug_info_t * id, int level, | |
237 | const char* data); | |
238 | ||
239 | Parameter: id: handle for debug log | |
240 | level: debug level | |
241 | data: string for debug entry | |
242 | ||
243 | Return Value: Address of written debug entry | |
244 | ||
245 | Description: writes debug entry in ascii format to active debug area | |
246 | (if level <= actual debug level) and switches to next debug | |
247 | area | |
248 | ||
249 | --------------------------------------------------------------------------- | |
250 | debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level, | |
251 | char* string,...); | |
252 | ||
253 | Parameter: id: handle for debug log | |
254 | level: debug level | |
255 | string: format string for debug entry | |
256 | ...: varargs used as in sprintf() | |
257 | ||
258 | Return Value: Address of written debug entry | |
259 | ||
260 | Description: writes debug entry with format string and varargs (longs) to | |
261 | active debug area (if level $<=$ actual debug level) and | |
262 | switches to next debug area. | |
263 | floats and long long datatypes cannot be used as varargs. | |
264 | ||
265 | --------------------------------------------------------------------------- | |
266 | ||
267 | int debug_register_view (debug_info_t * id, struct debug_view *view); | |
268 | ||
269 | Parameter: id: handle for debug log | |
270 | view: pointer to debug view struct | |
271 | ||
272 | Return Value: 0 : ok | |
273 | < 0: Error | |
274 | ||
66a464db | 275 | Description: registers new debug view and creates debugfs dir entry |
1da177e4 LT |
276 | |
277 | --------------------------------------------------------------------------- | |
278 | int debug_unregister_view (debug_info_t * id, struct debug_view *view); | |
279 | ||
280 | Parameter: id: handle for debug log | |
281 | view: pointer to debug view struct | |
282 | ||
283 | Return Value: 0 : ok | |
284 | < 0: Error | |
285 | ||
66a464db | 286 | Description: unregisters debug view and removes debugfs dir entry |
1da177e4 LT |
287 | |
288 | ||
289 | ||
290 | Predefined views: | |
291 | ----------------- | |
292 | ||
293 | extern struct debug_view debug_hex_ascii_view; | |
294 | extern struct debug_view debug_raw_view; | |
295 | extern struct debug_view debug_sprintf_view; | |
296 | ||
297 | Examples | |
298 | -------- | |
299 | ||
300 | /* | |
301 | * hex_ascii- + raw-view Example | |
302 | */ | |
303 | ||
304 | #include <linux/init.h> | |
305 | #include <asm/debug.h> | |
306 | ||
307 | static debug_info_t* debug_info; | |
308 | ||
309 | static int init(void) | |
310 | { | |
311 | /* register 4 debug areas with one page each and 4 byte data field */ | |
312 | ||
66a464db | 313 | debug_info = debug_register ("test", 1, 4, 4 ); |
1da177e4 LT |
314 | debug_register_view(debug_info,&debug_hex_ascii_view); |
315 | debug_register_view(debug_info,&debug_raw_view); | |
316 | ||
317 | debug_text_event(debug_info, 4 , "one "); | |
318 | debug_int_exception(debug_info, 4, 4711); | |
319 | debug_event(debug_info, 3, &debug_info, 4); | |
320 | ||
321 | return 0; | |
322 | } | |
323 | ||
324 | static void cleanup(void) | |
325 | { | |
326 | debug_unregister (debug_info); | |
327 | } | |
328 | ||
329 | module_init(init); | |
330 | module_exit(cleanup); | |
331 | ||
332 | --------------------------------------------------------------------------- | |
333 | ||
334 | /* | |
335 | * sprintf-view Example | |
336 | */ | |
337 | ||
338 | #include <linux/init.h> | |
339 | #include <asm/debug.h> | |
340 | ||
341 | static debug_info_t* debug_info; | |
342 | ||
343 | static int init(void) | |
344 | { | |
345 | /* register 4 debug areas with one page each and data field for */ | |
346 | /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ | |
347 | ||
66a464db | 348 | debug_info = debug_register ("test", 1, 4, sizeof(long) * 3); |
1da177e4 LT |
349 | debug_register_view(debug_info,&debug_sprintf_view); |
350 | ||
351 | debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); | |
352 | debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info); | |
353 | ||
354 | return 0; | |
355 | } | |
356 | ||
357 | static void cleanup(void) | |
358 | { | |
359 | debug_unregister (debug_info); | |
360 | } | |
361 | ||
362 | module_init(init); | |
363 | module_exit(cleanup); | |
364 | ||
365 | ||
366 | ||
66a464db | 367 | Debugfs Interface |
1da177e4 LT |
368 | ---------------- |
369 | Views to the debug logs can be investigated through reading the corresponding | |
66a464db | 370 | debugfs-files: |
1da177e4 LT |
371 | |
372 | Example: | |
373 | ||
66a464db MH |
374 | > ls /sys/kernel/debug/s390dbf/dasd |
375 | flush hex_ascii level pages raw | |
376 | > cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort +1 | |
1da177e4 LT |
377 | 00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... |
378 | 00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE | |
379 | 00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... | |
380 | 00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP | |
381 | 01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD | |
382 | 01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | .... | |
383 | 01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ... | |
384 | 01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | .... | |
385 | 01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE | |
386 | 01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | .... | |
387 | ||
388 | See section about predefined views for explanation of the above output! | |
389 | ||
390 | Changing the debug level | |
391 | ------------------------ | |
392 | ||
393 | Example: | |
394 | ||
395 | ||
66a464db | 396 | > cat /sys/kernel/debug/s390dbf/dasd/level |
1da177e4 | 397 | 3 |
66a464db MH |
398 | > echo "5" > /sys/kernel/debug/s390dbf/dasd/level |
399 | > cat /sys/kernel/debug/s390dbf/dasd/level | |
1da177e4 LT |
400 | 5 |
401 | ||
402 | Flushing debug areas | |
403 | -------------------- | |
404 | Debug areas can be flushed with piping the number of the desired | |
66a464db | 405 | area (0...n) to the debugfs file "flush". When using "-" all debug areas |
1da177e4 LT |
406 | are flushed. |
407 | ||
408 | Examples: | |
409 | ||
410 | 1. Flush debug area 0: | |
66a464db | 411 | > echo "0" > /sys/kernel/debug/s390dbf/dasd/flush |
1da177e4 LT |
412 | |
413 | 2. Flush all debug areas: | |
66a464db MH |
414 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/flush |
415 | ||
416 | Changing the size of debug areas | |
417 | ------------------------------------ | |
418 | It is possible the change the size of debug areas through piping | |
419 | the number of pages to the debugfs file "pages". The resize request will | |
420 | also flush the debug areas. | |
421 | ||
422 | Example: | |
423 | ||
424 | Define 4 pages for the debug areas of debug feature "dasd": | |
425 | > echo "4" > /sys/kernel/debug/s390dbf/dasd/pages | |
1da177e4 LT |
426 | |
427 | Stooping the debug feature | |
428 | -------------------------- | |
429 | Example: | |
430 | ||
431 | 1. Check if stopping is allowed | |
432 | > cat /proc/sys/s390dbf/debug_stoppable | |
433 | 2. Stop debug feature | |
434 | > echo 0 > /proc/sys/s390dbf/debug_active | |
435 | ||
436 | lcrash Interface | |
437 | ---------------- | |
438 | It is planned that the dump analysis tool lcrash gets an additional command | |
439 | 's390dbf' to display all the debug logs. With this tool it will be possible | |
440 | to investigate the debug logs on a live system and with a memory dump after | |
441 | a system crash. | |
442 | ||
443 | Investigating raw memory | |
444 | ------------------------ | |
445 | One last possibility to investigate the debug logs at a live | |
446 | system and after a system crash is to look at the raw memory | |
447 | under VM or at the Service Element. | |
448 | It is possible to find the anker of the debug-logs through | |
449 | the 'debug_area_first' symbol in the System map. Then one has | |
450 | to follow the correct pointers of the data-structures defined | |
451 | in debug.h and find the debug-areas in memory. | |
452 | Normally modules which use the debug feature will also have | |
453 | a global variable with the pointer to the debug-logs. Following | |
454 | this pointer it will also be possible to find the debug logs in | |
455 | memory. | |
456 | ||
457 | For this method it is recommended to use '16 * x + 4' byte (x = 0..n) | |
458 | for the length of the data field in debug_register() in | |
459 | order to see the debug entries well formatted. | |
460 | ||
461 | ||
462 | Predefined Views | |
463 | ---------------- | |
464 | ||
465 | There are three predefined views: hex_ascii, raw and sprintf. | |
466 | The hex_ascii view shows the data field in hex and ascii representation | |
467 | (e.g. '45 43 4b 44 | ECKD'). | |
468 | The raw view returns a bytestream as the debug areas are stored in memory. | |
469 | ||
470 | The sprintf view formats the debug entries in the same way as the sprintf | |
fff9289b | 471 | function would do. The sprintf event/exception functions write to the |
1da177e4 LT |
472 | debug entry a pointer to the format string (size = sizeof(long)) |
473 | and for each vararg a long value. So e.g. for a debug entry with a format | |
474 | string plus two varargs one would need to allocate a (3 * sizeof(long)) | |
475 | byte data area in the debug_register() function. | |
476 | ||
477 | ||
478 | NOTE: If using the sprintf view do NOT use other event/exception functions | |
479 | than the sprintf-event and -exception functions. | |
480 | ||
481 | The format of the hex_ascii and sprintf view is as follows: | |
482 | - Number of area | |
483 | - Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated | |
484 | Universal Time (UTC), January 1, 1970) | |
485 | - level of debug entry | |
486 | - Exception flag (* = Exception) | |
487 | - Cpu-Number of calling task | |
488 | - Return Address to caller | |
489 | - data field | |
490 | ||
491 | The format of the raw view is: | |
492 | - Header as described in debug.h | |
493 | - datafield | |
494 | ||
495 | A typical line of the hex_ascii view will look like the following (first line | |
496 | is only for explanation and will not be displayed when 'cating' the view): | |
497 | ||
498 | area time level exception cpu caller data (hex + ascii) | |
499 | -------------------------------------------------------------------------- | |
500 | 00 00964419409:440690 1 - 00 88023fe | |
501 | ||
502 | ||
503 | Defining views | |
504 | -------------- | |
505 | ||
506 | Views are specified with the 'debug_view' structure. There are defined | |
66a464db | 507 | callback functions which are used for reading and writing the debugfs files: |
1da177e4 LT |
508 | |
509 | struct debug_view { | |
510 | char name[DEBUG_MAX_PROCF_LEN]; | |
511 | debug_prolog_proc_t* prolog_proc; | |
512 | debug_header_proc_t* header_proc; | |
513 | debug_format_proc_t* format_proc; | |
514 | debug_input_proc_t* input_proc; | |
515 | void* private_data; | |
516 | }; | |
517 | ||
518 | where | |
519 | ||
520 | typedef int (debug_header_proc_t) (debug_info_t* id, | |
521 | struct debug_view* view, | |
522 | int area, | |
523 | debug_entry_t* entry, | |
524 | char* out_buf); | |
525 | ||
526 | typedef int (debug_format_proc_t) (debug_info_t* id, | |
527 | struct debug_view* view, char* out_buf, | |
528 | const char* in_buf); | |
529 | typedef int (debug_prolog_proc_t) (debug_info_t* id, | |
530 | struct debug_view* view, | |
531 | char* out_buf); | |
532 | typedef int (debug_input_proc_t) (debug_info_t* id, | |
533 | struct debug_view* view, | |
534 | struct file* file, const char* user_buf, | |
535 | size_t in_buf_size, loff_t* offset); | |
536 | ||
537 | ||
538 | The "private_data" member can be used as pointer to view specific data. | |
539 | It is not used by the debug feature itself. | |
540 | ||
66a464db | 541 | The output when reading a debugfs file is structured like this: |
1da177e4 LT |
542 | |
543 | "prolog_proc output" | |
544 | ||
545 | "header_proc output 1" "format_proc output 1" | |
546 | "header_proc output 2" "format_proc output 2" | |
547 | "header_proc output 3" "format_proc output 3" | |
548 | ... | |
549 | ||
66a464db | 550 | When a view is read from the debugfs, the Debug Feature calls the |
1da177e4 LT |
551 | 'prolog_proc' once for writing the prolog. |
552 | Then 'header_proc' and 'format_proc' are called for each | |
553 | existing debug entry. | |
554 | ||
555 | The input_proc can be used to implement functionality when it is written to | |
66a464db | 556 | the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level). |
1da177e4 LT |
557 | |
558 | For header_proc there can be used the default function | |
670e9f34 | 559 | debug_dflt_header_fn() which is defined in debug.h. |
1da177e4 LT |
560 | and which produces the same header output as the predefined views. |
561 | E.g: | |
562 | 00 00964419409:440761 2 - 00 88023ec | |
563 | ||
564 | In order to see how to use the callback functions check the implementation | |
565 | of the default views! | |
566 | ||
567 | Example | |
568 | ||
569 | #include <asm/debug.h> | |
570 | ||
571 | #define UNKNOWNSTR "data: %08x" | |
572 | ||
573 | const char* messages[] = | |
574 | {"This error...........\n", | |
575 | "That error...........\n", | |
576 | "Problem..............\n", | |
577 | "Something went wrong.\n", | |
578 | "Everything ok........\n", | |
579 | NULL | |
580 | }; | |
581 | ||
582 | static int debug_test_format_fn( | |
583 | debug_info_t * id, struct debug_view *view, | |
584 | char *out_buf, const char *in_buf | |
585 | ) | |
586 | { | |
587 | int i, rc = 0; | |
588 | ||
589 | if(id->buf_size >= 4) { | |
590 | int msg_nr = *((int*)in_buf); | |
591 | if(msg_nr < sizeof(messages)/sizeof(char*) - 1) | |
592 | rc += sprintf(out_buf, "%s", messages[msg_nr]); | |
593 | else | |
594 | rc += sprintf(out_buf, UNKNOWNSTR, msg_nr); | |
595 | } | |
596 | out: | |
597 | return rc; | |
598 | } | |
599 | ||
600 | struct debug_view debug_test_view = { | |
601 | "myview", /* name of view */ | |
602 | NULL, /* no prolog */ | |
603 | &debug_dflt_header_fn, /* default header for each entry */ | |
604 | &debug_test_format_fn, /* our own format function */ | |
605 | NULL, /* no input function */ | |
606 | NULL /* no private data */ | |
607 | }; | |
608 | ||
609 | ===== | |
610 | test: | |
611 | ===== | |
612 | debug_info_t *debug_info; | |
613 | ... | |
614 | debug_info = debug_register ("test", 0, 4, 4 )); | |
615 | debug_register_view(debug_info, &debug_test_view); | |
616 | for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i); | |
617 | ||
66a464db | 618 | > cat /sys/kernel/debug/s390dbf/test/myview |
1da177e4 LT |
619 | 00 00964419734:611402 1 - 00 88042ca This error........... |
620 | 00 00964419734:611405 1 - 00 88042ca That error........... | |
621 | 00 00964419734:611408 1 - 00 88042ca Problem.............. | |
622 | 00 00964419734:611411 1 - 00 88042ca Something went wrong. | |
623 | 00 00964419734:611414 1 - 00 88042ca Everything ok........ | |
624 | 00 00964419734:611417 1 - 00 88042ca data: 00000005 | |
625 | 00 00964419734:611419 1 - 00 88042ca data: 00000006 | |
626 | 00 00964419734:611422 1 - 00 88042ca data: 00000007 | |
627 | 00 00964419734:611425 1 - 00 88042ca data: 00000008 | |
628 | 00 00964419734:611428 1 - 00 88042ca data: 00000009 |