Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | S390 Debug Feature |
| 2 | ================== |
| 3 | |
| 4 | files: arch/s390/kernel/debug.c |
Randy Dunlap | 58cc855 | 2009-01-06 14:42:42 -0800 | [diff] [blame] | 5 | arch/s390/include/asm/debug.h |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. |
Matt LaPlante | a2ffd27 | 2006-10-03 22:49:15 +0200 | [diff] [blame] | 14 | If the system still runs but only a subcomponent which uses dbf fails, |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 15 | it is possible to look at the debug logs on a live system via the Linux |
| 16 | debugfs filesystem. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Nicolas Kaiser | 2254f5a | 2006-12-04 15:40:23 +0100 | [diff] [blame] | 39 | The debug areas themselves are also ordered in form of a ring buffer. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 55 | the debugfs-filesystem. Under the toplevel directory "s390dbf" there is |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | a directory for each registered component, which is named like the |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 57 | corresponding component. The debugfs normally should be mounted to |
Nicolas Kaiser | 2254f5a | 2006-12-04 15:40:23 +0100 | [diff] [blame] | 58 | /sys/kernel/debug therefore the debug feature can be accessed under |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 59 | /sys/kernel/debug/s390dbf. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 66 | a view can be inspected simply by reading the corresponding debugfs file. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 67 | |
Paolo Ornati | 670e9f3 | 2006-10-03 22:57:56 +0200 | [diff] [blame] | 68 | All debug logs have an actual debug level (range from 0 to 6). |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | provided for every debug log. Debugging can be switched off completely |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 77 | by using "-" on the 'level' debugfs file. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | |
| 79 | Example: |
| 80 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 81 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/level |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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: |
Matt LaPlante | 992caac | 2006-10-03 22:52:05 +0200 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | set to 1 the debug feature is running. If "debug_active" is set to 0 the |
| 89 | debug feature is turned off. |
Nicolas Kaiser | 2254f5a | 2006-12-04 15:40:23 +0100 | [diff] [blame] | 90 | The second trigger which stops the debug feature is a kernel oops. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Nicolas Kaiser | 2254f5a | 2006-12-04 15:40:23 +0100 | [diff] [blame] | 94 | suggested to use an oopsed kernel in a production environment. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | ---------------------------------------------------------------------------- |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 104 | debug_info_t *debug_register(char *name, int pages, int nr_areas, |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 105 | int buf_size); |
| 106 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 107 | Parameter: name: Name of debug log (e.g. used for debugfs entry) |
| 108 | pages: number of pages, which will be allocated per area |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 9637c3f | 2008-04-17 07:46:18 +0200 | [diff] [blame] | 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 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | --------------------------------------------------------------------------- |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 160 | void debug_stop_all(void); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 296 | Description: registers new debug view and creates debugfs dir entry |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 307 | Description: unregisters debug view and removes debugfs dir entry |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 334 | debug_info = debug_register ("test", 1, 4, 4 ); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 369 | debug_info = debug_register ("test", 1, 4, sizeof(long) * 3); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 388 | Debugfs Interface |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 389 | ---------------- |
| 390 | Views to the debug logs can be investigated through reading the corresponding |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 391 | debugfs-files: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 392 | |
| 393 | Example: |
| 394 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 417 | > cat /sys/kernel/debug/s390dbf/dasd/level |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 418 | 3 |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 419 | > echo "5" > /sys/kernel/debug/s390dbf/dasd/level |
| 420 | > cat /sys/kernel/debug/s390dbf/dasd/level |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 | 5 |
| 422 | |
| 423 | Flushing debug areas |
| 424 | -------------------- |
| 425 | Debug areas can be flushed with piping the number of the desired |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 426 | area (0...n) to the debugfs file "flush". When using "-" all debug areas |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 427 | are flushed. |
| 428 | |
| 429 | Examples: |
| 430 | |
| 431 | 1. Flush debug area 0: |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 432 | > echo "0" > /sys/kernel/debug/s390dbf/dasd/flush |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 433 | |
| 434 | 2. Flush all debug areas: |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 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 |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Matt LaPlante | fff9289 | 2006-10-03 22:47:42 +0200 | [diff] [blame] | 492 | function would do. The sprintf event/exception functions write to the |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 528 | callback functions which are used for reading and writing the debugfs files: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 562 | The output when reading a debugfs file is structured like this: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 571 | When a view is read from the debugfs, the Debug Feature calls the |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 577 | the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level). |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 578 | |
| 579 | For header_proc there can be used the default function |
Paolo Ornati | 670e9f3 | 2006-10-03 22:57:56 +0200 | [diff] [blame] | 580 | debug_dflt_header_fn() which is defined in debug.h. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | |
Michael Holzheu | 66a464d | 2005-06-25 14:55:33 -0700 | [diff] [blame] | 639 | > cat /sys/kernel/debug/s390dbf/test/myview |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |