tracetool 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. #!/bin/sh
  2. #
  3. # Code generator for trace events
  4. #
  5. # Copyright IBM, Corp. 2010
  6. #
  7. # This work is licensed under the terms of the GNU GPL, version 2. See
  8. # the COPYING file in the top-level directory.
  9. # Disable pathname expansion, makes processing text with '*' characters simpler
  10. set -f
  11. usage()
  12. {
  13. cat >&2 <<EOF
  14. usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
  15. Generate tracing code for a file on stdin.
  16. Backends:
  17. --nop Tracing disabled
  18. --simple Simple built-in backend
  19. --stderr Stderr built-in backend
  20. --ust LTTng User Space Tracing backend
  21. --dtrace DTrace/SystemTAP backend
  22. Output formats:
  23. -h Generate .h file
  24. -c Generate .c file
  25. -d Generate .d file (DTrace only)
  26. --stap Generate .stp file (DTrace with SystemTAP only)
  27. Options:
  28. --binary [path] Full path to QEMU binary
  29. --target-arch [arch] QEMU emulator target arch
  30. --target-type [type] QEMU emulator target type ('system' or 'user')
  31. --probe-prefix [prefix] Prefix for dtrace probe names
  32. (default: qemu-\$targettype-\$targetarch)
  33. EOF
  34. exit 1
  35. }
  36. # Get the name of a trace event
  37. get_name()
  38. {
  39. echo ${1%%\(*}
  40. }
  41. # Get the argument list of a trace event, including types and names
  42. get_args()
  43. {
  44. local args
  45. args=${1#*\(}
  46. args=${args%%\)*}
  47. echo "$args"
  48. }
  49. # Get the argument name list of a trace event
  50. get_argnames()
  51. {
  52. local nfields field name sep
  53. nfields=0
  54. sep="$2"
  55. for field in $(get_args "$1"); do
  56. nfields=$((nfields + 1))
  57. # Drop pointer star
  58. field=${field#\*}
  59. # Only argument names have commas at the end
  60. name=${field%,}
  61. test "$field" = "$name" && continue
  62. printf "%s%s " $name $sep
  63. done
  64. # Last argument name
  65. if [ "$nfields" -gt 1 ]
  66. then
  67. printf "%s" "$name"
  68. fi
  69. }
  70. # Get the number of arguments to a trace event
  71. get_argc()
  72. {
  73. local name argc
  74. argc=0
  75. for name in $(get_argnames "$1", ","); do
  76. argc=$((argc + 1))
  77. done
  78. echo $argc
  79. }
  80. # Get the format string for a trace event
  81. get_fmt()
  82. {
  83. local fmt
  84. fmt=${1#*\"}
  85. fmt=${fmt%\"*}
  86. echo "$fmt"
  87. }
  88. # Get the state of a trace event
  89. get_state()
  90. {
  91. local str disable state
  92. str=$(get_name "$1")
  93. disable=${str##disable }
  94. if [ "$disable" = "$str" ] ; then
  95. state=1
  96. else
  97. state=0
  98. fi
  99. echo "$state"
  100. }
  101. linetoh_begin_nop()
  102. {
  103. return
  104. }
  105. linetoh_nop()
  106. {
  107. local name args
  108. name=$(get_name "$1")
  109. args=$(get_args "$1")
  110. # Define an empty function for the trace event
  111. cat <<EOF
  112. static inline void trace_$name($args)
  113. {
  114. }
  115. EOF
  116. }
  117. linetoh_end_nop()
  118. {
  119. return
  120. }
  121. linetoc_begin_nop()
  122. {
  123. return
  124. }
  125. linetoc_nop()
  126. {
  127. # No need for function definitions in nop backend
  128. return
  129. }
  130. linetoc_end_nop()
  131. {
  132. return
  133. }
  134. linetoh_begin_simple()
  135. {
  136. cat <<EOF
  137. #include "simpletrace.h"
  138. EOF
  139. simple_event_num=0
  140. }
  141. cast_args_to_uint64_t()
  142. {
  143. local arg
  144. for arg in $(get_argnames "$1", ","); do
  145. printf "%s" "(uint64_t)(uintptr_t)$arg"
  146. done
  147. }
  148. linetoh_simple()
  149. {
  150. local name args argc trace_args state
  151. name=$(get_name "$1")
  152. args=$(get_args "$1")
  153. argc=$(get_argc "$1")
  154. state=$(get_state "$1")
  155. if [ "$state" = "0" ]; then
  156. name=${name##disable }
  157. fi
  158. trace_args="$simple_event_num"
  159. if [ "$argc" -gt 0 ]
  160. then
  161. trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
  162. fi
  163. cat <<EOF
  164. static inline void trace_$name($args)
  165. {
  166. trace$argc($trace_args);
  167. }
  168. EOF
  169. simple_event_num=$((simple_event_num + 1))
  170. }
  171. linetoh_end_simple()
  172. {
  173. cat <<EOF
  174. #define NR_TRACE_EVENTS $simple_event_num
  175. extern TraceEvent trace_list[NR_TRACE_EVENTS];
  176. EOF
  177. }
  178. linetoc_begin_simple()
  179. {
  180. cat <<EOF
  181. #include "trace.h"
  182. TraceEvent trace_list[] = {
  183. EOF
  184. simple_event_num=0
  185. }
  186. linetoc_simple()
  187. {
  188. local name state
  189. name=$(get_name "$1")
  190. state=$(get_state "$1")
  191. if [ "$state" = "0" ] ; then
  192. name=${name##disable }
  193. fi
  194. cat <<EOF
  195. {.tp_name = "$name", .state=$state},
  196. EOF
  197. simple_event_num=$((simple_event_num + 1))
  198. }
  199. linetoc_end_simple()
  200. {
  201. cat <<EOF
  202. };
  203. EOF
  204. }
  205. #STDERR
  206. linetoh_begin_stderr()
  207. {
  208. cat <<EOF
  209. #include <stdio.h>
  210. EOF
  211. }
  212. linetoh_stderr()
  213. {
  214. local name args argnames argc fmt
  215. name=$(get_name "$1")
  216. args=$(get_args "$1")
  217. argnames=$(get_argnames "$1" ",")
  218. argc=$(get_argc "$1")
  219. fmt=$(get_fmt "$1")
  220. if [ "$argc" -gt 0 ]; then
  221. argnames=", $argnames"
  222. fi
  223. cat <<EOF
  224. static inline void trace_$name($args)
  225. {
  226. fprintf(stderr, "$name $fmt\n" $argnames);
  227. }
  228. EOF
  229. }
  230. linetoh_end_stderr()
  231. {
  232. return
  233. }
  234. linetoc_begin_stderr()
  235. {
  236. return
  237. }
  238. linetoc_stderr()
  239. {
  240. return
  241. }
  242. linetoc_end_stderr()
  243. {
  244. return
  245. }
  246. #END OF STDERR
  247. # Clean up after UST headers which pollute the namespace
  248. ust_clean_namespace() {
  249. cat <<EOF
  250. #undef mutex_lock
  251. #undef mutex_unlock
  252. #undef inline
  253. #undef wmb
  254. EOF
  255. }
  256. linetoh_begin_ust()
  257. {
  258. echo "#include <ust/tracepoint.h>"
  259. ust_clean_namespace
  260. }
  261. linetoh_ust()
  262. {
  263. local name args argnames
  264. name=$(get_name "$1")
  265. args=$(get_args "$1")
  266. argnames=$(get_argnames "$1", ",")
  267. cat <<EOF
  268. DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
  269. #define trace_$name trace_ust_$name
  270. EOF
  271. }
  272. linetoh_end_ust()
  273. {
  274. return
  275. }
  276. linetoc_begin_ust()
  277. {
  278. cat <<EOF
  279. #include <ust/marker.h>
  280. $(ust_clean_namespace)
  281. #include "trace.h"
  282. EOF
  283. }
  284. linetoc_ust()
  285. {
  286. local name args argnames fmt
  287. name=$(get_name "$1")
  288. args=$(get_args "$1")
  289. argnames=$(get_argnames "$1", ",")
  290. [ -z "$argnames" ] || argnames=", $argnames"
  291. fmt=$(get_fmt "$1")
  292. cat <<EOF
  293. DEFINE_TRACE(ust_$name);
  294. static void ust_${name}_probe($args)
  295. {
  296. trace_mark(ust, $name, "$fmt"$argnames);
  297. }
  298. EOF
  299. # Collect names for later
  300. names="$names $name"
  301. }
  302. linetoc_end_ust()
  303. {
  304. cat <<EOF
  305. static void __attribute__((constructor)) trace_init(void)
  306. {
  307. EOF
  308. for name in $names; do
  309. cat <<EOF
  310. register_trace_ust_$name(ust_${name}_probe);
  311. EOF
  312. done
  313. echo "}"
  314. }
  315. linetoh_begin_dtrace()
  316. {
  317. cat <<EOF
  318. #include "trace-dtrace.h"
  319. EOF
  320. }
  321. linetoh_dtrace()
  322. {
  323. local name args argnames state nameupper
  324. name=$(get_name "$1")
  325. args=$(get_args "$1")
  326. argnames=$(get_argnames "$1", ",")
  327. state=$(get_state "$1")
  328. if [ "$state" = "0" ] ; then
  329. name=${name##disable }
  330. fi
  331. nameupper=`echo $name | tr '[:lower:]' '[:upper:]'`
  332. # Define an empty function for the trace event
  333. cat <<EOF
  334. static inline void trace_$name($args) {
  335. if (QEMU_${nameupper}_ENABLED()) {
  336. QEMU_${nameupper}($argnames);
  337. }
  338. }
  339. EOF
  340. }
  341. linetoh_end_dtrace()
  342. {
  343. return
  344. }
  345. linetoc_begin_dtrace()
  346. {
  347. return
  348. }
  349. linetoc_dtrace()
  350. {
  351. # No need for function definitions in dtrace backend
  352. return
  353. }
  354. linetoc_end_dtrace()
  355. {
  356. return
  357. }
  358. linetod_begin_dtrace()
  359. {
  360. cat <<EOF
  361. provider qemu {
  362. EOF
  363. }
  364. linetod_dtrace()
  365. {
  366. local name args state
  367. name=$(get_name "$1")
  368. args=$(get_args "$1")
  369. state=$(get_state "$1")
  370. if [ "$state" = "0" ] ; then
  371. name=${name##disable }
  372. fi
  373. # DTrace provider syntax expects foo() for empty
  374. # params, not foo(void)
  375. if [ "$args" = "void" ]; then
  376. args=""
  377. fi
  378. # Define prototype for probe arguments
  379. cat <<EOF
  380. probe $name($args);
  381. EOF
  382. }
  383. linetod_end_dtrace()
  384. {
  385. cat <<EOF
  386. };
  387. EOF
  388. }
  389. linetostap_begin_dtrace()
  390. {
  391. return
  392. }
  393. linetostap_dtrace()
  394. {
  395. local i arg name args arglist state
  396. name=$(get_name "$1")
  397. args=$(get_args "$1")
  398. arglist=$(get_argnames "$1", "")
  399. state=$(get_state "$1")
  400. if [ "$state" = "0" ] ; then
  401. name=${name##disable }
  402. fi
  403. # Define prototype for probe arguments
  404. cat <<EOF
  405. probe $probeprefix.$name = process("$binary").mark("$name")
  406. {
  407. EOF
  408. i=1
  409. for arg in $arglist
  410. do
  411. # 'limit' is a reserved keyword
  412. if [ "$arg" = "limit" ]; then
  413. arg="_limit"
  414. fi
  415. cat <<EOF
  416. $arg = \$arg$i;
  417. EOF
  418. i="$((i+1))"
  419. done
  420. cat <<EOF
  421. }
  422. EOF
  423. }
  424. linetostap_end_dtrace()
  425. {
  426. return
  427. }
  428. # Process stdin by calling begin, line, and end functions for the backend
  429. convert()
  430. {
  431. local begin process_line end str disable
  432. begin="lineto$1_begin_$backend"
  433. process_line="lineto$1_$backend"
  434. end="lineto$1_end_$backend"
  435. "$begin"
  436. while read -r str; do
  437. # Skip comments and empty lines
  438. test -z "${str%%#*}" && continue
  439. # Process the line. The nop backend handles disabled lines.
  440. disable=${str%%disable *}
  441. echo
  442. if test -z "$disable"; then
  443. # Pass the disabled state as an arg for the simple
  444. # or DTrace backends which handle it dynamically.
  445. # For all other backends, call lineto$1_nop()
  446. if [ $backend = "simple" -o "$backend" = "dtrace" ]; then
  447. "$process_line" "$str"
  448. else
  449. "lineto$1_nop" "${str##disable }"
  450. fi
  451. else
  452. "$process_line" "$str"
  453. fi
  454. done
  455. echo
  456. "$end"
  457. }
  458. tracetoh()
  459. {
  460. cat <<EOF
  461. #ifndef TRACE_H
  462. #define TRACE_H
  463. /* This file is autogenerated by tracetool, do not edit. */
  464. #include "qemu-common.h"
  465. EOF
  466. convert h
  467. echo "#endif /* TRACE_H */"
  468. }
  469. tracetoc()
  470. {
  471. echo "/* This file is autogenerated by tracetool, do not edit. */"
  472. convert c
  473. }
  474. tracetod()
  475. {
  476. if [ $backend != "dtrace" ]; then
  477. echo "DTrace probe generator not applicable to $backend backend"
  478. exit 1
  479. fi
  480. echo "/* This file is autogenerated by tracetool, do not edit. */"
  481. convert d
  482. }
  483. tracetostap()
  484. {
  485. if [ $backend != "dtrace" ]; then
  486. echo "SystemTAP tapset generator not applicable to $backend backend"
  487. exit 1
  488. fi
  489. if [ -z "$binary" ]; then
  490. echo "--binary is required for SystemTAP tapset generator"
  491. exit 1
  492. fi
  493. if [ -z "$probeprefix" -a -z "$targettype" ]; then
  494. echo "--target-type is required for SystemTAP tapset generator"
  495. exit 1
  496. fi
  497. if [ -z "$probeprefix" -a -z "$targetarch" ]; then
  498. echo "--target-arch is required for SystemTAP tapset generator"
  499. exit 1
  500. fi
  501. if [ -z "$probeprefix" ]; then
  502. probeprefix="qemu.$targettype.$targetarch";
  503. fi
  504. echo "/* This file is autogenerated by tracetool, do not edit. */"
  505. convert stap
  506. }
  507. backend=
  508. output=
  509. binary=
  510. targettype=
  511. targetarch=
  512. probeprefix=
  513. until [ -z "$1" ]
  514. do
  515. case "$1" in
  516. "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
  517. "--binary") shift ; binary="$1" ;;
  518. "--target-arch") shift ; targetarch="$1" ;;
  519. "--target-type") shift ; targettype="$1" ;;
  520. "--probe-prefix") shift ; probeprefix="$1" ;;
  521. "-h" | "-c" | "-d") output="${1#-}" ;;
  522. "--stap") output="${1#--}" ;;
  523. "--check-backend") exit 0 ;; # used by ./configure to test for backend
  524. "--list-backends") # used by ./configure to list available backends
  525. echo "nop simple stderr ust dtrace"
  526. exit 0
  527. ;;
  528. *)
  529. usage;;
  530. esac
  531. shift
  532. done
  533. if [ "$backend" = "" -o "$output" = "" ]; then
  534. usage
  535. fi
  536. gen="traceto$output"
  537. "$gen"
  538. exit 0