devprobe.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include "probe.h"
  16. enum {
  17. Qdir,
  18. Qctl,
  19. Qdata,
  20. };
  21. enum {
  22. ProbeEntry = 1,
  23. ProbeExit
  24. };
  25. /* fix me make this programmable */
  26. enum {
  27. defaultlogsize = 1024,
  28. printsize = 64,
  29. };
  30. typedef struct Probelog Probelog;
  31. struct Probelog {
  32. uint64_t ticks;
  33. /* yeah, waste a whole int on something stupid but ... */
  34. int info;
  35. uint32_t pc;
  36. /* these are different depending on type */
  37. int32_t dat[4];
  38. };
  39. static Rendez probesleep;
  40. static QLock probeslk;
  41. static Probe *probes;
  42. static Lock loglk;
  43. static Probelog *probelog = nil;
  44. /* probe indices. These are just unsigned longs. You mask them
  45. * to get an index. This makes fifo empty/full etc. trivial.
  46. */
  47. static uint32_t pw = 0, pr = 0;
  48. static int probesactive = 0;
  49. static unsigned long logsize = defaultlogsize, logmask = defaultlogsize - 1;
  50. static char eventname[] = {
  51. [ProbeEntry] = 'E',
  52. [ProbeExit] = 'X'
  53. };
  54. static Dirtab probedir[]={
  55. {".", {Qdir, 0, QTDIR}, 0, DMDIR|0555},
  56. {"probectl", {Qctl}, 0, 0664},
  57. {"probe", {Qdata}, 0, 0440},
  58. };
  59. char hex[] = {
  60. '0',
  61. '1',
  62. '2',
  63. '3',
  64. '4',
  65. '5',
  66. '6',
  67. '7',
  68. '8',
  69. '9',
  70. 'A',
  71. 'B',
  72. 'C',
  73. 'D',
  74. 'E',
  75. 'F',
  76. };
  77. /* big-endian ... */
  78. void
  79. hex32(uint32_t l, char *c)
  80. {
  81. int i;
  82. for(i = 8; i; i--){
  83. c[i-1] = hex[l&0xf];
  84. l >>= 4;
  85. }
  86. }
  87. void
  88. hex64(uint64_t l, char *c)
  89. {
  90. hex32(l>>32, c);
  91. hex32(l, &c[8]);
  92. }
  93. static int
  94. lognonempty(void *)
  95. {
  96. return pw - pr;
  97. }
  98. static int
  99. logfull(void)
  100. {
  101. return (pw - pr) >= logsize;
  102. }
  103. static uint32_t
  104. idx(uint32_t f)
  105. {
  106. return f & logmask;
  107. }
  108. /* can return NULL, meaning, no record for you */
  109. static struct Probelog *
  110. newpl(void)
  111. {
  112. uint32_t index;
  113. if (logfull()){
  114. wakeup(&probesleep);
  115. return nil;
  116. }
  117. ilock(&loglk);
  118. index = pw++;
  119. iunlock(&loglk);
  120. return &probelog[idx(index)];
  121. }
  122. static void
  123. probeentry(Probe *p)
  124. {
  125. struct Probelog *pl;
  126. //print("probeentry %p p %p func %p argp %p\n", &p, p, p->func, p->argp);
  127. pl = newpl();
  128. if (! pl)
  129. return;
  130. cycles(&pl->ticks);
  131. pl->pc = (uint32_t)p->func;
  132. pl->dat[0] = p->argp[0];
  133. pl->dat[1] = p->argp[1];
  134. pl->dat[2] = p->argp[2];
  135. pl->dat[3] = p->argp[3];
  136. pl->info = ProbeEntry;
  137. }
  138. static void
  139. probeexit(Probe *p)
  140. {
  141. //print("probeexit %p p %p func %p argp %p\n", &p, p, p->func, p->argp);
  142. struct Probelog *pl;
  143. pl = newpl();
  144. if (! pl)
  145. return;
  146. cycles(&pl->ticks);
  147. pl->pc = (uint32_t)p->func;
  148. pl->dat[0] = p->rval;
  149. pl->info = ProbeExit;
  150. }
  151. static Chan*
  152. probeattach(char *spec)
  153. {
  154. return devattach('+', spec);
  155. }
  156. static Walkqid*
  157. probewalk(Chan *c, Chan *nc, char **name, int nname)
  158. {
  159. return devwalk(c, nc, name, nname, probedir, nelem(probedir), devgen);
  160. }
  161. static int32_t
  162. probestat(Chan *c, uint8_t *db, int32_t n)
  163. {
  164. return devstat(c, db, n, probedir, nelem(probedir), devgen);
  165. }
  166. static Chan*
  167. probeopen(Chan *c, int omode)
  168. {
  169. /* if there is no probelog, allocate one. Open always fails
  170. * if the basic alloc fails. You can resize it later.
  171. */
  172. if (! probelog)
  173. probelog = malloc(sizeof(*probelog)*logsize);
  174. /* I guess malloc doesn't toss an error */
  175. if (! probelog)
  176. error("probelog malloc failed");
  177. c = devopen(c, omode, probedir, nelem(probedir), devgen);
  178. return c;
  179. }
  180. static void
  181. probeclose(Chan *)
  182. {
  183. }
  184. static int32_t
  185. proberead(Chan *c, void *a, int32_t n, int64_t offset)
  186. {
  187. char *buf;
  188. char *cp = a;
  189. struct Probelog *pl;
  190. Probe *p;
  191. int i;
  192. static QLock gate;
  193. if(c->qid.type == QTDIR)
  194. return devdirread(c, a, n, probedir, nelem(probedir), devgen);
  195. switch((uint32_t)c->qid.path){
  196. default:
  197. error("proberead: bad qid");
  198. case Qctl:
  199. buf = malloc(READSTR);
  200. i = 0;
  201. qlock(&probeslk);
  202. i += snprint(buf + i, READSTR - i, "logsize %lu\n", logsize);
  203. for(p = probes; p != nil; p = p->next)
  204. i += snprint(buf + i, READSTR - i, "probe %p new %s\n",
  205. p->func, p->name);
  206. for(p = probes; p != nil; p = p->next)
  207. if (p->enabled)
  208. i += snprint(buf + i, READSTR - i, "probe %s on\n",
  209. p->name);
  210. i += snprint(buf + i, READSTR - i, "#probehits %lu, in queue %lu\n",
  211. pw, pw-pr);
  212. snprint(buf + i, READSTR - i, "#probelog %p\n", probelog);
  213. qunlock(&probeslk);
  214. n = readstr(offset, a, n, buf);
  215. free(buf);
  216. break;
  217. case Qdata:
  218. qlock(&gate);
  219. if(waserror()){
  220. qunlock(&gate);
  221. nexterror();
  222. }
  223. while(!lognonempty(nil))
  224. tsleep(&probesleep, lognonempty, nil, 5000);
  225. i = 0;
  226. while(lognonempty((void *)0)){
  227. int j;
  228. pl = probelog + idx(pr);
  229. if ((i + printsize) >= n)
  230. break;
  231. /* simple format */
  232. cp[0] = eventname[pl->info];
  233. cp ++;
  234. *cp++ = ' ';
  235. hex32(pl->pc, cp);
  236. cp[8] = ' ';
  237. cp += 9;
  238. hex64(pl->ticks, cp);
  239. cp[16] = ' ';
  240. cp += 17;
  241. for(j = 0; j < 4; j++){
  242. hex32(pl->dat[j], cp);
  243. cp[8] = ' ';
  244. cp += 9;
  245. }
  246. /* adjust for extra skip above */
  247. cp--;
  248. *cp++ = '\n';
  249. pr++;
  250. i += printsize;
  251. }
  252. poperror();
  253. qunlock(&gate);
  254. n = i;
  255. break;
  256. }
  257. return n;
  258. }
  259. static int32_t
  260. probewrite(Chan *c, void *a, int32_t n, int64_t)
  261. {
  262. char *tok[5];
  263. char *ep, *s = nil;
  264. Probe *p, **pp;
  265. int ntok;
  266. qlock(&probeslk);
  267. if(waserror()){
  268. qunlock(&probeslk);
  269. if(s != nil) free(s);
  270. nexterror();
  271. }
  272. switch((uint32_t)c->qid.path){
  273. default:
  274. error("proberead: bad qid");
  275. case Qctl:
  276. s = malloc(n + 1);
  277. memmove(s, a, n);
  278. s[n] = 0;
  279. ntok = tokenize(s, tok, nelem(tok));
  280. if(!strcmp(tok[0], "probe")){ /* 'probe' ktextaddr 'on'|'off'|'mk'|'del' [name] */
  281. if(ntok < 3)
  282. error("devprobe: usage: 'probe' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name]");
  283. for(pp = &probes; *pp != nil; pp = &(*pp)->next)
  284. if(!strcmp(tok[1], (*pp)->name))
  285. break;
  286. p = *pp;
  287. if(!strcmp(tok[2], "new")){
  288. uint32_t addr;
  289. void *func;
  290. addr = strtoul(tok[1], &ep, 0);
  291. func = (void*)addr;
  292. if(*ep)
  293. error("devprobe: address not in recognized format");
  294. // if(addr < ((uint32_t) start) || addr > ((uint32_t) end))
  295. // error("devprobe: address out of bounds");
  296. if(p != nil)
  297. error("devprobe: 0x%p already has probe");
  298. p = mkprobe(func, probeentry, probeexit);
  299. p->next = probes;
  300. if(ntok < 4)
  301. snprint(p->name, sizeof p->name, "%p", func);
  302. else
  303. strncpy(p->name, tok[3], sizeof p->name);
  304. probes = p;
  305. } else if(!strcmp(tok[2], "on")){
  306. if(p == nil)
  307. error("devprobe: probe not found");
  308. if(!p->enabled)
  309. probeinstall(p);
  310. print("probeinstall in devprobe\n");
  311. probesactive++;
  312. } else if(!strcmp(tok[2], "off")){
  313. if(p == nil)
  314. error("devprobe: probe not found");
  315. if(p->enabled)
  316. probeuninstall(p);
  317. probesactive--;
  318. } else if(!strcmp(tok[2], "del")){
  319. if(p == nil)
  320. error("devprobe: probe not found");
  321. if(p->enabled)
  322. probeuninstall(p);
  323. probesactive--;
  324. *pp = p->next;
  325. freeprobe(p);
  326. } else if(!strcmp(tok[2], "mv")){
  327. if(p == nil)
  328. error("devprobe: probe not found");
  329. if(ntok < 4)
  330. error("devprobe: rename without new name?");
  331. strncpy(p->name, tok[3], sizeof p->name);
  332. }
  333. } else if(!strcmp(tok[0], "size")){
  334. int l, size;
  335. struct Probelog *newprobelog;
  336. l = strtoul(tok[1], &ep, 0);
  337. if(*ep)
  338. error("devprobe: size not in recognized format");
  339. size = 1 << l;
  340. /* sort of foolish. Alloc new probe first, then free old. */
  341. /* and too bad if there are unread probes */
  342. newprobelog = malloc(sizeof(*newprobelog)*size);
  343. /* does malloc throw waserror? I don't know */
  344. free(probelog);
  345. probelog = newprobelog;
  346. logsize = size;
  347. pr = pw = 0;
  348. } else {
  349. error("devprobe: usage: 'probe' [ktextaddr|name] 'on'|'off'|'mk'|'del' [name] or: 'size' buffersize (power of 2)");
  350. }
  351. free(s);
  352. break;
  353. }
  354. poperror();
  355. qunlock(&probeslk);
  356. return n;
  357. }
  358. Dev probedevtab = {
  359. .dc = '+',
  360. .name = "probe",
  361. .reset = devreset,
  362. .init = devinit,
  363. .shutdown = devshutdown,
  364. .attach = probeattach,
  365. .walk = probewalk,
  366. .stat = probestat,
  367. .open = probeopen,
  368. .create = devcreate,
  369. .close = probeclose,
  370. .read = proberead,
  371. .bread = devbread,
  372. .write = probewrite,
  373. .bwrite = devbwrite,
  374. .remove = devremove,
  375. .wstat = devwstat,
  376. };