| Commit | Line | Data |
|---|---|---|
| d3776285 MD |
1 | /* |
| 2 | * Copyright (c) 2005 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 81540c2d EN |
7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| d3776285 | 10 | * |
| 81540c2d EN |
11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| d3776285 MD |
14 | * notice, this list of conditions and the following disclaimer in |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 81540c2d | 32 | * SUCH DAMAGE. |
| 81540c2d | 33 | */ |
| 81540c2d | 34 | /* |
| d3776285 MD |
35 | * Generic Kernel trace buffer support. |
| 36 | * | |
| 81540c2d EN |
37 | */ |
| 38 | ||
| 39 | #ifndef _SYS_KTR_H_ | |
| 40 | #define _SYS_KTR_H_ | |
| 41 | ||
| 1bd40720 | 42 | #include <sys/types.h> |
| 75f59a66 | 43 | #include <sys/sysctl.h> |
| 5bf48697 | 44 | #include <sys/cpputil.h> |
| 1bd40720 | 45 | |
| 282a0149 | 46 | #ifdef _KERNEL |
| 81540c2d | 47 | #include "opt_ktr.h" |
| 282a0149 | 48 | #endif |
| 81540c2d | 49 | |
| ade21b34 MD |
50 | /* |
| 51 | * Conveniently auto-enable KTRs when particular KTRs are specified | |
| 52 | * in kernel options. This way we can get logging during boot. | |
| 53 | * However, if KTR_ALL is optioned, just disable everything by default. | |
| 54 | * The user can enable individual masks via sysctl. | |
| 55 | */ | |
| 56 | #if defined(KTR_ALL) | |
| ddca1582 | 57 | #define KTR_AUTO_ENABLE 0 |
| ade21b34 | 58 | #else |
| ddca1582 MD |
59 | #define KTR_ALL 0 |
| 60 | #define KTR_AUTO_ENABLE -1 | |
| 81540c2d EN |
61 | #endif |
| 62 | ||
| ddca1582 MD |
63 | #define KTR_BUFSIZE 192 |
| 64 | #define KTR_VERSION 4 | |
| 65 | ||
| 66 | #define KTR_VERSION_WITH_FREQ 3 | |
| 67 | #define KTR_VERSION_KTR_CPU 4 | |
| 81540c2d EN |
68 | |
| 69 | #ifndef LOCORE | |
| 70 | ||
| d3776285 MD |
71 | struct ktr_info { |
| 72 | const char *kf_name; /* human-interpreted subsystem name */ | |
| 73 | int32_t *kf_master_enable; /* the master enable variable */ | |
| 5bf48697 | 74 | const char * const kf_format; /* data format */ |
| d3776285 MD |
75 | int kf_data_size; /* relevance of the data buffer */ |
| 76 | }; | |
| 77 | ||
| 81540c2d EN |
78 | struct ktr_entry { |
| 79 | u_int64_t ktr_timestamp; | |
| d3776285 | 80 | struct ktr_info *ktr_info; |
| 81540c2d | 81 | const char *ktr_file; |
| d3776285 MD |
82 | void *ktr_caller1; |
| 83 | void *ktr_caller2; | |
| 84 | int32_t ktr_line; | |
| 85 | int32_t ktr_unused; | |
| af6ff89e | 86 | int32_t ktr_data[KTR_BUFSIZE / sizeof(int32_t)]; |
| 81540c2d EN |
87 | }; |
| 88 | ||
| ddca1582 MD |
89 | struct ktr_cpu_core { |
| 90 | struct ktr_entry *ktr_buf; | |
| 91 | int ktr_idx; | |
| 92 | }; | |
| 93 | ||
| 94 | struct ktr_cpu { | |
| 95 | struct ktr_cpu_core core; | |
| 02289741 | 96 | } __cachealign; |
| ddca1582 MD |
97 | |
| 98 | #ifdef _KERNEL | |
| 99 | ||
| 5bf48697 AE |
100 | struct ktr_entry * ktr_begin_write_entry(struct ktr_info *, |
| 101 | const char *, int); | |
| 102 | int ktr_finish_write_entry(struct ktr_info *, struct ktr_entry *); | |
| af6ff89e | 103 | void cpu_ktr_caller(struct ktr_entry *ktr); |
| 81540c2d | 104 | |
| ddca1582 MD |
105 | #endif |
| 106 | ||
| d3776285 MD |
107 | /* |
| 108 | * Take advantage of constant integer optimizations by the compiler | |
| 109 | * to optimize-out disabled code at compile-time. If KTR_ENABLE_<name> | |
| 110 | * is 0, the compiler avoids generating all related code when KTR is enabled. | |
| 111 | */ | |
| 81540c2d EN |
112 | |
| 113 | #ifdef KTR | |
| 114 | ||
| d3776285 MD |
115 | SYSCTL_DECL(_debug_ktr); |
| 116 | ||
| 117 | #define KTR_INFO_MASTER(master) \ | |
| 118 | SYSCTL_NODE(_debug_ktr, OID_AUTO, master, CTLFLAG_RW, 0, ""); \ | |
| ade21b34 | 119 | int ktr_ ## master ## _enable = KTR_AUTO_ENABLE; \ |
| d3776285 | 120 | SYSCTL_INT(_debug_ktr, OID_AUTO, master ## _enable, CTLFLAG_RW, \ |
| f22af1e9 SW |
121 | &ktr_ ## master ## _enable, 0, \ |
| 122 | "Bit mask to control " __XSTRING(master) "'s event logging") | |
| d3776285 MD |
123 | |
| 124 | #define KTR_INFO_MASTER_EXTERN(master) \ | |
| 125 | SYSCTL_DECL(_debug_ktr_ ## master); \ | |
| 126 | extern int ktr_ ## master ## _enable \ | |
| 81540c2d EN |
127 | |
| 128 | /* | |
| d3776285 MD |
129 | * This creates a read-only sysctl so the user knows what the mask |
| 130 | * definitions are and a number of static const int's which are used | |
| 131 | * by the compiler to optimize the trace logging at compile-time and | |
| 132 | * run-time. | |
| 5bf48697 AE |
133 | * You're supposed to specify any arguments to the format as you would in |
| 134 | * a function prototype. | |
| 135 | * We automagically create a struct for the arguments and a throwaway | |
| 136 | * function that will be called with the format and the actual arguments | |
| 137 | * at the KTR_LOG site. This makes sure that the compiler will typecheck | |
| 138 | * the arguments against the format string. On gcc, this requires -Wformat | |
| 139 | * (which is included in -Wall) and -O1 at least. Note that using | |
| 140 | * ktr_info.kf_format will not work, hence we need to define another | |
| 141 | * throwaway const wariable for the format. | |
| 81540c2d | 142 | */ |
| 5bf48697 AE |
143 | #define KTR_INFO(compile, master, name, maskbit, format, ...) \ |
| 144 | static const int ktr_ ## master ## _ ## name ## _mask = \ | |
| 145 | 1 << (maskbit); \ | |
| 146 | static const int ktr_ ## master ## _ ##name ## _enable = \ | |
| d3776285 | 147 | compile; \ |
| 5bf48697 AE |
148 | static int ktr_ ## master ## _ ## name ## _mask_ro = \ |
| 149 | 1 << (maskbit); \ | |
| 150 | SYSCTL_INT(_debug_ktr_ ## master, OID_AUTO, name ## _mask, \ | |
| 151 | CTLFLAG_RD, &ktr_ ## master ## _ ## name ## _mask_ro, \ | |
| 152 | 0, "Value of the " __XSTRING(name) " event in " __XSTRING(master) "'s mask"); \ | |
| 153 | __GENSTRUCT(ktr_info_ ## master ## _ ## name ## _args, __VA_ARGS__) \ | |
| 154 | __packed; \ | |
| 155 | CTASSERT(sizeof(struct ktr_info_ ## master ## _ ## name ## _args) <= KTR_BUFSIZE); \ | |
| 156 | static inline void \ | |
| 157 | __ktr_info_ ## master ## _ ## name ## _fmtcheck(const char *fmt, \ | |
| 158 | ...) __printf0like(1, 2); \ | |
| 159 | static inline void \ | |
| 160 | __ktr_info_ ## master ## _ ## name ## _fmtcheck(const char *fmt __unused, \ | |
| 161 | ...) \ | |
| 162 | {} \ | |
| 163 | static const char * const __ktr_ ## master ## _ ## name ## _fmt = format; \ | |
| 164 | static struct ktr_info ktr_info_ ## master ## _ ## name = { \ | |
| 165 | .kf_name = #master "_" #name, \ | |
| 166 | .kf_master_enable = &ktr_ ## master ## _enable, \ | |
| 167 | .kf_format = format, \ | |
| 168 | .kf_data_size = sizeof(struct ktr_info_ ## master ## _ ## name ## _args), \ | |
| 169 | } | |
| 170 | ||
| 171 | ||
| 172 | ||
| 173 | ||
| 174 | /* | |
| 175 | * Call ktr_begin_write_entry() that sets up the entry for us; use | |
| 176 | * a struct copy to give as max flexibility as possible to the compiler. | |
| 177 | * In higher optimization levels, it will copy the arguments directly from | |
| 178 | * registers to the destination buffer. Call our dummy function that will | |
| 179 | * typecheck the arguments against the format string. | |
| 180 | */ | |
| 181 | #define KTR_LOG(name, ...) \ | |
| 182 | do { \ | |
| 183 | __ktr_info_ ## name ## _fmtcheck (__ktr_ ## name ## _fmt, ##__VA_ARGS__); \ | |
| 184 | if (ktr_ ## name ## _enable && \ | |
| 185 | (ktr_ ## name ## _mask & *ktr_info_ ## name .kf_master_enable)) { \ | |
| 186 | struct ktr_entry *entry; \ | |
| 187 | entry = ktr_begin_write_entry(&ktr_info_ ## name, __FILE__, __LINE__); \ | |
| 188 | if (!entry) \ | |
| 189 | break; \ | |
| 190 | *(struct ktr_info_ ## name ## _args *)&entry->ktr_data[0] = \ | |
| 191 | (struct ktr_info_ ## name ## _args){ __VA_ARGS__}; \ | |
| 192 | if (ktr_finish_write_entry(&ktr_info_ ## name, entry)) { \ | |
| 193 | kprintf(ktr_info_ ## name .kf_format, ##__VA_ARGS__); \ | |
| 194 | kprintf("\n"); \ | |
| 195 | } \ | |
| 196 | } \ | |
| 197 | } while(0) | |
| d3776285 | 198 | |
| b0bbd261 MC |
199 | #define KTR_COND_LOG(name, cond, ...) \ |
| 200 | do { \ | |
| 201 | __ktr_info_ ## name ## _fmtcheck (__ktr_ ## name ## _fmt, ##__VA_ARGS__); \ | |
| 202 | if ((cond) && \ | |
| 203 | ktr_ ## name ## _enable && \ | |
| 204 | (ktr_ ## name ## _mask & *ktr_info_ ## name .kf_master_enable)) { \ | |
| 205 | struct ktr_entry *entry; \ | |
| 206 | entry = ktr_begin_write_entry(&ktr_info_ ## name, __FILE__, __LINE__); \ | |
| 207 | if (!entry) \ | |
| 208 | break; \ | |
| 209 | *(struct ktr_info_ ## name ## _args *)&entry->ktr_data[0] = \ | |
| 210 | (struct ktr_info_ ## name ## _args){ __VA_ARGS__}; \ | |
| 211 | if (ktr_finish_write_entry(&ktr_info_ ## name, entry)) { \ | |
| 212 | kprintf(ktr_info_ ## name .kf_format, ##__VA_ARGS__); \ | |
| 213 | kprintf("\n"); \ | |
| 214 | } \ | |
| 215 | } \ | |
| 216 | } while(0) | |
| 217 | ||
| 81540c2d | 218 | #else |
| d3776285 MD |
219 | |
| 220 | #define KTR_INFO_MASTER(master) \ | |
| 3a052084 | 221 | static const int ktr_ ## master ## _enable = 0 |
| d3776285 MD |
222 | |
| 223 | #define KTR_INFO_MASTER_EXTERN(master) \ | |
| 3a052084 | 224 | static const int ktr_ ## master ## _enable |
| d3776285 | 225 | |
| 5bf48697 | 226 | #define KTR_INFO(compile, master, name, maskbit, format, ...) \ |
| d3776285 | 227 | static const int ktr_ ## master ## _ ## name ## _mask = \ |
| 5bf48697 | 228 | (1 << maskbit) |
| d3776285 MD |
229 | |
| 230 | #define KTR_LOG(info, args...) | |
| d3776285 | 231 | |
| b0bbd261 MC |
232 | #define KTR_COND_LOG(info, args...) |
| 233 | ||
| 81540c2d EN |
234 | #endif |
| 235 | ||
| d3776285 | 236 | #endif /* !LOCORE */ |
| 81540c2d | 237 | #endif /* !_SYS_KTR_H_ */ |