[go: up one dir, main page]

File: dynamic.h

package info (click to toggle)
uftrace 0.17-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 5,264 kB
  • sloc: ansic: 49,132; python: 10,882; asm: 837; makefile: 760; cpp: 627; sh: 624; javascript: 191
file content (159 lines) | stat: -rw-r--r-- 4,325 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#ifndef UFTRACE_MCOUNT_DYNAMIC_H
#define UFTRACE_MCOUNT_DYNAMIC_H

#include <link.h>
#include <stdlib.h>

#ifdef HAVE_LIBCAPSTONE
#include <capstone/capstone.h>
#endif

#include "utils/symbol.h"

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

#define PAGE_ADDR(a) ((void *)((a) & ~(PAGE_SIZE - 1)))
#define PAGE_LEN(a, l) (a + l - (unsigned long)PAGE_ADDR(a))

#define XRAY_SECT "xray_instr_map"
#define MCOUNTLOC_SECT "__mcount_loc"
#define PATCHABLE_SECT "__patchable_function_entries"

/* target instrumentation function it needs to call */
extern void __fentry__(void);
extern void __dentry__(void);
extern void __xray_entry(void);
extern void __xray_exit(void);

struct xray_instr_map {
	uint64_t address;
	uint64_t function;
	uint8_t kind;
	uint8_t always_instrument;
	uint8_t version;
	uint8_t padding[13];
};

enum mcount_dynamic_type {
	DYNAMIC_NONE,
	DYNAMIC_PG,
	DYNAMIC_FENTRY,
	DYNAMIC_FENTRY_NOP,
	DYNAMIC_XRAY,
	DYNAMIC_PATCHABLE,
};

__maybe_unused static const char *mdi_type_names[] = {
	"none", "pg", "fentry", "fentry-nop", "xray", "fpatchable",
};

struct mcount_dynamic_info {
	struct mcount_dynamic_info *next;
	struct uftrace_mmap *map;
	unsigned long base_addr;
	unsigned long text_addr;
	int text_size;
	unsigned long trampoline;
	struct list_head bad_syms;
	enum mcount_dynamic_type type;
	void *patch_target;
	unsigned nr_patch_target;
};

struct mcount_disasm_engine {
#ifdef HAVE_LIBCAPSTONE
	csh engine;
#endif
};

#define INSTRUMENT_SUCCESS 0
#define INSTRUMENT_FAILED -1
#define INSTRUMENT_SKIPPED -2

/*
 * Supposing the size of smallest conditional branch is 2 byte.
 * We can replace, at most, 3 of them by the instrumentation
 * instruction.
 */
#define MAX_COND_BRANCH 3

int mcount_dynamic_update(struct uftrace_sym_info *sinfo, char *patch_funcs,
			  enum uftrace_pattern_type ptype);
void mcount_dynamic_dlopen(struct uftrace_sym_info *sinfo, struct dl_phdr_info *info, char *path,
			   struct uftrace_mmap *map);
void mcount_dynamic_finish(void);

struct mcount_orig_insn {
	struct rb_node node;
	unsigned long addr;
	void *orig;
	void *insn;
	int orig_size;
	int insn_size;
};

struct cond_branch_info {
	/* where the insn starts in the out-of-line exec buffer*/
	unsigned long insn_index;
	/* the original target address of the branch */
	unsigned long branch_target;
	unsigned long insn_addr;
	unsigned long insn_size;
};

/*
 * mcount_disasm_info - information for dynamic patch
 * @sym : symbol for the function
 * @addr : currently targeted function address.
 * @insns : byte array to store instruction.
 * @orig_size : size of original instructions
 * @copy_size : size of copied instructions (may be modified)
 * @modified : whether instruction is changed
 * @has_jump : whether jump_target should be added
 */
struct mcount_disasm_info {
	struct uftrace_symbol *sym;
	unsigned long addr;
	unsigned char insns[64];
	int orig_size;
	int copy_size;
	bool modified;
	bool has_jump;
	bool has_intel_cet;
	uint8_t nr_branch;
	struct cond_branch_info branch_info[MAX_COND_BRANCH];
};

void mcount_save_code(struct mcount_disasm_info *info, unsigned call_size, void *jmp_insn,
		      unsigned jmp_size);
void *mcount_find_code(unsigned long addr);
struct mcount_orig_insn *mcount_find_insn(unsigned long addr);
void mcount_freeze_code(void);

/* these should be implemented for each architecture */
int mcount_setup_trampoline(struct mcount_dynamic_info *adi);
void mcount_cleanup_trampoline(struct mcount_dynamic_info *mdi);

int mcount_patch_func(struct mcount_dynamic_info *mdi, struct uftrace_symbol *sym,
		      struct mcount_disasm_engine *disasm, unsigned min_size);

void mcount_disasm_init(struct mcount_disasm_engine *disasm);
void mcount_disasm_finish(struct mcount_disasm_engine *disasm);

int mcount_arch_branch_table_size(struct mcount_disasm_info *info);
void mcount_arch_patch_branch(struct mcount_disasm_info *info, struct mcount_orig_insn *orig);

struct dynamic_bad_symbol {
	struct list_head list;
	struct uftrace_symbol *sym;
	bool reverted;
};

struct dynamic_bad_symbol *mcount_find_badsym(struct mcount_dynamic_info *mdi, unsigned long addr);
bool mcount_add_badsym(struct mcount_dynamic_info *mdi, unsigned long callsite,
		       unsigned long target);
void mcount_free_badsym(struct mcount_dynamic_info *mdi);

#endif /* UFTRACE_MCOUNT_DYNAMIC_H */