Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 1 | ================== |
| 2 | S390 Debug Feature |
| 3 | ================== |
| 4 | |
| 5 | files: |
| 6 | - arch/s390/kernel/debug.c |
| 7 | - arch/s390/include/asm/debug.h |
| 8 | |
| 9 | Description: |
| 10 | ------------ |
| 11 | The goal of this feature is to provide a kernel debug logging API |
| 12 | where log records can be stored efficiently in memory, where each component |
| 13 | (e.g. device drivers) can have one separate debug log. |
| 14 | One purpose of this is to inspect the debug logs after a production system crash |
| 15 | in order to analyze the reason for the crash. |
| 16 | |
| 17 | If the system still runs but only a subcomponent which uses dbf fails, |
| 18 | it is possible to look at the debug logs on a live system via the Linux |
| 19 | debugfs filesystem. |
| 20 | |
| 21 | The debug feature may also very useful for kernel and driver development. |
| 22 | |
| 23 | Design: |
| 24 | ------- |
| 25 | Kernel components (e.g. device drivers) can register themselves at the debug |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 26 | feature with the function call :c:func:`debug_register()`. |
| 27 | This function initializes a |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 28 | debug log for the caller. For each debug log exists a number of debug areas |
| 29 | where exactly one is active at one time. Each debug area consists of contiguous |
| 30 | pages in memory. In the debug areas there are stored debug entries (log records) |
| 31 | which are written by event- and exception-calls. |
| 32 | |
| 33 | An event-call writes the specified debug entry to the active debug |
| 34 | area and updates the log pointer for the active area. If the end |
| 35 | of the active debug area is reached, a wrap around is done (ring buffer) |
| 36 | and the next debug entry will be written at the beginning of the active |
| 37 | debug area. |
| 38 | |
| 39 | An exception-call writes the specified debug entry to the log and |
| 40 | switches to the next debug area. This is done in order to be sure |
| 41 | that the records which describe the origin of the exception are not |
| 42 | overwritten when a wrap around for the current area occurs. |
| 43 | |
| 44 | The debug areas themselves are also ordered in form of a ring buffer. |
| 45 | When an exception is thrown in the last debug area, the following debug |
| 46 | entries are then written again in the very first area. |
| 47 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 48 | There are four versions for the event- and exception-calls: One for |
| 49 | logging raw data, one for text, one for numbers (unsigned int and long), |
| 50 | and one for sprintf-like formatted strings. |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 51 | |
| 52 | Each debug entry contains the following data: |
| 53 | |
| 54 | - Timestamp |
| 55 | - Cpu-Number of calling task |
| 56 | - Level of debug entry (0...6) |
| 57 | - Return Address to caller |
| 58 | - Flag, if entry is an exception or not |
| 59 | |
| 60 | The debug logs can be inspected in a live system through entries in |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 61 | the debugfs-filesystem. Under the toplevel directory "``s390dbf``" there is |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 62 | a directory for each registered component, which is named like the |
| 63 | corresponding component. The debugfs normally should be mounted to |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 64 | ``/sys/kernel/debug`` therefore the debug feature can be accessed under |
| 65 | ``/sys/kernel/debug/s390dbf``. |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 66 | |
| 67 | The content of the directories are files which represent different views |
| 68 | to the debug log. Each component can decide which views should be |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 69 | used through registering them with the function :c:func:`debug_register_view()`. |
Heiko Carstens | ecb1ff6 | 2020-06-18 07:09:57 +0200 | [diff] [blame] | 70 | Predefined views for hex/ascii and sprintf data are provided. |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 71 | It is also possible to define other views. The content of |
| 72 | a view can be inspected simply by reading the corresponding debugfs file. |
| 73 | |
| 74 | All debug logs have an actual debug level (range from 0 to 6). |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 75 | The default level is 3. Event and Exception functions have a :c:data:`level` |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 76 | parameter. Only debug entries with a level that is lower or equal |
| 77 | than the actual level are written to the log. This means, when |
| 78 | writing events, high priority log entries should have a low level |
| 79 | value whereas low priority entries should have a high one. |
| 80 | The actual debug level can be changed with the help of the debugfs-filesystem |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 81 | through writing a number string "x" to the ``level`` debugfs file which is |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 82 | provided for every debug log. Debugging can be switched off completely |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 83 | by using "-" on the ``level`` debugfs file. |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 84 | |
| 85 | Example:: |
| 86 | |
| 87 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/level |
| 88 | |
| 89 | It is also possible to deactivate the debug feature globally for every |
| 90 | debug log. You can change the behavior using 2 sysctl parameters in |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 91 | ``/proc/sys/s390dbf``: |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 92 | |
| 93 | There are currently 2 possible triggers, which stop the debug feature |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 94 | globally. The first possibility is to use the ``debug_active`` sysctl. If |
| 95 | set to 1 the debug feature is running. If ``debug_active`` is set to 0 the |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 96 | debug feature is turned off. |
| 97 | |
| 98 | The second trigger which stops the debug feature is a kernel oops. |
| 99 | That prevents the debug feature from overwriting debug information that |
| 100 | happened before the oops. After an oops you can reactivate the debug feature |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 101 | by piping 1 to ``/proc/sys/s390dbf/debug_active``. Nevertheless, it's not |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 102 | suggested to use an oopsed kernel in a production environment. |
| 103 | |
| 104 | If you want to disallow the deactivation of the debug feature, you can use |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 105 | the ``debug_stoppable`` sysctl. If you set ``debug_stoppable`` to 0 the debug |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 106 | feature cannot be stopped. If the debug feature is already stopped, it |
| 107 | will stay deactivated. |
| 108 | |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 109 | Kernel Interfaces: |
| 110 | ------------------ |
| 111 | |
Steffen Maier | 0328e51 | 2019-07-03 12:19:48 +0200 | [diff] [blame] | 112 | .. kernel-doc:: arch/s390/kernel/debug.c |
Mauro Carvalho Chehab | a20aa85 | 2019-06-08 23:27:17 -0300 | [diff] [blame] | 113 | .. kernel-doc:: arch/s390/include/asm/debug.h |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 114 | |
| 115 | Predefined views: |
| 116 | ----------------- |
| 117 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 118 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 119 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 120 | extern struct debug_view debug_hex_ascii_view; |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 121 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 122 | extern struct debug_view debug_sprintf_view; |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 123 | |
| 124 | Examples |
| 125 | -------- |
| 126 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 127 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 128 | |
| 129 | /* |
Heiko Carstens | ecb1ff6 | 2020-06-18 07:09:57 +0200 | [diff] [blame] | 130 | * hex_ascii-view Example |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 131 | */ |
| 132 | |
| 133 | #include <linux/init.h> |
| 134 | #include <asm/debug.h> |
| 135 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 136 | static debug_info_t *debug_info; |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 137 | |
| 138 | static int init(void) |
| 139 | { |
| 140 | /* register 4 debug areas with one page each and 4 byte data field */ |
| 141 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 142 | debug_info = debug_register("test", 1, 4, 4 ); |
| 143 | debug_register_view(debug_info, &debug_hex_ascii_view); |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 144 | |
| 145 | debug_text_event(debug_info, 4 , "one "); |
| 146 | debug_int_exception(debug_info, 4, 4711); |
| 147 | debug_event(debug_info, 3, &debug_info, 4); |
| 148 | |
| 149 | return 0; |
| 150 | } |
| 151 | |
| 152 | static void cleanup(void) |
| 153 | { |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 154 | debug_unregister(debug_info); |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | module_init(init); |
| 158 | module_exit(cleanup); |
| 159 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 160 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 161 | |
| 162 | /* |
| 163 | * sprintf-view Example |
| 164 | */ |
| 165 | |
| 166 | #include <linux/init.h> |
| 167 | #include <asm/debug.h> |
| 168 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 169 | static debug_info_t *debug_info; |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 170 | |
| 171 | static int init(void) |
| 172 | { |
| 173 | /* register 4 debug areas with one page each and data field for */ |
| 174 | /* format string pointer + 2 varargs (= 3 * sizeof(long)) */ |
| 175 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 176 | debug_info = debug_register("test", 1, 4, sizeof(long) * 3); |
| 177 | debug_register_view(debug_info, &debug_sprintf_view); |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 178 | |
| 179 | debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__); |
| 180 | debug_sprintf_exception(debug_info, 1, "pointer to debug info: %p\n",&debug_info); |
| 181 | |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | static void cleanup(void) |
| 186 | { |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 187 | debug_unregister(debug_info); |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 188 | } |
| 189 | |
| 190 | module_init(init); |
| 191 | module_exit(cleanup); |
| 192 | |
| 193 | Debugfs Interface |
| 194 | ----------------- |
| 195 | Views to the debug logs can be investigated through reading the corresponding |
| 196 | debugfs-files: |
| 197 | |
| 198 | Example:: |
| 199 | |
| 200 | > ls /sys/kernel/debug/s390dbf/dasd |
Heiko Carstens | ecb1ff6 | 2020-06-18 07:09:57 +0200 | [diff] [blame] | 201 | flush hex_ascii level pages |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 202 | > cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort -k2,2 -s |
| 203 | 00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | .... |
| 204 | 00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE |
| 205 | 00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | .... |
| 206 | 00 00974733272:682281 1 * 02 0006ab08 41 4c 4c 43 | EXCP |
| 207 | 01 00974733272:682284 2 - 02 0006ab16 45 43 4b 44 | ECKD |
| 208 | 01 00974733272:682287 2 - 02 0006ab28 00 00 00 04 | .... |
| 209 | 01 00974733272:682289 2 - 02 0006ab3e 00 00 00 20 | ... |
| 210 | 01 00974733272:682297 2 - 02 0006ad7e 07 ea 4a 90 | .... |
| 211 | 01 00974733272:684384 2 - 00 0006ade6 46 52 45 45 | FREE |
| 212 | 01 00974733272:684388 2 - 00 0006adf6 07 ea 4a 90 | .... |
| 213 | |
| 214 | See section about predefined views for explanation of the above output! |
| 215 | |
| 216 | Changing the debug level |
| 217 | ------------------------ |
| 218 | |
| 219 | Example:: |
| 220 | |
| 221 | |
| 222 | > cat /sys/kernel/debug/s390dbf/dasd/level |
| 223 | 3 |
| 224 | > echo "5" > /sys/kernel/debug/s390dbf/dasd/level |
| 225 | > cat /sys/kernel/debug/s390dbf/dasd/level |
| 226 | 5 |
| 227 | |
| 228 | Flushing debug areas |
| 229 | -------------------- |
| 230 | Debug areas can be flushed with piping the number of the desired |
| 231 | area (0...n) to the debugfs file "flush". When using "-" all debug areas |
| 232 | are flushed. |
| 233 | |
| 234 | Examples: |
| 235 | |
| 236 | 1. Flush debug area 0:: |
| 237 | |
| 238 | > echo "0" > /sys/kernel/debug/s390dbf/dasd/flush |
| 239 | |
| 240 | 2. Flush all debug areas:: |
| 241 | |
| 242 | > echo "-" > /sys/kernel/debug/s390dbf/dasd/flush |
| 243 | |
| 244 | Changing the size of debug areas |
| 245 | ------------------------------------ |
| 246 | It is possible the change the size of debug areas through piping |
| 247 | the number of pages to the debugfs file "pages". The resize request will |
| 248 | also flush the debug areas. |
| 249 | |
| 250 | Example: |
| 251 | |
| 252 | Define 4 pages for the debug areas of debug feature "dasd":: |
| 253 | |
| 254 | > echo "4" > /sys/kernel/debug/s390dbf/dasd/pages |
| 255 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 256 | Stopping the debug feature |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 257 | -------------------------- |
| 258 | Example: |
| 259 | |
| 260 | 1. Check if stopping is allowed:: |
| 261 | |
| 262 | > cat /proc/sys/s390dbf/debug_stoppable |
| 263 | |
| 264 | 2. Stop debug feature:: |
| 265 | |
| 266 | > echo 0 > /proc/sys/s390dbf/debug_active |
| 267 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 268 | crash Interface |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 269 | ---------------- |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 270 | The ``crash`` tool since v5.1.0 has a built-in command |
| 271 | ``s390dbf`` to display all the debug logs or export them to the file system. |
| 272 | With this tool it is possible |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 273 | to investigate the debug logs on a live system and with a memory dump after |
| 274 | a system crash. |
| 275 | |
| 276 | Investigating raw memory |
| 277 | ------------------------ |
| 278 | One last possibility to investigate the debug logs at a live |
| 279 | system and after a system crash is to look at the raw memory |
| 280 | under VM or at the Service Element. |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 281 | It is possible to find the anchor of the debug-logs through |
| 282 | the ``debug_area_first`` symbol in the System map. Then one has |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 283 | to follow the correct pointers of the data-structures defined |
| 284 | in debug.h and find the debug-areas in memory. |
| 285 | Normally modules which use the debug feature will also have |
| 286 | a global variable with the pointer to the debug-logs. Following |
| 287 | this pointer it will also be possible to find the debug logs in |
| 288 | memory. |
| 289 | |
| 290 | For this method it is recommended to use '16 * x + 4' byte (x = 0..n) |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 291 | for the length of the data field in :c:func:`debug_register()` in |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 292 | order to see the debug entries well formatted. |
| 293 | |
| 294 | |
| 295 | Predefined Views |
| 296 | ---------------- |
| 297 | |
Heiko Carstens | ecb1ff6 | 2020-06-18 07:09:57 +0200 | [diff] [blame] | 298 | There are two predefined views: hex_ascii and sprintf. |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 299 | The hex_ascii view shows the data field in hex and ascii representation |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 300 | (e.g. ``45 43 4b 44 | ECKD``). |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 301 | |
| 302 | The sprintf view formats the debug entries in the same way as the sprintf |
| 303 | function would do. The sprintf event/exception functions write to the |
| 304 | debug entry a pointer to the format string (size = sizeof(long)) |
| 305 | and for each vararg a long value. So e.g. for a debug entry with a format |
| 306 | string plus two varargs one would need to allocate a (3 * sizeof(long)) |
| 307 | byte data area in the debug_register() function. |
| 308 | |
| 309 | IMPORTANT: |
| 310 | Using "%s" in sprintf event functions is dangerous. You can only |
| 311 | use "%s" in the sprintf event functions, if the memory for the passed string |
| 312 | is available as long as the debug feature exists. The reason behind this is |
| 313 | that due to performance considerations only a pointer to the string is stored |
| 314 | in the debug feature. If you log a string that is freed afterwards, you will |
| 315 | get an OOPS when inspecting the debug feature, because then the debug feature |
| 316 | will access the already freed memory. |
| 317 | |
| 318 | NOTE: |
| 319 | If using the sprintf view do NOT use other event/exception functions |
| 320 | than the sprintf-event and -exception functions. |
| 321 | |
| 322 | The format of the hex_ascii and sprintf view is as follows: |
| 323 | |
| 324 | - Number of area |
| 325 | - Timestamp (formatted as seconds and microseconds since 00:00:00 Coordinated |
| 326 | Universal Time (UTC), January 1, 1970) |
| 327 | - level of debug entry |
| 328 | - Exception flag (* = Exception) |
| 329 | - Cpu-Number of calling task |
| 330 | - Return Address to caller |
| 331 | - data field |
| 332 | |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 333 | A typical line of the hex_ascii view will look like the following (first line |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 334 | is only for explanation and will not be displayed when 'cating' the view):: |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 335 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 336 | area time level exception cpu caller data (hex + ascii) |
| 337 | -------------------------------------------------------------------------- |
| 338 | 00 00964419409:440690 1 - 00 88023fe |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 339 | |
| 340 | |
| 341 | Defining views |
| 342 | -------------- |
| 343 | |
| 344 | Views are specified with the 'debug_view' structure. There are defined |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 345 | callback functions which are used for reading and writing the debugfs files: |
| 346 | |
| 347 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 348 | |
| 349 | struct debug_view { |
| 350 | char name[DEBUG_MAX_PROCF_LEN]; |
| 351 | debug_prolog_proc_t* prolog_proc; |
| 352 | debug_header_proc_t* header_proc; |
| 353 | debug_format_proc_t* format_proc; |
| 354 | debug_input_proc_t* input_proc; |
| 355 | void* private_data; |
| 356 | }; |
| 357 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 358 | where: |
| 359 | |
| 360 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 361 | |
| 362 | typedef int (debug_header_proc_t) (debug_info_t* id, |
| 363 | struct debug_view* view, |
| 364 | int area, |
| 365 | debug_entry_t* entry, |
| 366 | char* out_buf); |
| 367 | |
| 368 | typedef int (debug_format_proc_t) (debug_info_t* id, |
| 369 | struct debug_view* view, char* out_buf, |
| 370 | const char* in_buf); |
| 371 | typedef int (debug_prolog_proc_t) (debug_info_t* id, |
| 372 | struct debug_view* view, |
| 373 | char* out_buf); |
| 374 | typedef int (debug_input_proc_t) (debug_info_t* id, |
| 375 | struct debug_view* view, |
| 376 | struct file* file, const char* user_buf, |
| 377 | size_t in_buf_size, loff_t* offset); |
| 378 | |
| 379 | |
| 380 | The "private_data" member can be used as pointer to view specific data. |
| 381 | It is not used by the debug feature itself. |
| 382 | |
| 383 | The output when reading a debugfs file is structured like this:: |
| 384 | |
| 385 | "prolog_proc output" |
| 386 | |
| 387 | "header_proc output 1" "format_proc output 1" |
| 388 | "header_proc output 2" "format_proc output 2" |
| 389 | "header_proc output 3" "format_proc output 3" |
| 390 | ... |
| 391 | |
| 392 | When a view is read from the debugfs, the Debug Feature calls the |
| 393 | 'prolog_proc' once for writing the prolog. |
| 394 | Then 'header_proc' and 'format_proc' are called for each |
| 395 | existing debug entry. |
| 396 | |
| 397 | The input_proc can be used to implement functionality when it is written to |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 398 | the view (e.g. like with ``echo "0" > /sys/kernel/debug/s390dbf/dasd/level``). |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 399 | |
| 400 | For header_proc there can be used the default function |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 401 | :c:func:`debug_dflt_header_fn()` which is defined in debug.h. |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 402 | and which produces the same header output as the predefined views. |
| 403 | E.g:: |
| 404 | |
| 405 | 00 00964419409:440761 2 - 00 88023ec |
| 406 | |
| 407 | In order to see how to use the callback functions check the implementation |
| 408 | of the default views! |
| 409 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 410 | Example: |
| 411 | |
| 412 | .. code-block:: c |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 413 | |
| 414 | #include <asm/debug.h> |
| 415 | |
| 416 | #define UNKNOWNSTR "data: %08x" |
| 417 | |
| 418 | const char* messages[] = |
| 419 | {"This error...........\n", |
| 420 | "That error...........\n", |
| 421 | "Problem..............\n", |
| 422 | "Something went wrong.\n", |
| 423 | "Everything ok........\n", |
| 424 | NULL |
| 425 | }; |
| 426 | |
| 427 | static int debug_test_format_fn( |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 428 | debug_info_t *id, struct debug_view *view, |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 429 | char *out_buf, const char *in_buf |
| 430 | ) |
| 431 | { |
| 432 | int i, rc = 0; |
| 433 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 434 | if (id->buf_size >= 4) { |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 435 | int msg_nr = *((int*)in_buf); |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 436 | if (msg_nr < sizeof(messages) / sizeof(char*) - 1) |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 437 | rc += sprintf(out_buf, "%s", messages[msg_nr]); |
| 438 | else |
| 439 | rc += sprintf(out_buf, UNKNOWNSTR, msg_nr); |
| 440 | } |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 441 | return rc; |
Steffen Maier | f11977b | 2019-07-03 12:19:47 +0200 | [diff] [blame] | 442 | } |
| 443 | |
| 444 | struct debug_view debug_test_view = { |
| 445 | "myview", /* name of view */ |
| 446 | NULL, /* no prolog */ |
| 447 | &debug_dflt_header_fn, /* default header for each entry */ |
| 448 | &debug_test_format_fn, /* our own format function */ |
| 449 | NULL, /* no input function */ |
| 450 | NULL /* no private data */ |
| 451 | }; |
| 452 | |
| 453 | test: |
| 454 | ===== |
| 455 | |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 456 | .. code-block:: c |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 457 | |
| 458 | debug_info_t *debug_info; |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 459 | int i; |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 460 | ... |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 461 | debug_info = debug_register("test", 0, 4, 4); |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 462 | debug_register_view(debug_info, &debug_test_view); |
Steffen Maier | 499723d | 2019-07-03 12:19:49 +0200 | [diff] [blame] | 463 | for (i = 0; i < 10; i ++) |
| 464 | debug_int_event(debug_info, 1, i); |
| 465 | |
| 466 | :: |
Mauro Carvalho Chehab | 8b4a503 | 2019-06-08 23:27:16 -0300 | [diff] [blame] | 467 | |
| 468 | > cat /sys/kernel/debug/s390dbf/test/myview |
| 469 | 00 00964419734:611402 1 - 00 88042ca This error........... |
| 470 | 00 00964419734:611405 1 - 00 88042ca That error........... |
| 471 | 00 00964419734:611408 1 - 00 88042ca Problem.............. |
| 472 | 00 00964419734:611411 1 - 00 88042ca Something went wrong. |
| 473 | 00 00964419734:611414 1 - 00 88042ca Everything ok........ |
| 474 | 00 00964419734:611417 1 - 00 88042ca data: 00000005 |
| 475 | 00 00964419734:611419 1 - 00 88042ca data: 00000006 |
| 476 | 00 00964419734:611422 1 - 00 88042ca data: 00000007 |
| 477 | 00 00964419734:611425 1 - 00 88042ca data: 00000008 |
| 478 | 00 00964419734:611428 1 - 00 88042ca data: 00000009 |