1 // bpf translation pass
2 // Copyright (C) 2016-2019 Red Hat Inc.
4 // This file is part of systemtap, and is free software. You can
5 // redistribute it and/or modify it under the terms of the GNU General
6 // Public License (GPL); either version 2, or (at your option) any
10 #include "bpf-internal.h"
11 #include "elaborate.h"
20 value::print(std::ostream
&o
) const
27 return o
<< "$" << imm_val
;
29 return o
<< "$\"" << escaped_literal_string (str_val
) << "\"";
31 return o
<< "r" << reg_val
;
33 return o
<< "t" << reg_val
;
35 return o
<< "<BUG:unknown operand>";
40 : code(-1), id(0), off(0),
41 dest(NULL
), src0(NULL
), src1(NULL
),
42 prev(NULL
), next(NULL
)
48 if (BPF_CLASS (code
) != BPF_JMP
)
50 switch (BPF_OP (code
))
71 case BPF_ALU64
| BPF_MOV
| BPF_X
:
72 case BPF_ALU64
| BPF_MOV
| BPF_K
:
73 case BPF_ALU
| BPF_MOV
| BPF_K
:
74 case BPF_LD
| BPF_IMM
| BPF_DW
:
85 switch (BPF_CLASS (c
))
97 is_binary(opcode code
)
99 if (BPF_CLASS (code
) != BPF_ALU64
)
101 switch (BPF_OP (code
))
121 is_commutative(opcode code
)
123 if (BPF_CLASS (code
) != BPF_ALU64
)
125 switch (BPF_OP (code
))
138 /* Various functions for eBPF helper lookup: */
140 std::map
<unsigned, const char *> bpf_func_name_map
;
141 std::map
<std::string
, bpf_func_id
> bpf_func_id_map
;
143 /* PR23829: On older kernels, bpf.h does not define __BPF_FUNC_MAPPER.
144 As a fallback, use the *earliest* __BPF_FUNC_MAPPER, so stapbpf
145 will not try helpers that only exist on subsequent kernels.
147 TODO: This isn't perfect since even older kernels don't have
148 some of these helpers.
150 XXX: Note the build limitation in that SystemTap must be compiled
151 against a recent kernel to be able to use the helpers from that
152 kernel. That's also the case when building against recent bpf.h
153 with __BPF_FUNC_MAPPER, so this workaround is not the source of the
155 #ifndef __BPF_FUNC_MAPPER
156 #define __BPF_FUNC_MAPPER(FN) \
158 FN(map_lookup_elem), \
159 FN(map_update_elem), \
160 FN(map_delete_elem), \
164 FN(get_prandom_u32), \
165 FN(get_smp_processor_id), \
166 FN(skb_store_bytes), \
167 FN(l3_csum_replace), \
168 FN(l4_csum_replace), \
170 FN(clone_redirect), \
171 FN(get_current_pid_tgid), \
172 FN(get_current_uid_gid), \
173 FN(get_current_comm), \
174 FN(get_cgroup_classid), \
177 FN(skb_get_tunnel_key), \
178 FN(skb_set_tunnel_key), \
179 FN(perf_event_read), \
181 FN(get_route_realm), \
182 FN(perf_event_output), \
183 FN(skb_load_bytes), \
186 FN(skb_get_tunnel_opt), \
187 FN(skb_set_tunnel_opt), \
188 FN(skb_change_proto), \
189 FN(skb_change_type), \
190 FN(skb_under_cgroup), \
191 FN(get_hash_recalc), \
192 FN(get_current_task), \
193 FN(probe_write_user), \
194 FN(current_task_under_cgroup), \
195 FN(skb_change_tail), \
198 FN(set_hash_invalid), \
203 init_bpf_helper_tables ()
205 #define __BPF_SET_FUNC_NAME(x) bpf_func_name_map[BPF_FUNC_ ## x] = #x
206 #define __BPF_SET_FUNC_ID(x) bpf_func_id_map[#x] = BPF_FUNC_ ## x
207 __BPF_FUNC_MAPPER(__BPF_SET_FUNC_NAME
)
208 __STAPBPF_FUNC_MAPPER(__BPF_SET_FUNC_NAME
)
209 __BPF_FUNC_MAPPER(__BPF_SET_FUNC_ID
)
210 __STAPBPF_FUNC_MAPPER(__BPF_SET_FUNC_ID
)
215 bpf_function_name (unsigned id
)
217 if (bpf_func_name_map
.count(id
) != 0)
218 return bpf_func_name_map
[id
];
223 bpf_function_id (const std::string
& name
)
225 if (bpf_func_id_map
.count(name
) != 0)
226 return bpf_func_id_map
[name
];
227 return __BPF_FUNC_MAX_ID
;
231 bpf_function_nargs (unsigned id
)
233 // ??? generalize to all bpf functions
236 case BPF_FUNC_map_lookup_elem
: return 2;
237 case BPF_FUNC_map_update_elem
: return 4;
238 case BPF_FUNC_map_delete_elem
: return 2;
239 case BPF_FUNC_probe_read
: return 3;
240 case BPF_FUNC_ktime_get_ns
: return 0;
241 case BPF_FUNC_trace_printk
: return 5;
242 case BPF_FUNC_get_prandom_u32
: return 0;
243 case BPF_FUNC_get_smp_processor_id
: return 0;
244 case BPF_FUNC_get_current_pid_tgid
: return 0;
245 case BPF_FUNC_get_current_uid_gid
: return 0;
246 case BPF_FUNC_get_current_comm
: return 2;
247 case BPF_FUNC_perf_event_read
: return 2;
248 case BPF_FUNC_perf_event_output
: return 5;
255 insn::mark_sets(bitset::set1_ref
&s
, bool v
) const
259 // Return value and call-clobbered registers.
260 for (unsigned i
= BPF_REG_0
; i
<= BPF_REG_5
; ++i
)
264 s
.set(dest
->reg(), v
);
268 insn::mark_uses(bitset::set1_ref
&s
, bool v
) const
273 for (unsigned i
= 0; i
< n
; ++i
)
274 s
.set(BPF_REG_1
+ i
, v
);
276 else if (code
== (BPF_JMP
| BPF_EXIT
))
280 if (src0
&& src0
->is_reg())
281 s
.set(src0
->reg(), v
);
282 if (src1
&& src1
->is_reg())
283 s
.set(src1
->reg(), v
);
288 opcode_name(opcode op
)
294 case BPF_LDX
| BPF_MEM
| BPF_B
: opn
= "ldxb"; break;
295 case BPF_LDX
| BPF_MEM
| BPF_H
: opn
= "ldxh"; break;
296 case BPF_LDX
| BPF_MEM
| BPF_W
: opn
= "ldxw"; break;
297 case BPF_LDX
| BPF_MEM
| BPF_DW
: opn
= "ldx"; break;
299 case BPF_STX
| BPF_MEM
| BPF_B
: opn
= "stxb"; break;
300 case BPF_STX
| BPF_MEM
| BPF_H
: opn
= "stxh"; break;
301 case BPF_STX
| BPF_MEM
| BPF_W
: opn
= "stxw"; break;
302 case BPF_STX
| BPF_MEM
| BPF_DW
: opn
= "stx"; break;
304 case BPF_ST
| BPF_MEM
| BPF_B
: opn
= "stkb"; break;
305 case BPF_ST
| BPF_MEM
| BPF_H
: opn
= "stkh"; break;
306 case BPF_ST
| BPF_MEM
| BPF_W
: opn
= "stkw"; break;
307 case BPF_ST
| BPF_MEM
| BPF_DW
: opn
= "stk"; break;
309 case BPF_ALU64
| BPF_ADD
| BPF_X
: opn
= "addx"; break;
310 case BPF_ALU64
| BPF_ADD
| BPF_K
: opn
= "addk"; break;
311 case BPF_ALU64
| BPF_SUB
| BPF_X
: opn
= "subx"; break;
312 case BPF_ALU64
| BPF_SUB
| BPF_K
: opn
= "subk"; break;
313 case BPF_ALU64
| BPF_AND
| BPF_X
: opn
= "andx"; break;
314 case BPF_ALU64
| BPF_AND
| BPF_K
: opn
= "andk"; break;
315 case BPF_ALU64
| BPF_OR
| BPF_X
: opn
= "orx"; break;
316 case BPF_ALU64
| BPF_OR
| BPF_K
: opn
= "ork"; break;
317 case BPF_ALU64
| BPF_LSH
| BPF_X
: opn
= "lshx"; break;
318 case BPF_ALU64
| BPF_LSH
| BPF_K
: opn
= "lshk"; break;
319 case BPF_ALU64
| BPF_RSH
| BPF_X
: opn
= "rshx"; break;
320 case BPF_ALU64
| BPF_RSH
| BPF_K
: opn
= "rshk"; break;
321 case BPF_ALU64
| BPF_XOR
| BPF_X
: opn
= "xorx"; break;
322 case BPF_ALU64
| BPF_XOR
| BPF_K
: opn
= "xork"; break;
323 case BPF_ALU64
| BPF_MUL
| BPF_X
: opn
= "mulx"; break;
324 case BPF_ALU64
| BPF_MUL
| BPF_K
: opn
= "mulk"; break;
325 case BPF_ALU64
| BPF_MOV
| BPF_X
: opn
= "movx"; break;
326 case BPF_ALU64
| BPF_MOV
| BPF_K
: opn
= "movk"; break;
327 case BPF_ALU64
| BPF_ARSH
| BPF_X
: opn
= "arshx"; break;
328 case BPF_ALU64
| BPF_ARSH
| BPF_K
: opn
= "arshk"; break;
329 case BPF_ALU64
| BPF_DIV
| BPF_X
: opn
= "divx"; break;
330 case BPF_ALU64
| BPF_DIV
| BPF_K
: opn
= "divk"; break;
331 case BPF_ALU64
| BPF_MOD
| BPF_X
: opn
= "modx"; break;
332 case BPF_ALU64
| BPF_MOD
| BPF_K
: opn
= "modk"; break;
333 case BPF_ALU64
| BPF_NEG
: opn
= "negx"; break;
335 case BPF_ALU
| BPF_MOV
| BPF_X
: opn
= "movwx"; break;
336 case BPF_ALU
| BPF_MOV
| BPF_K
: opn
= "movwk"; break;
338 case BPF_LD
| BPF_IMM
| BPF_DW
: opn
= "movdk"; break;
339 case BPF_LD_MAP
: opn
= "movmap"; break;
341 case BPF_JMP
| BPF_CALL
: opn
= "call"; break;
342 case BPF_JMP
| BPF_CALL
| BPF_X
: opn
= "tcall"; break;
343 case BPF_JMP
| BPF_EXIT
: opn
= "exit"; break;
345 case BPF_JMP
| BPF_JA
: opn
= "jmp"; break;
346 case BPF_JMP
| BPF_JEQ
| BPF_X
: opn
= "jeqx"; break;
347 case BPF_JMP
| BPF_JEQ
| BPF_K
: opn
= "jeqk"; break;
348 case BPF_JMP
| BPF_JNE
| BPF_X
: opn
= "jnex"; break;
349 case BPF_JMP
| BPF_JNE
| BPF_K
: opn
= "jnek"; break;
350 case BPF_JMP
| BPF_JGT
| BPF_X
: opn
= "jugtx"; break;
351 case BPF_JMP
| BPF_JGT
| BPF_K
: opn
= "jugtk"; break;
352 case BPF_JMP
| BPF_JGE
| BPF_X
: opn
= "jugex"; break;
353 case BPF_JMP
| BPF_JGE
| BPF_K
: opn
= "jugek"; break;
354 case BPF_JMP
| BPF_JSGT
| BPF_X
: opn
= "jsgtx"; break;
355 case BPF_JMP
| BPF_JSGT
| BPF_K
: opn
= "jsgtk"; break;
356 case BPF_JMP
| BPF_JSGE
| BPF_X
: opn
= "jsgex"; break;
357 case BPF_JMP
| BPF_JSGE
| BPF_K
: opn
= "jsgek"; break;
358 case BPF_JMP
| BPF_JSET
| BPF_X
: opn
= "jsetx"; break;
359 case BPF_JMP
| BPF_JSET
| BPF_K
: opn
= "jsetk"; break;
362 opn
= "<BUG:unknown opcode>";
369 insn::print(std::ostream
&o
) const
373 o
<< "{" << note
<< "} ";
375 const char *opn
= opcode_name (code
);
379 case BPF_LDX
| BPF_MEM
| BPF_B
:
380 case BPF_LDX
| BPF_MEM
| BPF_H
:
381 case BPF_LDX
| BPF_MEM
| BPF_W
:
382 case BPF_LDX
| BPF_MEM
| BPF_DW
:
383 return o
<< opn
<< "\t" << *dest
385 << showpos
<< off
<< noshowpos
<< "]";
387 case BPF_STX
| BPF_MEM
| BPF_B
:
388 case BPF_STX
| BPF_MEM
| BPF_H
:
389 case BPF_STX
| BPF_MEM
| BPF_W
:
390 case BPF_STX
| BPF_MEM
| BPF_DW
:
391 case BPF_ST
| BPF_MEM
| BPF_B
:
392 case BPF_ST
| BPF_MEM
| BPF_H
:
393 case BPF_ST
| BPF_MEM
| BPF_W
:
394 case BPF_ST
| BPF_MEM
| BPF_DW
:
395 return o
<< opn
<< "\t[" << *src0
396 << showpos
<< off
<< noshowpos
399 case BPF_ALU
| BPF_MOV
| BPF_X
:
400 case BPF_ALU
| BPF_MOV
| BPF_K
:
401 case BPF_ALU64
| BPF_MOV
| BPF_X
:
402 case BPF_ALU64
| BPF_MOV
| BPF_K
:
403 case BPF_LD
| BPF_IMM
| BPF_DW
:
405 return o
<< opn
<< "\t" << *dest
<< "," << *src1
;
407 case BPF_ALU64
| BPF_NEG
:
408 return o
<< opn
<< "\t" << *dest
<< "," << *src0
;
410 case BPF_ALU64
| BPF_ADD
| BPF_X
:
411 case BPF_ALU64
| BPF_ADD
| BPF_K
:
412 case BPF_ALU64
| BPF_SUB
| BPF_X
:
413 case BPF_ALU64
| BPF_SUB
| BPF_K
:
414 case BPF_ALU64
| BPF_AND
| BPF_X
:
415 case BPF_ALU64
| BPF_AND
| BPF_K
:
416 case BPF_ALU64
| BPF_OR
| BPF_X
:
417 case BPF_ALU64
| BPF_OR
| BPF_K
:
418 case BPF_ALU64
| BPF_LSH
| BPF_X
:
419 case BPF_ALU64
| BPF_LSH
| BPF_K
:
420 case BPF_ALU64
| BPF_RSH
| BPF_X
:
421 case BPF_ALU64
| BPF_RSH
| BPF_K
:
422 case BPF_ALU64
| BPF_XOR
| BPF_X
:
423 case BPF_ALU64
| BPF_XOR
| BPF_K
:
424 case BPF_ALU64
| BPF_MUL
| BPF_X
:
425 case BPF_ALU64
| BPF_MUL
| BPF_K
:
426 case BPF_ALU64
| BPF_ARSH
| BPF_X
:
427 case BPF_ALU64
| BPF_ARSH
| BPF_K
:
428 case BPF_ALU64
| BPF_DIV
| BPF_X
:
429 case BPF_ALU64
| BPF_DIV
| BPF_K
:
430 case BPF_ALU64
| BPF_MOD
| BPF_K
:
431 case BPF_ALU64
| BPF_MOD
| BPF_X
:
432 return o
<< opn
<< "\t" << *dest
<< "," << *src0
<< "," << *src1
;
434 case BPF_JMP
| BPF_CALL
:
435 case BPF_JMP
| BPF_CALL
| BPF_X
:
437 if (const char *name
= bpf_function_name(src1
->imm()))
441 return o
<< "," << off
;
443 case BPF_JMP
| BPF_EXIT
:
444 case BPF_JMP
| BPF_JA
:
447 case BPF_JMP
| BPF_JEQ
| BPF_X
:
448 case BPF_JMP
| BPF_JEQ
| BPF_K
:
449 case BPF_JMP
| BPF_JNE
| BPF_X
:
450 case BPF_JMP
| BPF_JNE
| BPF_K
:
451 case BPF_JMP
| BPF_JGT
| BPF_X
:
452 case BPF_JMP
| BPF_JGT
| BPF_K
:
453 case BPF_JMP
| BPF_JGE
| BPF_X
:
454 case BPF_JMP
| BPF_JGE
| BPF_K
:
455 case BPF_JMP
| BPF_JSGT
| BPF_X
:
456 case BPF_JMP
| BPF_JSGT
| BPF_K
:
457 case BPF_JMP
| BPF_JSGE
| BPF_X
:
458 case BPF_JMP
| BPF_JSGE
| BPF_K
:
459 case BPF_JMP
| BPF_JSET
| BPF_X
:
460 case BPF_JMP
| BPF_JSET
| BPF_K
:
461 return o
<< opn
<< "\t" << *src0
<< "," << *src1
;
464 return o
<< "<BUG:unknown instruction format>";
468 edge::edge(block
*p
, block
*n
)
471 n
->prevs
.insert (this);
476 next
->prevs
.erase (this);
477 if (prev
->taken
== this)
479 if (prev
->fallthru
== this)
480 prev
->fallthru
= NULL
;
484 edge::redirect_next(block
*n
)
486 next
->prevs
.erase (this);
488 n
->prevs
.insert (this);
492 : first(NULL
), last(NULL
), taken(NULL
), fallthru(NULL
), id(i
)
497 for (insn
*n
, *i
= first
; i
; i
= n
)
507 block::is_forwarder() const
512 return fallthru
->next
;
514 else if (first
== last
&& first
->code
== (BPF_JMP
| BPF_JA
))
520 block::print(ostream
&o
) const
523 o
<< "\t[prevs: entry]\n";
527 for (edge_set::const_iterator i
= prevs
.begin(); i
!= prevs
.end(); ++i
)
528 o
<< ' ' << (*i
)->prev
->id
;
532 o
<< id
<< ':' << endl
;
533 for (insn
*i
= first
; i
!= NULL
; i
= i
->next
)
534 o
<< '\t' << *i
<< endl
;
537 o
<< "\t[taken: " << taken
->next
->id
<< "]" << endl
;
539 o
<< "\t[fallthru: " << fallthru
->next
->id
<< "]" << endl
;
541 o
<< "\t[end]" << endl
;
545 insn_inserter::new_insn()
550 n
->note
= notes
.top();
559 insn_before_inserter::insert(insn
*n
)
573 insn_after_inserter::insert(insn
*p
)
577 assert(b
->first
== NULL
&& b
->last
== NULL
);
578 b
->first
= b
->last
= p
;
594 program::program(enum bpf_target target
)
595 : target(target
), hardreg_vals(MAX_BPF_REG
), max_tmp_space(0)
597 for (unsigned i
= 0; i
< MAX_BPF_REG
; ++i
)
598 hardreg_vals
[i
] = value::mk_hardreg(i
);
603 // XXX We need to suffer a memory leak here, as blocks / edges are
604 // tightly interlinked structures, and their dtors like to invoke
605 // functions on each other. This will need a rethink, as this is
606 // the type of problem domain where a garbage collected runtime
607 // shines, and most other languages don't.
609 for (auto i
= blocks
.begin (); i
!= blocks
.end (); ++i
)
611 for (auto i
= reg_vals
.begin (); i
!= reg_vals
.end (); ++i
)
613 for (auto i
= imm_map
.begin (); i
!= imm_map
.end (); ++i
)
615 for (auto i
= str_map
.begin (); i
!= str_map
.end (); ++i
)
621 program::new_block ()
623 block
*r
= new block(blocks
.size ());
624 blocks
.push_back (r
);
629 program::lookup_reg(regno r
)
632 return &hardreg_vals
[r
];
634 return reg_vals
[r
- MAX_BPF_REG
];
641 value
*v
= new value(value::mk_reg(r
));
642 reg_vals
.push_back(v
);
647 program::new_imm(int64_t i
)
649 auto old
= imm_map
.find(i
);
650 if (old
!= imm_map
.end())
653 value
*v
= new value(value::mk_imm(i
));
654 auto ok
= imm_map
.insert(std::pair
<int64_t, value
*>(i
, v
));
660 program::new_str(std::string str
, bool format_str
)
662 std::unordered_map
<std::string
, value
*>& m
= str_map
;
663 if (format_str
) m
= format_map
;
665 auto old
= m
.find(str
);
669 value
*v
= new value(value::mk_str(str
, format_str
));
670 auto ok
= m
.insert(std::pair
<std::string
, value
*>(str
, v
));
676 program::mk_ld(insn_inserter
&ins
, int sz
, value
*dest
, value
*base
, int off
)
678 insn
*i
= ins
.new_insn();
679 i
->code
= BPF_LDX
| BPF_MEM
| sz
;
686 program::mk_st(insn_inserter
&ins
, int sz
, value
*base
, int off
, value
*src
)
688 insn
*i
= ins
.new_insn();
689 i
->code
= (src
->is_imm() ? BPF_ST
: BPF_STX
) | BPF_MEM
| sz
;
696 program::mk_binary(insn_inserter
&ins
, opcode op
, value
*dest
,
697 value
*s0
, value
*s1
)
701 if (s0
->is_imm() && s0
->imm() == 0)
703 mk_unary(ins
, BPF_NEG
, dest
, s1
);
707 else if (is_commutative(op
)
708 && ((s1
->is_reg() && !s0
->is_reg()) || dest
== s1
))
711 insn
*i
= ins
.new_insn();
712 i
->code
= BPF_ALU64
| op
| (s1
->is_imm() ? BPF_K
: BPF_X
);
719 program::mk_unary(insn_inserter
&ins
, opcode op
, value
*dest
, value
*src
)
721 assert (op
== BPF_NEG
); // XXX: BPF_NEG is the only unary operator so far.
723 if (dest
!= src
) // src is not used for BPF_NEG. BPF negates in-place.
724 mk_mov(ins
, dest
, src
);
726 insn
*i
= ins
.new_insn();
727 i
->code
= BPF_ALU64
| op
; // BPF_X is not used for BPF_NEG.
729 i
->src0
= dest
; // XXX: dest as an ersatz 'source'.
733 program::mk_mov(insn_inserter
&ins
, value
*dest
, value
*src
)
738 opcode code
= BPF_ALU64
| BPF_MOV
| BPF_X
;
741 int64_t i
= src
->imm();
743 code
= BPF_ALU64
| BPF_MOV
| BPF_K
;
744 else if (i
== (uint32_t)i
)
745 code
= BPF_ALU
| BPF_MOV
| BPF_K
;
747 code
= BPF_LD
| BPF_IMM
| BPF_DW
;
750 insn
*i
= ins
.new_insn();
757 program::mk_jmp(insn_inserter
&ins
, block
*dest
)
759 insn
*i
= ins
.new_insn();
760 i
->code
= BPF_JMP
| BPF_JA
;
762 block
*b
= ins
.get_block();
763 b
->taken
= new edge(b
, dest
);
767 program::mk_call(insn_inserter
&ins
, enum bpf_func_id id
, unsigned nargs
)
769 insn
*i
= ins
.new_insn();
770 i
->code
= BPF_JMP
| BPF_CALL
;
771 i
->src1
= new_imm((int)id
);
776 program::mk_exit(insn_inserter
&ins
)
778 insn
*i
= ins
.new_insn();
779 i
->code
= BPF_JMP
| BPF_EXIT
;
783 program::mk_jcond(insn_inserter
&ins
, condition c
, value
*s0
, value
*s1
,
789 if (s1
->is_reg() && !s0
->is_reg())
797 case LT
: c
= GT
; break;
798 case LE
: c
= GE
; break;
799 case GT
: c
= LT
; break;
800 case GE
: c
= LE
; break;
801 case LTU
: c
= GTU
; break;
802 case LEU
: c
= GEU
; break;
803 case GTU
: c
= LTU
; break;
804 case GEU
: c
= LEU
; break;
851 block
*b
= ins
.get_block();
852 b
->taken
= new edge(b
, t
);
853 b
->fallthru
= new edge(b
, f
);
855 insn
*i
= ins
.new_insn();
856 i
->code
= BPF_JMP
| code
| (s1
->is_imm() ? BPF_K
: BPF_X
);
862 program::load_map(insn_inserter
&ins
, value
*dest
, int src
)
864 assert (src
>= 0); // PR23476: Ensure a stray stats reference doesn't slip through.
865 insn
*i
= ins
.new_insn();
866 i
->code
= BPF_LD_MAP
;
868 i
->src1
= new_imm(src
);
872 program::print(ostream
&o
) const
874 for (unsigned n
= blocks
.size(), i
= 0; i
< n
; ++i
)
876 block
*b
= blocks
[i
];