Browse Source

argN -> regs rewrite done

Tobias Waldekranz.com 8 years ago
parent
commit
7c3acf08f0
4 changed files with 135 additions and 41 deletions
  1. 101 13
      global.c
  2. 24 24
      kprobe.c
  3. 5 0
      node.c
  4. 5 4
      ply.c

+ 101 - 13
global.c

12
 #include "sym.h"
12
 #include "sym.h"
13
 #include "type.h"
13
 #include "type.h"
14
 
14
 
15
+/* . */
16
+
17
+static int global_dot_type_infer(const struct func *func, struct node *n)
18
+{
19
+	struct node *sou, *member;
20
+	struct type *t;
21
+	struct tfield *f;
22
+
23
+	if (n->sym->type)
24
+		return 0;
25
+
26
+	sou = n->expr.args;
27
+	member = sou->next;
28
+	if (!sou->sym->type)
29
+		return 0;
30
+
31
+	t = type_base(sou->sym->type);
32
+
33
+	/* TODO: add union */
34
+	if (t->ttype != T_STRUCT) {
35
+		_e("%#N: %N is neither struct nor union (type '%T').\n",
36
+		   n, sou, sou->sym->type);
37
+		return -EINVAL;
38
+	}
39
+
40
+	tfields_foreach(f, t->sou.fields) {
41
+		if (!strcmp(f->name, member->string.data)) {
42
+			/* given `sou.member` where sou is a
43
+			 * struct/union, infer that the expression's
44
+			 * type is equal to member's type. */
45
+			n->sym->type = f->type;
46
+			return 0;
47
+		}
48
+	}
49
+
50
+	_e("%#N: type '%T' has no member named '%s'.\n",
51
+	   n, t, member->string.data);
52
+	return -EINVAL;
53
+}
54
+
55
+
56
+/* :deref */
57
+
58
+static int global_deref_type_infer(const struct func *func, struct node *n)
59
+{
60
+	struct node *ptr = n->expr.args;
61
+	struct type *t;
62
+
63
+	if (n->sym->type || !ptr->sym->type)
64
+		return 0;
65
+
66
+	t = type_base(ptr->sym->type);
67
+	if (t->ttype != T_POINTER) {
68
+		_e("%#N: can't dereference %N (type '%T').\n",
69
+		   n, ptr, ptr->sym->type);
70
+		return -EINVAL;
71
+	}
72
+
73
+	/* given `*p` where p is a pointer, infer that the
74
+	 * expression's type is equal to p's concrete type. */
75
+	n->sym->type = t->ptr.type;
76
+	return 0;
77
+}
78
+
15
 
79
 
16
 /* :map */
80
 /* :map */
17
 
81
 
65
 static int global_map_static_validate(const struct func *func, struct node *n)
129
 static int global_map_static_validate(const struct func *func, struct node *n)
66
 {
130
 {
67
 	if (n->expr.args->ntype != N_IDENT) {
131
 	if (n->expr.args->ntype != N_IDENT) {
68
-		_e("%#N: trying to lookup a key in %N, which is not a map.\n",
132
+		_e("%#N: can't lookup a key in %N, which is not a map.\n",
69
 		   n, n);
133
 		   n, n);
70
 		return -EINVAL;
134
 		return -EINVAL;
71
 	}
135
 	}
222
 	.func = { .type = &t_void, .vargs = 1 },
286
 	.func = { .type = &t_void, .vargs = 1 },
223
 };
287
 };
224
 
288
 
