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 | ||
2254f5a7 | 39 | The debug areas themselves are also ordered in form of a ring buffer. |
1da177e4 LT |
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 | 57 | corresponding component. The debugfs normally should be mounted to |
2254f5a7 | 58 | /sys/kernel/debug therefore the debug feature can be accessed under |
66a464db | 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. | |
2254f5a7 | 90 | The second trigger which stops the debug feature is a kernel oops. |
1da177e4 LT |
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 | |
2254f5a7 | 94 | suggested to use an oopsed kernel in a production environment. |
1da177e4 LT |
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 | ||
9637c3f3 MH |
118 | ---------------------------------------------------------------------------- |
119 | debug_info_t *debug_register_mode(char *name, int pages, int nr_areas, | |
120 | int buf_size, mode_t mode, uid_t uid, | |
121 | gid_t gid); | |
122 | ||
123 | Parameter: name: Name of debug log (e.g. used for debugfs entry) | |
124 | pages: Number of pages, which will be allocated per area | |
125 | nr_areas: Number of debug areas | |
126 | buf_size: Size of data area in each debug entry | |
127 | mode: File mode for debugfs files. E.g. S_IRWXUGO | |
128 | uid: User ID for debugfs files. Currently only 0 is | |
129 | supported. | |
130 | gid: Group ID for debugfs files. Currently only 0 is | |
131 | supported. | |
132 | ||
133 | Return Value: Handle for generated debug area | |
134 | NULL if register failed | |
135 | ||
136 | Description: Allocates memory for a debug log | |
137 | Must not be called within an interrupt handler | |
138 | ||
1da177e4 LT |
139 | --------------------------------------------------------------------------- |
140 | void debug_unregister (debug_info_t * id); | |
141 | ||
142 | Parameter: id: handle for debug log | |
143 | ||
144 | Return Value: none | |
145 | ||
146 | Description: frees memory for a debug log | |
147 | Must not be called within an interrupt handler | |
148 | ||
149 | --------------------------------------------------------------------------- | |
150 | void debug_set_level (debug_info_t * id, int new_level); | |
151 | ||
152 | Parameter: id: handle for debug log | |
153 | new_level: new debug level | |
154 | ||
155 | Return Value: none | |
156 | ||
157 | Description: Sets new actual debug level if new_level is valid. | |
158 | ||
159 | --------------------------------------------------------------------------- | |
66a464db | 160 | void debug_stop_all(void); |
1da177e4 LT |
161 | |
162 | Parameter: none | |
163 | ||
164 | Return Value: none | |
165 | ||
166 | Description: stops the debug feature if stopping is allowed. Currently | |
167 | used in case of a kernel oops. | |
168 | ||
169 | --------------------------------------------------------------------------- | |
170 | debug_entry_t* debug_event (debug_info_t* id, int level, void* data, | |
171 | int length); | |
172 | ||
173 | Parameter: id: handle for debug log | |
174 | level: debug level | |
175 | data: pointer to data for debug entry | |
176 | length: length of data in bytes | |
177 | ||
178 | Return Value: Address of written debug entry | |
179 | ||
180 | Description: writes debug entry to active debug area (if level <= actual | |
181 | debug level) | |
182 | ||
183 | --------------------------------------------------------------------------- | |
184 | debug_entry_t* debug_int_event (debug_info_t * id, int level, | |
185 | unsigned int data); | |
186 | debug_entry_t* debug_long_event(debug_info_t * id, int level, | |
187 | unsigned long data); | |
188 | ||
189 | Parameter: id: handle for debug log | |
190 | level: debug level | |
191 | data: integer value for debug entry | |
192 | ||
193 | Return Value: Address of written debug entry | |
194 | ||
195 | Description: writes debug entry to active debug area (if level <= actual | |
196 | debug level) | |
197 | ||
198 | --------------------------------------------------------------------------- | |
199 | debug_entry_t* debug_text_event (debug_info_t * id, int level, | |
200 | const char* data); | |
201 | ||
202 | Parameter: id: handle for debug log | |
203 | level: debug level | |
204 | data: string for debug entry | |
205 | ||
206 | Return Value: Address of written debug entry | |
207 | ||
208 | Description: writes debug entry in ascii format to active debug area | |
209 | (if level <= actual debug level) | |
210 | ||
211 | --------------------------------------------------------------------------- | |
212 | debug_entry_t* debug_sprintf_event (debug_info_t * id, int level, | |
213 | char* string,...); | |
214 | ||
215 | Parameter: id: handle for debug log | |
216 | level: debug level | |
217 | string: format string for debug entry | |
218 | ...: varargs used as in sprintf() | |
219 | ||
220 | Return Value: Address of written debug entry | |
221 | ||
222 | Description: writes debug entry with format string and varargs (longs) to | |
223 | active debug area (if level $<=$ actual debug level). | |
224 | floats and long long datatypes cannot be used as varargs. | |
225 | ||
226 | --------------------------------------------------------------------------- | |
227 | ||
228 | debug_entry_t* debug_exception (debug_info_t* id, int level, void* data, | |
229 | int length); | |
230 | ||
231 | Parameter: id: handle for debug log | |
232 | level: debug level | |
233 | data: pointer to data for debug entry | |
234 | length: length of data in bytes | |
235 | ||
236 | Return Value: Address of written debug entry | |
237 | ||
238 | Description: writes debug entry to active debug area (if level <= actual | |
239 | debug level) and switches to next debug area | |
240 | ||
241 | --------------------------------------------------------------------------- | |
242 | debug_entry_t* debug_int_exception (debug_info_t * id, int level, | |
243 | unsigned int data); | |
244 | debug_entry_t* debug_long_exception(debug_info_t * id, int level, | |
245 | unsigned long data); | |
246 | ||
247 | Parameter: id: handle for debug log | |
248 | level: debug level | |
249 | data: integer value for debug entry | |
250 | ||
251 | Return Value: Address of written debug entry | |
252 | ||
253 | Description: writes debug entry to active debug area (if level <= actual | |
254 | debug level) and switches to next debug area | |
255 | ||
256 | --------------------------------------------------------------------------- | |
257 | debug_entry_t* debug_text_exception (debug_info_t * id, int level, | |
258 | const char* data); | |
259 | ||
260 | Parameter: id: handle for debug log | |
261 | level: debug level | |
262 | data: string for debug entry | |
263 | ||
264 | Return Value: Address of written debug entry | |
265 | ||
266 | Description: writes debug entry in ascii format to active debug area | |
267 | (if level <= actual debug level) and switches to next debug | |
268 | area | |
269 | ||
270 | --------------------------------------------------------------------------- | |
271 | debug_entry_t* debug_sprintf_exception (debug_info_t * id, int level, | |
272 | char* string,...); | |
273 | ||
274 | Parameter: id: handle for debug log | |
275 | level: debug level | |
276 | string: format string for debug entry | |
277 | ...: varargs used as in sprintf() | |
278 | ||
279 | Return Value: Address of written debug entry | |
280 | ||
281 | Description: writes debug entry with format string and varargs (longs) to | |
282 | active debug area (if level $<=$ actual debug level) and | |
283 | switches to next debug area. | |
284 | floats and long long datatypes cannot be used as varargs. | |
285 | ||
286 | --------------------------------------------------------------------------- | |
287 | ||
288 | int debug_register_view (debug_info_t * id, struct debug_view *view); | |
289 | ||
290 | Parameter: id: handle for debug log | |
291 | view: pointer to debug view struct | |
292 | ||
293 | Return Value: 0 : ok | |
294 | < 0: Error | |
295 | ||
66a464db | 296 | Description: registers new debug view and creates debugfs dir entry |
1da177e4 LT |
297 | |
298 | --------------------------------------------------------------------------- | |
299 | int debug_unregister_view (debug_info_t * id, struct debug_view *view); | |
300 | ||
301 | Parameter: id: handle for debug log | |
302 | view: pointer to debug view struct | |
303 | ||
304 | Return Value: 0 : ok | |
305 | < 0: Error | |
306 | ||
66a464db | 307 | Description: unregisters debug view and removes debugfs dir entry |
1da177e4 LT |
308 | |
309 | ||
310 | ||
311 | Predefined views: | |
312 | ----------------- | |
313 | ||
314 | extern struct debug_view debug_hex_ascii_view; | |
315 | extern struct debug_view debug_raw_view; | |
316 | extern struct debug_view debug_sprintf_view; | |
317 | ||
318 | Examples | |
319 | -------- | |
320 | ||
321 | /* | |
322 | * hex_ascii- + raw-view Example | |
323 | */ | |
324 | ||
325 | #include <linux/init.h> | |
326 | #include <asm/debug.h> | |
327 | ||
328 | static debug_info_t* debug_info; | |
329 | ||
330 | static int init(void) | |
331 | { | |
332 | /* register 4 debug areas with one page each and 4 byte data field */ | |
333 | ||
66a464db | 334 | debug_info = debug_register ("test", 1, 4, 4 ); |
1da177e4 LT |
335 | debug_register_view(debug_info,&debug_hex_ascii_view); |
336 | debug_register_view(debug_info,&debug_raw_view); | |
337 | ||
338 | debug_text_event(debug_info, 4 , "one "); | |
339 | debug_int_exception(debug_info, 4, 4711); | |
340 | debug_event(debug_info, 3, &debug_info, 4); | |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
345 | static void cleanup(void) | |
346 | { | |
347 | debug_unregister (debug_info); | |
348 | } | |
349 | ||
350 | module_init(init); | |
351 | module_exit(cleanup); | |
352 | ||
353 | --------------------------------------------------------------------------- | |
354 | ||
355 | /* | |
356 | * sprintf-view Example | |
357 | */ | |
358 | ||
359 | #include <linux/init.h> | |
360 | #include <asm/debug.h> | |
361 | ||
362 | static debug_info_t* debug_info; | |
363 | ||
364 | static int init(void) | |
365 | { | |
366 | /* register 4 debug areas with one page each and data field for */ | |
367 | /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ | |
368 | ||
66a464db | 369 | debug_info = debug_register ("test", 1, 4, sizeof(long) * 3); |
1da177e4 LT |
370 | debug_register_view(debug_info,&debug_sprintf_view); |
371 | ||
372 | debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); | |
373 | debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info); | |
374 | ||
375 | return 0; | |
376 | } | |
377 | ||
378 | static void cleanup(void) | |
379 | { | |
380 | debug_unregister (debug_info); | |
381 | } | |
382 | ||
383 | module_init(init); | |
384 | module_exit(cleanup); | |
385 | ||
386 | ||
387 | ||
66a464db | 388 | Debugfs Interface |
1da177e4 LT |
389 | ---------------- |
390 | Views to the debug logs can be investigated through reading the corresponding | |
66a464db | 391 | debugfs-files: |
1da177e4 LT |
392 | |
393 | Example: | |
394 | ||
66a464db MH |
395 | > ls /sys/kernel/debug/s390dbf/dasd |
396 | flush hex_ascii level pages raw | |
397 | > cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort +1 | |
1da177e4 LT |
398 | 00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... |
399 | 00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE | |
400 | 00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... | |
401 | 00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP | |
402 | 01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD | |
403 | 01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | .... | |
404 | 01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ... | |
405 | 01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | .... | |
406 | 01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE | |
407 | 01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | .... | |
408 | ||
409 | See section about predefined views for explanation of the above output! | |
410 | ||
411 | Changing the debug level | |
412 | ------------------------ | |
413 | ||
414 | Example: | |
415 | ||
416 | ||
66a464db | 417 | > cat /sys/kernel/debug/s390dbf/dasd/level |
1da177e4 | 418 | 3 |
66a464db MH |
419 | > echo "5" > /sys/kernel/debug/s390dbf/dasd/level |
420 | > cat /sys/kernel/debug/s390dbf/dasd/level | |
1da177e4 LT |
421 | 5 |
422 | ||
423 | Flushing debug areas | |
424 | -------------------- | |
425 | Debug areas can be flushed with piping the number of the desired | |
66a464db | 426 | area (0...n) to the debugfs file "flush". When using "-" all debug areas |
1da177e4 LT |
427 | are flushed. |
428 | ||
429 | Examples: | |
430 | ||
431 | 1. Flush debug area 0: | |
66a464db | 432 | > echo "0" > /sys/kernel/debug/s390dbf/dasd/flush |
1da177e4 LT |
433 | |
434 | 2. Flush all debug areas: | |
66a464db MH |
435 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/flush |
436 | ||
437 | Changing the size of debug areas | |
438 | ------------------------------------ | |
439 | It is possible the change the size of debug areas through piping | |
440 | the number of pages to the debugfs file "pages". The resize request will | |
441 | also flush the debug areas. | |
442 | ||
443 | Example: | |
444 | ||
445 | Define 4 pages for the debug areas of debug feature "dasd": | |
446 | > echo "4" > /sys/kernel/debug/s390dbf/dasd/pages | |
1da177e4 LT |
447 | |
448 | Stooping the debug feature | |
449 | -------------------------- | |
450 | Example: | |
451 | ||
452 | 1. Check if stopping is allowed | |
453 | > cat /proc/sys/s390dbf/debug_stoppable | |
454 | 2. Stop debug feature | |
455 | > echo 0 > /proc/sys/s390dbf/debug_active | |
456 | ||
457 | lcrash Interface | |
458 | ---------------- | |
459 | It is planned that the dump analysis tool lcrash gets an additional command | |
460 | 's390dbf' to display all the debug logs. With this tool it will be possible | |
461 | to investigate the debug logs on a live system and with a memory dump after | |
462 | a system crash. | |
463 | ||
464 | Investigating raw memory | |
465 | ------------------------ | |
466 | One last possibility to investigate the debug logs at a live | |
467 | system and after a system crash is to look at the raw memory | |
468 | under VM or at the Service Element. | |
469 | It is possible to find the anker of the debug-logs through | |
470 | the 'debug_area_first' symbol in the System map. Then one has | |
471 | to follow the correct pointers of the data-structures defined | |
472 | in debug.h and find the debug-areas in memory. | |
473 | Normally modules which use the debug feature will also have | |
474 | a global variable with the pointer to the debug-logs. Following | |
475 | this pointer it will also be possible to find the debug logs in | |
476 | memory. | |
477 | ||
478 | For this method it is recommended to use '16 * x + 4' byte (x = 0..n) | |
479 | for the length of the data field in debug_register() in | |
480 | order to see the debug entries well formatted. | |
481 | ||
482 | ||
483 | Predefined Views | |
484 | ---------------- | |
485 | ||
486 | There are three predefined views: hex_ascii, raw and sprintf. | |
487 | The hex_ascii view shows the data field in hex and ascii representation | |
488 | (e.g. '45 43 4b 44 | ECKD'). | |
489 | The raw view returns a bytestream as the debug areas are stored in memory. | |
490 | ||
491 | The sprintf view formats the debug entries in the same way as the sprintf | |
fff9289b | 492 | function would do. The sprintf event/exception functions write to the |
1da177e4 LT |
493 | debug entry a pointer to the format string (size = sizeof(long)) |
494 | and for each vararg a long value. So e.g. for a debug entry with a format | |
495 | string plus two varargs one would need to allocate a (3 * sizeof(long)) | |
496 | byte data area in the debug_register() function. | |
497 | ||
498 | ||
499 | NOTE: If using the sprintf view do NOT use other event/exception functions | |
500 | than the sprintf-event and -exception functions. | |
501 | ||
502 | The format of the hex_ascii and sprintf view is as follows: | |
503 | - Number of area | |
504 | - Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated | |
505 | Universal Time (UTC), January 1, 1970) | |
506 | - level of debug entry | |
507 | - Exception flag (* = Exception) | |
508 | - Cpu-Number of calling task | |
509 | - Return Address to caller | |
510 | - data field | |
511 | ||
512 | The format of the raw view is: | |
513 | - Header as described in debug.h | |
514 | - datafield | |
515 | ||
516 | A typical line of the hex_ascii view will look like the following (first line | |
517 | is only for explanation and will not be displayed when 'cating' the view): | |
518 | ||
519 | area time level exception cpu caller data (hex + ascii) | |
520 | -------------------------------------------------------------------------- | |
521 | 00 00964419409:440690 1 - 00 88023fe | |
522 | ||
523 | ||
524 | Defining views | |
525 | -------------- | |
526 | ||
527 | Views are specified with the 'debug_view' structure. There are defined | |
66a464db | 528 | callback functions which are used for reading and writing the debugfs files: |
1da177e4 LT |
529 | |
530 | struct debug_view { | |
531 | char name[DEBUG_MAX_PROCF_LEN]; | |
532 | debug_prolog_proc_t* prolog_proc; | |
533 | debug_header_proc_t* header_proc; | |
534 | debug_format_proc_t* format_proc; | |
535 | debug_input_proc_t* input_proc; | |
536 | void* private_data; | |
537 | }; | |
538 | ||
539 | where | |
540 | ||
541 | typedef int (debug_header_proc_t) (debug_info_t* id, | |
542 | struct debug_view* view, | |
543 | int area, | |
544 | debug_entry_t* entry, | |
545 | char* out_buf); | |
546 | ||
547 | typedef int (debug_format_proc_t) (debug_info_t* id, | |
548 | struct debug_view* view, char* out_buf, | |
549 | const char* in_buf); | |
550 | typedef int (debug_prolog_proc_t) (debug_info_t* id, | |
551 | struct debug_view* view, | |
552 | char* out_buf); | |
553 | typedef int (debug_input_proc_t) (debug_info_t* id, | |
554 | struct debug_view* view, | |
555 | struct file* file, const char* user_buf, | |
556 | size_t in_buf_size, loff_t* offset); | |
557 | ||
558 | ||
559 | The "private_data" member can be used as pointer to view specific data. | |
560 | It is not used by the debug feature itself. | |
561 | ||
66a464db | 562 | The output when reading a debugfs file is structured like this: |
1da177e4 LT |
563 | |
564 | "prolog_proc output" | |
565 | ||
566 | "header_proc output 1" "format_proc output 1" | |
567 | "header_proc output 2" "format_proc output 2" | |
568 | "header_proc output 3" "format_proc output 3" | |
569 | ... | |
570 | ||
66a464db | 571 | When a view is read from the debugfs, the Debug Feature calls the |
1da177e4 LT |
572 | 'prolog_proc' once for writing the prolog. |
573 | Then 'header_proc' and 'format_proc' are called for each | |
574 | existing debug entry. | |
575 | ||
576 | The input_proc can be used to implement functionality when it is written to | |
66a464db | 577 | the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level). |
1da177e4 LT |
578 | |
579 | For header_proc there can be used the default function | |
670e9f34 | 580 | debug_dflt_header_fn() which is defined in debug.h. |
1da177e4 LT |
581 | and which produces the same header output as the predefined views. |
582 | E.g: | |
583 | 00 00964419409:440761 2 - 00 88023ec | |
584 | ||
585 | In order to see how to use the callback functions check the implementation | |
586 | of the default views! | |
587 | ||
588 | Example | |
589 | ||
590 | #include <asm/debug.h> | |
591 | ||
592 | #define UNKNOWNSTR "data: %08x" | |
593 | ||
594 | const char* messages[] = | |
595 | {"This error...........\n", | |
596 | "That error...........\n", | |
597 | "Problem..............\n", | |
598 | "Something went wrong.\n", | |
599 | "Everything ok........\n", | |
600 | NULL | |
601 | }; | |
602 | ||
603 | static int debug_test_format_fn( | |
604 | debug_info_t * id, struct debug_view *view, | |
605 | char *out_buf, const char *in_buf | |
606 | ) | |
607 | { | |
608 | int i, rc = 0; | |
609 | ||
610 | if(id->buf_size >= 4) { | |
611 | int msg_nr = *((int*)in_buf); | |
612 | if(msg_nr < sizeof(messages)/sizeof(char*) - 1) | |
613 | rc += sprintf(out_buf, "%s", messages[msg_nr]); | |
614 | else | |
615 | rc += sprintf(out_buf, UNKNOWNSTR, msg_nr); | |
616 | } | |
617 | out: | |
618 | return rc; | |
619 | } | |
620 | ||
621 | struct debug_view debug_test_view = { | |
622 | "myview", /* name of view */ | |
623 | NULL, /* no prolog */ | |
624 | &debug_dflt_header_fn, /* default header for each entry */ | |
625 | &debug_test_format_fn, /* our own format function */ | |
626 | NULL, /* no input function */ | |
627 | NULL /* no private data */ | |
628 | }; | |
629 | ||
630 | ===== | |
631 | test: | |
632 | ===== | |
633 | debug_info_t *debug_info; | |
634 | ... | |
635 | debug_info = debug_register ("test", 0, 4, 4 )); | |
636 | debug_register_view(debug_info, &debug_test_view); | |
637 | for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i); | |
638 | ||
66a464db | 639 | > cat /sys/kernel/debug/s390dbf/test/myview |
1da177e4 LT |
640 | 00 00964419734:611402 1 - 00 88042ca This error........... |
641 | 00 00964419734:611405 1 - 00 88042ca That error........... | |
642 | 00 00964419734:611408 1 - 00 88042ca Problem.............. | |
643 | 00 00964419734:611411 1 - 00 88042ca Something went wrong. | |
644 | 00 00964419734:611414 1 - 00 88042ca Everything ok........ | |
645 | 00 00964419734:611417 1 - 00 88042ca data: 00000005 | |
646 | 00 00964419734:611419 1 - 00 88042ca data: 00000006 | |
647 | 00 00964419734:611422 1 - 00 88042ca data: 00000007 | |
648 | 00 00964419734:611425 1 - 00 88042ca data: 00000008 | |
649 | 00 00964419734:611428 1 - 00 88042ca data: 00000009 |