A dynamic tracer for Linux

kprobe.c 2.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <linux/ptrace.h>
  6. #include "ply.h"
  7. struct kprobe {
  8. };
  9. static int kprobe_ir_prologue(prog_t *prog)
  10. {
  11. sym_t *ctx = sym_get(prog->locals, "ctx");
  12. if (!ctx)
  13. return 0;
  14. ctx->reg = ir_alloc_register(prog->ir);
  15. ir_emit_reg_get(prog->ir, ctx->reg);
  16. /* kernel sets r1 to the address of the context */
  17. ir_emit_insn(prog->ir, MOV(0, 0), ctx->reg, BPF_REG_1);
  18. return 0;
  19. }
  20. static inline int is_arg(const char *name)
  21. {
  22. return (strstr(name, "arg") == name)
  23. && (strlen(name) == 4)
  24. && (name[3] >= '0' && name[3] <= '9');
  25. }
  26. static int kprobe_rewrite_arg(prog_t *prog, node_t *n)
  27. {
  28. const char *reg;
  29. int arg = n->ident[3] - '0';
  30. node_t *new, *ctx;
  31. reg = arch_register_argument(arg);
  32. if (!reg) {
  33. node_print(n, stderr);
  34. fputs(": the location of this argument is unknown\n", stderr);
  35. /* TODO: add ABI mappings for specifying arguments
  36. * passed on the stack. */
  37. return -EINVAL;
  38. }
  39. ctx = node_ident("ctx");
  40. /* argN => (*ctx).REG */
  41. new = node_vlist(node_keyword('.', 0),
  42. node_vlist(node_keyword('*', 0),
  43. ctx,
  44. NULL),
  45. node_string(reg),
  46. NULL);
  47. ctx->type = type_ptr_of(&t_pt_regs);
  48. new->type = n->type;
  49. new->list->type = &t_void;
  50. new->list->next->type = &t_pt_regs;
  51. new->list->next->list->type = &t_void;
  52. node_replace(n, new);
  53. return sym_add(prog->locals, ctx->ident, ctx->type, &ctx->sym);
  54. }
  55. static int kprobe_rewrite_node(prog_t *prog, node_t *n)
  56. {
  57. if ((n->ntype == N_IDENT) && is_arg(n->ident))
  58. return kprobe_rewrite_arg(prog, n);
  59. return 0;
  60. }
  61. static int kprobe_resolve(prog_t *prog, node_t *n)
  62. {
  63. type_t *t;
  64. if (is_arg(n->ident))
  65. t = &t_ulong;
  66. else if (!strcmp(n->ident, "ctx"))
  67. t = type_ptr_of(&t_pt_regs);
  68. else
  69. return -ENOENT;
  70. n->type = t;
  71. return sym_add(prog->locals, n->ident, t, &n->sym);
  72. }
  73. static int kprobe_probe(prog_t *prog)
  74. {
  75. struct kprobe *kp;
  76. kp = calloc(1, sizeof(*kp));
  77. assert(kp);
  78. prog->provider_data = kp;
  79. return 0;
  80. }
  81. provider_t kprobe = {
  82. .name = "kprobe",
  83. .ir_prologue = kprobe_ir_prologue,
  84. .rewrite_node = kprobe_rewrite_node,
  85. .resolve = kprobe_resolve,
  86. .probe = kprobe_probe,
  87. };
  88. __attribute__((constructor))
  89. static void kprobe_init(void)
  90. {
  91. provider_register(&kprobe);
  92. }