289
+struct type t_string_array = {
290
+	.ttype = T_ARRAY,
291
+
292
+	.array = { .type = &t_char, .len = 64 }, /* TODO: tunable */
293
+};
294
+
295
+struct type t_string = {
296
+	.ttype = T_TYPEDEF,
297
+
298
+	.tdef = { .name = ":string", .type = &t_string_array },
299
+};
300
+
301
+struct tfield f_dot[] = {
302
+	{ .type = &t_void },
303
+	{ .type = &t_string },
304
+
305
+	{ .type = NULL }
306
+};
307
+
308
+struct type t_dot_func = {
309
+	.ttype = T_FUNC,
310
+
311
+	.func = { .type = &t_void, .args = f_dot },
312
+};
313
+
225
 struct tfield f_2args[] = {
314
 struct tfield f_2args[] = {
226
 	{ .type = &t_void },
315
 	{ .type = &t_void },
227
 	{ .type = &t_void },
316
 	{ .type = &t_void },
254
 		.static_ret = 1,
343
 		.static_ret = 1,
255
 	},
344
 	},
256
 
345
 
346
+	{
347
+		.name = ".",
348
+		.type = &t_dot_func,
349
+		.type_infer = global_dot_type_infer,
350
+	},
351
+	{
352
+		.name = ":deref",
353
+		.type = &t_1arg_func,
354
+		.type_infer = global_deref_type_infer,
355
+	},
356
+
257
 	{
357
 	{
258
 		.name = "+",
358
 		.name = "+",
259
 		.type = &t_2args_func,
359
 		.type = &t_2args_func,
330
 	.name = ":num",
430
 	.name = ":num",
331
 };
431
 };
332
 
432
 
333
-struct type t_string_array = {
334
-	.ttype = T_ARRAY,
335
-
336
-	.array = { .type = &t_char, .len = 64 }, /* TODO: tunable */
337
-};
338
-
339
-struct type t_string = {
340
-	.ttype = T_TYPEDEF,
341
-
342
-	.tdef = { .name = ":string", .type = &t_string_array },
343
-};
344
-
345
 static const struct func global_string_func = {
433
 static const struct func global_string_func = {
346
 	.name = ":string",
434
 	.name = ":string",
347
 	.type = &t_string,
435
 	.type = &t_string,

+ 24 - 24
kprobe.c

14
 #include "type.h"
14
 #include "type.h"
15
 
15
 
16
 struct kprobe {
16
 struct kprobe {
17
-	int use_ctx:1;
18
-
19
-	struct irstate ctx_irs;
17
+	struct irstate regs_irs;
20
 };
18
 };
21
 
19
 
22
-/* ctx */
20
+/* regs */
23
 
21
 
24
 static struct type t_pt_regsp = {
22
 static struct type t_pt_regsp = {
25
 	.ttype = T_POINTER,
23
 	.ttype = T_POINTER,
27
 	.ptr.type = &t_pt_regs,
25
 	.ptr.type = &t_pt_regs,
28
 };
26
 };
29
 
27
 
30
-static const struct func kprobe_ctx_func = {
31
-	.name = "ctx",
28
+static const struct func kprobe_regs_func = {
29
+	.name = "regs",
32
 
30
 
33
 	.type = &t_pt_regsp,
31
 	.type = &t_pt_regsp,
34
 	.static_ret = 1,
32
 	.static_ret = 1,
61
 		return -EINVAL;
59
 		return -EINVAL;
62
 	}
60
 	}
63
 
61
 
64
-	/* argN => (*ctx).REG */
62
+	/* argN => (*regs).REG */
65
 	new = node_expr(".",
63
 	new = node_expr(".",
66
-			node_expr("*", node_ident("ctx"), NULL),
64
+			node_expr(":deref", node_ident("regs"), NULL),
67
 			node_string((char *)reg),
65
 			node_string((char *)reg),
68
 			NULL);
66
 			NULL);
69
 
67
 
70
-	ast_fprint(stdout, n);
71
-	ast_fprint(stdout, new);
72
-
73
 	node_replace(n, new);
68
 	node_replace(n, new);
74
 	return 0;
69
 	return 0;
75
 }
70
 }
91
 static int kprobe_ir_pre(struct prog *prog)
86
 static int kprobe_ir_pre(struct prog *prog)
