1/* 2 * net/tipc/dbg.c: TIPC print buffer routines for debugging 3 * 4 * Copyright (c) 1996-2006, Ericsson AB 5 * Copyright (c) 2005-2006, Wind River Systems 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 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 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the names of the copyright holders nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * Alternatively, this software may be distributed under the terms of the 21 * GNU General Public License ("GPL") version 2 as published by the Free 22 * Software Foundation. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37#include "core.h" 38#include "config.h" 39#include "dbg.h" 40 41static char print_string[TIPC_PB_MAX_STR]; 42static DEFINE_SPINLOCK(print_lock); 43 44static struct print_buf null_buf = { NULL, 0, NULL, NULL }; 45struct print_buf *TIPC_NULL = &null_buf; 46 47static struct print_buf cons_buf = { NULL, 0, NULL, NULL }; 48struct print_buf *TIPC_CONS = &cons_buf; 49 50static struct print_buf log_buf = { NULL, 0, NULL, NULL }; 51struct print_buf *TIPC_LOG = &log_buf; 52 53 54#define FORMAT(PTR,LEN,FMT) \ 55{\ 56 va_list args;\ 57 va_start(args, FMT);\ 58 LEN = vsprintf(PTR, FMT, args);\ 59 va_end(args);\ 60 *(PTR + LEN) = '\0';\ 61} 62 63/* 64 * Locking policy when using print buffers. 65 * 66 * The following routines use 'print_lock' for protection: 67 * 1) tipc_printf() - to protect its print buffer(s) and 'print_string' 68 * 2) TIPC_TEE() - to protect its print buffer(s) 69 * 3) tipc_dump() - to protect its print buffer(s) and 'print_string' 70 * 4) tipc_log_XXX() - to protect TIPC_LOG 71 * 72 * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent 73 * simultaneous use of the print buffer(s) being manipulated. 74 */ 75 76/** 77 * tipc_printbuf_init - initialize print buffer to empty 78 * @pb: pointer to print buffer structure 79 * @raw: pointer to character array used by print buffer 80 * @size: size of character array 81 * 82 * Makes the print buffer a null device that discards anything written to it 83 * if the character array is too small (or absent). 84 */ 85 86void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size) 87{ 88 pb->buf = raw; 89 pb->crs = raw; 90 pb->size = size; 91 pb->next = NULL; 92 93 if (size < TIPC_PB_MIN_SIZE) { 94 pb->buf = NULL; 95 } else if (raw) { 96 pb->buf[0] = 0; 97 pb->buf[size-1] = ~0; 98 } 99} 100 101/** 102 * tipc_printbuf_reset - reinitialize print buffer to empty state 103 * @pb: pointer to print buffer structure 104 */ 105 106void tipc_printbuf_reset(struct print_buf *pb) 107{ 108 tipc_printbuf_init(pb, pb->buf, pb->size); 109} 110 111/** 112 * tipc_printbuf_empty - test if print buffer is in empty state 113 * @pb: pointer to print buffer structure 114 * 115 * Returns non-zero if print buffer is empty. 116 */ 117 118int tipc_printbuf_empty(struct print_buf *pb) 119{ 120 return (!pb->buf || (pb->crs == pb->buf)); 121} 122 123/** 124 * tipc_printbuf_validate - check for print buffer overflow 125 * @pb: pointer to print buffer structure 126 * 127 * Verifies that a print buffer has captured all data written to it. 128 * If data has been lost, linearize buffer and prepend an error message 129 * 130 * Returns length of print buffer data string (including trailing NUL) 131 */ 132 133int tipc_printbuf_validate(struct print_buf *pb) 134{ 135 char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n"; 136 char *cp_buf; 137 struct print_buf cb; 138 139 if (!pb->buf) 140 return 0; 141 142 if (pb->buf[pb->size - 1] == 0) { 143 cp_buf = kmalloc(pb->size, GFP_ATOMIC); 144 if (cp_buf != NULL){ 145 tipc_printbuf_init(&cb, cp_buf, pb->size); 146 tipc_printbuf_move(&cb, pb); 147 tipc_printbuf_move(pb, &cb); 148 kfree(cp_buf); 149 memcpy(pb->buf, err, strlen(err)); 150 } else { 151 tipc_printbuf_reset(pb); 152 tipc_printf(pb, err); 153 } 154 } 155 return (pb->crs - pb->buf + 1); 156} 157 158/** 159 * tipc_printbuf_move - move print buffer contents to another print buffer 160 * @pb_to: pointer to destination print buffer structure 161 * @pb_from: pointer to source print buffer structure 162 * 163 * Current contents of destination print buffer (if any) are discarded. 164 * Source print buffer becomes empty if a successful move occurs. 165 */ 166 167void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from) 168{ 169 int len; 170 171 /* Handle the cases where contents can't be moved */ 172 173 if (!pb_to->buf) 174 return; 175 176 if (!pb_from->buf) { 177 tipc_printbuf_reset(pb_to); 178 return; 179 } 180 181 if (pb_to->size < pb_from->size) { 182 tipc_printbuf_reset(pb_to); 183 tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***"); 184 return; 185 } 186 187 /* Copy data from char after cursor to end (if used) */ 188 189 len = pb_from->buf + pb_from->size - pb_from->crs - 2; 190 if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) { 191 strcpy(pb_to->buf, pb_from->crs + 1); 192 pb_to->crs = pb_to->buf + len; 193 } else 194 pb_to->crs = pb_to->buf; 195 196 /* Copy data from start to cursor (always) */ 197 198 len = pb_from->crs - pb_from->buf; 199 strcpy(pb_to->crs, pb_from->buf); 200 pb_to->crs += len; 201 202 tipc_printbuf_reset(pb_from); 203} 204 205/** 206 * tipc_printf - append formatted output to print buffer chain 207 * @pb: pointer to chain of print buffers (may be NULL) 208 * @fmt: formatted info to be printed 209 */ 210 211void tipc_printf(struct print_buf *pb, const char *fmt, ...) 212{ 213 int chars_to_add; 214 int chars_left; 215 char save_char; 216 struct print_buf *pb_next; 217 218 spin_lock_bh(&print_lock); 219 FORMAT(print_string, chars_to_add, fmt); 220 if (chars_to_add >= TIPC_PB_MAX_STR) 221 strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***"); 222 223 while (pb) { 224 if (pb == TIPC_CONS) 225 printk(print_string); 226 else if (pb->buf) { 227 chars_left = pb->buf + pb->size - pb->crs - 1; 228 if (chars_to_add <= chars_left) { 229 strcpy(pb->crs, print_string); 230 pb->crs += chars_to_add; 231 } else if (chars_to_add >= (pb->size - 1)) { 232 strcpy(pb->buf, print_string + chars_to_add + 1 233 - pb->size); 234 pb->crs = pb->buf + pb->size - 1; 235 } else { 236 strcpy(pb->buf, print_string + chars_left); 237 save_char = print_string[chars_left]; 238 print_string[chars_left] = 0; 239 strcpy(pb->crs, print_string); 240 print_string[chars_left] = save_char; 241 pb->crs = pb->buf + chars_to_add - chars_left; 242 } 243 } 244 pb_next = pb->next; 245 pb->next = NULL; 246 pb = pb_next; 247 } 248 spin_unlock_bh(&print_lock); 249} 250 251/** 252 * TIPC_TEE - perform next output operation on both print buffers 253 * @b0: pointer to chain of print buffers (may be NULL) 254 * @b1: pointer to print buffer to add to chain 255 * 256 * Returns pointer to print buffer chain. 257 */ 258 259struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1) 260{ 261 struct print_buf *pb = b0; 262 263 if (!b0 || (b0 == b1)) 264 return b1; 265 266 spin_lock_bh(&print_lock); 267 while (pb->next) { 268 if ((pb->next == b1) || (pb->next == b0)) 269 pb->next = pb->next->next; 270 else 271 pb = pb->next; 272 } 273 pb->next = b1; 274 spin_unlock_bh(&print_lock); 275 return b0; 276} 277 278/** 279 * print_to_console - write string of bytes to console in multiple chunks 280 */ 281 282static void print_to_console(char *crs, int len) 283{ 284 int rest = len; 285 286 while (rest > 0) { 287 int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR; 288 char c = crs[sz]; 289 290 crs[sz] = 0; 291 printk((const char *)crs); 292 crs[sz] = c; 293 rest -= sz; 294 crs += sz; 295 } 296} 297 298/** 299 * printbuf_dump - write print buffer contents to console 300 */ 301 302static void printbuf_dump(struct print_buf *pb) 303{ 304 int len; 305 306 if (!pb->buf) { 307 printk("*** PRINT BUFFER NOT ALLOCATED ***"); 308 return; 309 } 310 311 /* Dump print buffer from char after cursor to end (if used) */ 312 313 len = pb->buf + pb->size - pb->crs - 2; 314 if ((pb->buf[pb->size - 1] == 0) && (len > 0)) 315 print_to_console(pb->crs + 1, len); 316 317 /* Dump print buffer from start to cursor (always) */ 318 319 len = pb->crs - pb->buf; 320 print_to_console(pb->buf, len); 321} 322 323/** 324 * tipc_dump - dump non-console print buffer(s) to console 325 * @pb: pointer to chain of print buffers 326 */ 327 328void tipc_dump(struct print_buf *pb, const char *fmt, ...) 329{ 330 struct print_buf *pb_next; 331 int len; 332 333 spin_lock_bh(&print_lock); 334 FORMAT(print_string, len, fmt); 335 printk(print_string); 336 337 for (; pb; pb = pb->next) { 338 if (pb != TIPC_CONS) { 339 printk("\n---- Start of %s log dump ----\n\n", 340 (pb == TIPC_LOG) ? "global" : "local"); 341 printbuf_dump(pb); 342 tipc_printbuf_reset(pb); 343 printk("\n---- End of dump ----\n"); 344 } 345 pb_next = pb->next; 346 pb->next = NULL; 347 pb = pb_next; 348 } 349 spin_unlock_bh(&print_lock); 350} 351 352/** 353 * tipc_log_stop - free up TIPC log print buffer 354 */ 355 356void tipc_log_stop(void) 357{ 358 spin_lock_bh(&print_lock); 359 if (TIPC_LOG->buf) { 360 kfree(TIPC_LOG->buf); 361 TIPC_LOG->buf = NULL; 362 } 363 spin_unlock_bh(&print_lock); 364} 365 366/** 367 * tipc_log_reinit - (re)initialize TIPC log print buffer 368 * @log_size: print buffer size to use 369 */ 370 371void tipc_log_reinit(int log_size) 372{ 373 tipc_log_stop(); 374 375 if (log_size) { 376 if (log_size < TIPC_PB_MIN_SIZE) 377 log_size = TIPC_PB_MIN_SIZE; 378 spin_lock_bh(&print_lock); 379 tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), 380 log_size); 381 spin_unlock_bh(&print_lock); 382 } 383} 384 385/** 386 * tipc_log_resize - reconfigure size of TIPC log buffer 387 */ 388 389struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) 390{ 391 u32 value; 392 393 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 394 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 395 396 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 397 if (value != delimit(value, 0, 32768)) 398 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 399 " (log size must be 0-32768)"); 400 tipc_log_reinit(value); 401 return tipc_cfg_reply_none(); 402} 403 404/** 405 * tipc_log_dump - capture TIPC log buffer contents in configuration message 406 */ 407 408struct sk_buff *tipc_log_dump(void) 409{ 410 struct sk_buff *reply; 411 412 spin_lock_bh(&print_lock); 413 if (!TIPC_LOG->buf) 414 reply = tipc_cfg_reply_ultra_string("log not activated\n"); 415 else if (tipc_printbuf_empty(TIPC_LOG)) 416 reply = tipc_cfg_reply_ultra_string("log is empty\n"); 417 else { 418 struct tlv_desc *rep_tlv; 419 struct print_buf pb; 420 int str_len; 421 422 str_len = min(TIPC_LOG->size, 32768u); 423 reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len)); 424 if (reply) { 425 rep_tlv = (struct tlv_desc *)reply->data; 426 tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len); 427 tipc_printbuf_move(&pb, TIPC_LOG); 428 str_len = strlen(TLV_DATA(rep_tlv)) + 1; 429 skb_put(reply, TLV_SPACE(str_len)); 430 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); 431 } 432 } 433 spin_unlock_bh(&print_lock); 434 return reply; 435} 436