Computer Laboratory

tesla_debug.c
Go to the documentation of this file.
1 
2 /*-
3  * Copyright (c) 2012-2013 Jonathan Anderson
4  * All rights reserved.
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $Id$
32  */
33 
34 #include "tesla_internal.h"
35 #include "tesla_strnlen.h"
36 
37 #ifndef _KERNEL
38 #include <fnmatch.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #endif
42 
43 void
44 print_transition(const char *debug, const struct tesla_transition *t)
45 {
46  if (!tesla_debugging(debug))
47  return;
48 
49  char buffer[1024];
50  char *end = buffer + sizeof(buffer);
51 
52  sprint_transition(buffer, end, t);
53  print("%s", buffer);
54 }
55 
56 char*
57 sprint_transition(char *buf, const char *end, const struct tesla_transition *t)
58 {
59  char *c = buf;
60 
61  /* Note: On at least one Mac, combining the following
62  * into a single snprintf() causes the wrong thing
63  * to be printed (instead of t->mask, we get an address!).
64  */
65  SAFE_SPRINTF(c, end, "(%d:", t->from);
66  SAFE_SPRINTF(c, end, "0x%tx", t->from_mask);
67  SAFE_SPRINTF(c, end, " -> %d:", t->to);
68  SAFE_SPRINTF(c, end, "0x%tx", t->to_mask);
69 
70  if (t->flags & TESLA_TRANS_INIT)
71  SAFE_SPRINTF(c, end, " <init>");
72 
73  if (t->flags & TESLA_TRANS_CLEANUP)
74  SAFE_SPRINTF(c, end, " <clean>");
75 
76  SAFE_SPRINTF(c, end, ") ");
77 
78  return c;
79 }
80 
81 void
82 print_transitions(const char *debug, const struct tesla_transitions *transp)
83 {
84  if (!tesla_debugging(debug))
85  return;
86 
87  char buffer[1024];
88  char *end = buffer + sizeof(buffer);
89 
90  sprint_transitions(buffer, end, transp);
91  print("%s", buffer);
92 }
93 
94 char*
95 sprint_transitions(char *buffer, const char *end,
96  const struct tesla_transitions *tp)
97 {
98  char *c = buffer;
99 
100  SAFE_SPRINTF(c, end, "[ ");
101 
102  for (size_t i = 0; i < tp->length; i++)
103  c = sprint_transition(c, end, tp->transitions + i);
104 
105  SAFE_SPRINTF(c, end, "]");
106 
107  return c;
108 }
109 
110 char*
111 key_string(char *buffer, const char *end, const struct tesla_key *key)
112 {
113  char *c = buffer;
114 
115  SAFE_SPRINTF(c, end, "0x%tx [ ", key->tk_mask);
116 
117  for (int32_t i = 0; i < TESLA_KEY_SIZE; i++) {
118  if (key->tk_mask & (1 << i))
119  SAFE_SPRINTF(c, end, "%tx ", key->tk_keys[i]);
120  else
121  SAFE_SPRINTF(c, end, "X ");
122  }
123 
124  SAFE_SPRINTF(c, end, "]");
125 
126  return c;
127 }
128 
129 #ifndef NDEBUG
130 
131 int32_t
132 tesla_debugging(const char *name)
133 {
134 #ifdef _KERNEL
135  /*
136  * In the kernel, only print 'libtesla.{event,instance}*' output.
137  */
138  static const char* allowed[] = {
139  "libtesla.event",
140  "libtesla.instance",
141  NULL,
142  };
143  const size_t len = sizeof(allowed) / sizeof(allowed[0]);
144 
145  for (size_t i = 0; (i < len) && (allowed[i] != NULL); i++) {
146  const char *s = allowed[i];
147  const size_t len = strlen(s);
148 
149  if (strncmp(s, name, len) == 0)
150  return 1;
151  }
152 
153  return 0;
154 #else
155 #ifdef HAVE_ISSETUGID
156  /*
157  * Debugging paths could be more vulnerable to format string problems
158  * than other code; don't allow when running setuid or setgid.
159  */
160  if (issetugid())
161  return 0;
162 #endif
163 
164  const char *env = getenv("TESLA_DEBUG");
165 
166  /* If TESLA_DEBUG is not set, we're definitely not debugging. */
167  if (env == NULL)
168  return 0;
169 
170  /* Allow e.g. 'libtesla' to match 'libtesla.foo'. */
171  size_t envlen = strnlen(env, 100);
172  if ((strncmp(env, name, envlen) == 0) && (name[envlen] == '.'))
173  return 1;
174 
175  /* Otherwise, use fnmatch's normal star-matching. */
176  return (fnmatch(env, name, 0) == 0);
177 #endif
178 }
179 
180 void
181 assert_instanceof(struct tesla_instance *instance, struct tesla_class *tclass)
182 {
183  assert(instance != NULL);
184  assert(tclass != NULL);
185 
186  int32_t instance_belongs_to_class = 0;
187  for (uint32_t i = 0; i < tclass->tc_limit; i++) {
188  if (instance == &tclass->tc_instances[i]) {
189  instance_belongs_to_class = 1;
190  break;
191  }
192  }
193 
194  tesla_assert(instance_belongs_to_class,
195  ("tesla_instance %x not of class '%s'",
196  instance, tclass->tc_name)
197  );
198 }
199 
200 void
201 print_class(const struct tesla_class *c)
202 {
203  static const char *DEBUG_NAME = "libtesla.class.state";
204  if (!tesla_debugging(DEBUG_NAME))
205  return;
206 
207  print("----\n");
208  print("struct tesla_class @ 0x%tx {\n", (intptr_t) c);
209  print(" name: '%s',\n", c->tc_name);
210  print(" description: '[...]',\n"); // TL;DR
211  print(" scope: ");
212  switch (c->tc_context) {
213  case TESLA_CONTEXT_THREAD: print("thread-local\n"); break;
214  case TESLA_CONTEXT_GLOBAL: print("global\n"); break;
215  default:
216  print("UNKNOWN (0x%x)\n", c->tc_context);
217  }
218  print(" limit: %d\n", c->tc_limit);
219  print(" %d/%d instances\n", c->tc_limit - c->tc_free, c->tc_limit);
220  for (uint32_t i = 0; i < c->tc_limit; i++) {
221  const struct tesla_instance *inst = c->tc_instances + i;
222  if (!tesla_instance_active(inst))
223  continue;
224 
225  print(" %2u: state %d, ", i, inst->ti_state);
226  print_key(DEBUG_NAME, &inst->ti_key);
227  print("\n");
228  }
229  print("}\n");
230  print("----\n");
231 }
232 
233 void
234 print_key(const char *debug_name, const struct tesla_key *key)
235 {
236  if (!tesla_debugging(debug_name))
237  return;
238 
239  static const size_t LEN = 15 * TESLA_KEY_SIZE + 10;
240  char buffer[LEN];
241  char *end = buffer + LEN;
242 
243  char *e = key_string(buffer, end, key);
244  assert(e < end);
245 
246  print("%s", buffer);
247 }
248 
249 #endif /* !NDEBUG */
250