92
 {
87
 {
93
 	struct kprobe *kp = prog->provider_data;
88
 	struct kprobe *kp = prog->provider_data;
89
+	struct sym **sym;
90
+
91
+	symtab_foreach(prog->locals, sym) {
92
+		if ((*sym)->name && !strcmp((*sym)->name, "regs")) {
93
+			irs_alloc_reg(&kp->regs_irs, prog->ir);
94
+
95
+			/* kernel sets r1 to the address of the
96
+			 * pt_regs struct, which ply denotes as
97
+			 * 'regs'. if we're using it we need to get a
98
+			 * reference to it before it is clobbered. */
99
+			ir_emit_insn(prog->ir, MOV(0, 0),
100
+				     kp->regs_irs.reg, BPF_REG_1);
101
+		}
102
+	}
94
 
103
 
95
-	if (!kp->use_ctx)
96
-		return 0;
97
-
98
-	irs_alloc_reg(&kp->ctx_irs, prog->ir);
99
-
100
-	/* kernel sets r1 to the address of the context */
101
-	ir_emit_insn(prog->ir, MOV(0, 0), kp->ctx_irs.reg, BPF_REG_1);
102
 	return 0;
104
 	return 0;
103
 }
105
 }
104
 
106
 
105
 static int kprobe_sym_alloc(struct prog *prog, struct node *n)
107
 static int kprobe_sym_alloc(struct prog *prog, struct node *n)
106
 {
108
 {
107
-	struct kprobe *kp = prog->provider_data;
108
 	const struct func *func = NULL;
109
 	const struct func *func = NULL;
109
 	int err;
110
 	int err;
110
 
111
 
112
 	case N_EXPR:
113
 	case N_EXPR:
113
 		break;
114
 		break;
114
 	case N_IDENT:
115
 	case N_IDENT:
115
-		if (!is_arg(n->ident.name))
116
-			break;
117
-
118
-		func = &kprobe_arg_func;
119
-		kp->use_ctx = 1;
116
+		if (!strcmp(n->ident.name, "regs"))
117
+			func = &kprobe_regs_func;
118
+		else if (is_arg(n->ident.name))
119
+			func = &kprobe_arg_func;
120
 		break;
120
 		break;
121
 	default:
121
 	default:
122
 		break;
122
 		break;

+ 5 - 0
node.c

86
 		n->next->prev = new;
86
 		n->next->prev = new;
87
 	}
87
 	}
88
 
88
 
89
+	if (new->up
90
+	    && (new->up->ntype == N_EXPR)
91
+	    && (new->up->expr.args == n))
92
+		new->up->expr.args = new;
93
+
89
 	/* TODO: don't leak memory */
94
 	/* TODO: don't leak memory */
90
 	return 0;
95
 	return 0;
91
 }
96
 }

+ 5 - 4
ply.c

254
 
254
 
255
 struct pass passes[] = {
255
 struct pass passes[] = {
256
 	{ .run = run_walk, .post = pass_sym_alloc },
256
 	{ .run = run_walk, .post = pass_sym_alloc },
257
-	/* node->sym ok */
258
 	{ .run = run_walk, .post = pass_type_infer },
257
 	{ .run = run_walk, .post = pass_type_infer },
259
-	/* node->sym->type ok */
260
-	/* user input is accepted. we'll now start rewriting the ast,
261
-	 * so errors beyond this point are internal errors. */
258
+
262
 	{ .run = run_walk, .post = pass_rewrite },
259
 	{ .run = run_walk, .post = pass_rewrite },
260
+
261
+	{ .run = run_walk, .post = pass_sym_alloc },
262
+	{ .run = run_walk, .post = pass_type_infer },
263
+
263
 	{ .run = run_ir },
264
 	{ .run = run_ir },
264
 	/* program flattened to vBPF instructions, now rewrite it to
265
 	/* program flattened to vBPF instructions, now rewrite it to
265
 	 * fit into the actual hw/vm. */
266
 	 * fit into the actual hw/vm. */