dbg.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * net/tipc/dbg.c: TIPC print buffer routines for debuggign
  3. *
  4. * Copyright (c) 2003-2005, Ericsson Research Canada
  5. * Copyright (c) 2005, Wind River Systems
  6. * Copyright (c) 2005-2006, Ericsson AB
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are met:
  11. *
  12. * Redistributions of source code must retain the above copyright notice, this
  13. * list of conditions and the following disclaimer.
  14. * Redistributions in binary form must reproduce the above copyright notice,
  15. * this list of conditions and the following disclaimer in the documentation
  16. * and/or other materials provided with the distribution.
  17. * Neither the names of the copyright holders nor the names of its
  18. * contributors may be used to endorse or promote products derived from this
  19. * software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  25. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  27. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  29. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  30. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. * POSSIBILITY OF SUCH DAMAGE.
  32. */
  33. #include "core.h"
  34. #include "config.h"
  35. #include "dbg.h"
  36. #define MAX_STRING 512
  37. static char print_string[MAX_STRING];
  38. static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
  39. static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
  40. struct print_buf *CONS = &cons_buf;
  41. static struct print_buf log_buf = { NULL, 0, NULL, NULL };
  42. struct print_buf *LOG = &log_buf;
  43. #define FORMAT(PTR,LEN,FMT) \
  44. {\
  45. va_list args;\
  46. va_start(args, FMT);\
  47. LEN = vsprintf(PTR, FMT, args);\
  48. va_end(args);\
  49. *(PTR + LEN) = '\0';\
  50. }
  51. /*
  52. * Locking policy when using print buffers.
  53. *
  54. * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
  55. * simultaneous use of the print buffer(s) being manipulated.
  56. * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
  57. * 'print_string' and to protect its print buffer(s).
  58. * 3) TEE() uses 'print_lock' to protect its print buffer(s).
  59. * 4) Routines of the form log_XXX() uses 'print_lock' to protect LOG.
  60. */
  61. /**
  62. * printbuf_init - initialize print buffer to empty
  63. */
  64. void printbuf_init(struct print_buf *pb, char *raw, u32 sz)
  65. {
  66. if (!pb || !raw || (sz < (MAX_STRING + 1)))
  67. return;
  68. pb->crs = pb->buf = raw;
  69. pb->size = sz;
  70. pb->next = 0;
  71. pb->buf[0] = 0;
  72. pb->buf[sz-1] = ~0;
  73. }
  74. /**
  75. * printbuf_reset - reinitialize print buffer to empty state
  76. */
  77. void printbuf_reset(struct print_buf *pb)
  78. {
  79. if (pb && pb->buf)
  80. printbuf_init(pb, pb->buf, pb->size);
  81. }
  82. /**
  83. * printbuf_empty - test if print buffer is in empty state
  84. */
  85. int printbuf_empty(struct print_buf *pb)
  86. {
  87. return (!pb || !pb->buf || (pb->crs == pb->buf));
  88. }
  89. /**
  90. * printbuf_validate - check for print buffer overflow
  91. *
  92. * Verifies that a print buffer has captured all data written to it.
  93. * If data has been lost, linearize buffer and prepend an error message
  94. *
  95. * Returns length of print buffer data string (including trailing NULL)
  96. */
  97. int printbuf_validate(struct print_buf *pb)
  98. {
  99. char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
  100. char *cp_buf;
  101. struct print_buf cb;
  102. if (!pb || !pb->buf)
  103. return 0;
  104. if (pb->buf[pb->size - 1] == '\0') {
  105. cp_buf = kmalloc(pb->size, GFP_ATOMIC);
  106. if (cp_buf != NULL){
  107. printbuf_init(&cb, cp_buf, pb->size);
  108. printbuf_move(&cb, pb);
  109. printbuf_move(pb, &cb);
  110. kfree(cp_buf);
  111. memcpy(pb->buf, err, strlen(err));
  112. } else {
  113. printbuf_reset(pb);
  114. tipc_printf(pb, err);
  115. }
  116. }
  117. return (pb->crs - pb->buf + 1);
  118. }
  119. /**
  120. * printbuf_move - move print buffer contents to another print buffer
  121. *
  122. * Current contents of destination print buffer (if any) are discarded.
  123. * Source print buffer becomes empty if a successful move occurs.
  124. */
  125. void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
  126. {
  127. int len;
  128. /* Handle the cases where contents can't be moved */
  129. if (!pb_to || !pb_to->buf)
  130. return;
  131. if (!pb_from || !pb_from->buf) {
  132. printbuf_reset(pb_to);
  133. return;
  134. }
  135. if (pb_to->size < pb_from->size) {
  136. printbuf_reset(pb_to);
  137. tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
  138. return;
  139. }
  140. /* Copy data from char after cursor to end (if used) */
  141. len = pb_from->buf + pb_from->size - pb_from->crs - 2;
  142. if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
  143. strcpy(pb_to->buf, pb_from->crs + 1);
  144. pb_to->crs = pb_to->buf + len;
  145. } else
  146. pb_to->crs = pb_to->buf;
  147. /* Copy data from start to cursor (always) */
  148. len = pb_from->crs - pb_from->buf;
  149. strcpy(pb_to->crs, pb_from->buf);
  150. pb_to->crs += len;
  151. printbuf_reset(pb_from);
  152. }
  153. /**
  154. * tipc_printf - append formatted output to print buffer chain
  155. */
  156. void tipc_printf(struct print_buf *pb, const char *fmt, ...)
  157. {
  158. int chars_to_add;
  159. int chars_left;
  160. char save_char;
  161. struct print_buf *pb_next;
  162. spin_lock_bh(&print_lock);
  163. FORMAT(print_string, chars_to_add, fmt);
  164. if (chars_to_add >= MAX_STRING)
  165. strcpy(print_string, "*** STRING TOO LONG ***");
  166. while (pb) {
  167. if (pb == CONS)
  168. printk(print_string);
  169. else if (pb->buf) {
  170. chars_left = pb->buf + pb->size - pb->crs - 1;
  171. if (chars_to_add <= chars_left) {
  172. strcpy(pb->crs, print_string);
  173. pb->crs += chars_to_add;
  174. } else {
  175. strcpy(pb->buf, print_string + chars_left);
  176. save_char = print_string[chars_left];
  177. print_string[chars_left] = 0;
  178. strcpy(pb->crs, print_string);
  179. print_string[chars_left] = save_char;
  180. pb->crs = pb->buf + chars_to_add - chars_left;
  181. }
  182. }
  183. pb_next = pb->next;
  184. pb->next = 0;
  185. pb = pb_next;
  186. }
  187. spin_unlock_bh(&print_lock);
  188. }
  189. /**
  190. * TEE - perform next output operation on both print buffers
  191. */
  192. struct print_buf *TEE(struct print_buf *b0, struct print_buf *b1)
  193. {
  194. struct print_buf *pb = b0;
  195. if (!b0 || (b0 == b1))
  196. return b1;
  197. if (!b1)
  198. return b0;
  199. spin_lock_bh(&print_lock);
  200. while (pb->next) {
  201. if ((pb->next == b1) || (pb->next == b0))
  202. pb->next = pb->next->next;
  203. else
  204. pb = pb->next;
  205. }
  206. pb->next = b1;
  207. spin_unlock_bh(&print_lock);
  208. return b0;
  209. }
  210. /**
  211. * print_to_console - write string of bytes to console in multiple chunks
  212. */
  213. static void print_to_console(char *crs, int len)
  214. {
  215. int rest = len;
  216. while (rest > 0) {
  217. int sz = rest < MAX_STRING ? rest : MAX_STRING;
  218. char c = crs[sz];
  219. crs[sz] = 0;
  220. printk((const char *)crs);
  221. crs[sz] = c;
  222. rest -= sz;
  223. crs += sz;
  224. }
  225. }
  226. /**
  227. * printbuf_dump - write print buffer contents to console
  228. */
  229. static void printbuf_dump(struct print_buf *pb)
  230. {
  231. int len;
  232. /* Dump print buffer from char after cursor to end (if used) */
  233. len = pb->buf + pb->size - pb->crs - 2;
  234. if ((pb->buf[pb->size - 1] == 0) && (len > 0))
  235. print_to_console(pb->crs + 1, len);
  236. /* Dump print buffer from start to cursor (always) */
  237. len = pb->crs - pb->buf;
  238. print_to_console(pb->buf, len);
  239. }
  240. /**
  241. * tipc_dump - dump non-console print buffer(s) to console
  242. */
  243. void tipc_dump(struct print_buf *pb, const char *fmt, ...)
  244. {
  245. int len;
  246. spin_lock_bh(&print_lock);
  247. FORMAT(CONS->buf, len, fmt);
  248. printk(CONS->buf);
  249. for (; pb; pb = pb->next) {
  250. if (pb == CONS)
  251. continue;
  252. printk("\n---- Start of dump,%s log ----\n\n",
  253. (pb == LOG) ? "global" : "local");
  254. printbuf_dump(pb);
  255. printbuf_reset(pb);
  256. printk("\n-------- End of dump --------\n");
  257. }
  258. spin_unlock_bh(&print_lock);
  259. }
  260. /**
  261. * log_stop - free up TIPC log print buffer
  262. */
  263. void log_stop(void)
  264. {
  265. spin_lock_bh(&print_lock);
  266. if (LOG->buf) {
  267. kfree(LOG->buf);
  268. LOG->buf = NULL;
  269. }
  270. spin_unlock_bh(&print_lock);
  271. }
  272. /**
  273. * log_reinit - set TIPC log print buffer to specified size
  274. */
  275. void log_reinit(int log_size)
  276. {
  277. log_stop();
  278. if (log_size) {
  279. if (log_size <= MAX_STRING)
  280. log_size = MAX_STRING + 1;
  281. spin_lock_bh(&print_lock);
  282. printbuf_init(LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
  283. spin_unlock_bh(&print_lock);
  284. }
  285. }
  286. /**
  287. * log_resize - reconfigure size of TIPC log buffer
  288. */
  289. struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space)
  290. {
  291. u32 value;
  292. if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
  293. return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
  294. value = *(u32 *)TLV_DATA(req_tlv_area);
  295. value = ntohl(value);
  296. if (value != delimit(value, 0, 32768))
  297. return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
  298. " (log size must be 0-32768)");
  299. log_reinit(value);
  300. return cfg_reply_none();
  301. }
  302. /**
  303. * log_dump - capture TIPC log buffer contents in configuration message
  304. */
  305. struct sk_buff *log_dump(void)
  306. {
  307. struct sk_buff *reply;
  308. spin_lock_bh(&print_lock);
  309. if (!LOG->buf)
  310. reply = cfg_reply_ultra_string("log not activated\n");
  311. else if (printbuf_empty(LOG))
  312. reply = cfg_reply_ultra_string("log is empty\n");
  313. else {
  314. struct tlv_desc *rep_tlv;
  315. struct print_buf pb;
  316. int str_len;
  317. str_len = min(LOG->size, 32768u);
  318. reply = cfg_reply_alloc(TLV_SPACE(str_len));
  319. if (reply) {
  320. rep_tlv = (struct tlv_desc *)reply->data;
  321. printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
  322. printbuf_move(&pb, LOG);
  323. str_len = strlen(TLV_DATA(rep_tlv)) + 1;
  324. skb_put(reply, TLV_SPACE(str_len));
  325. TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
  326. }
  327. }
  328. spin_unlock_bh(&print_lock);
  329. return reply;
  330. }