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