• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../perf.h"
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <linux/kernel.h>
8 #include "session.h"
9 #include "thread.h"
10 #include "thread-stack.h"
11 #include "util.h"
12 #include "debug.h"
13 #include "namespaces.h"
14 #include "comm.h"
15 #include "unwind.h"
16 
17 #include <api/fs/fs.h>
18 
thread__init_map_groups(struct thread * thread,struct machine * machine)19 int thread__init_map_groups(struct thread *thread, struct machine *machine)
20 {
21 	pid_t pid = thread->pid_;
22 
23 	if (pid == thread->tid || pid == -1) {
24 		thread->mg = map_groups__new(machine);
25 	} else {
26 		struct thread *leader = __machine__findnew_thread(machine, pid, pid);
27 		if (leader) {
28 			thread->mg = map_groups__get(leader->mg);
29 			thread__put(leader);
30 		}
31 	}
32 
33 	return thread->mg ? 0 : -1;
34 }
35 
thread__new(pid_t pid,pid_t tid)36 struct thread *thread__new(pid_t pid, pid_t tid)
37 {
38 	char *comm_str;
39 	struct comm *comm;
40 	struct thread *thread = zalloc(sizeof(*thread));
41 
42 	if (thread != NULL) {
43 		thread->pid_ = pid;
44 		thread->tid = tid;
45 		thread->ppid = -1;
46 		thread->cpu = -1;
47 		INIT_LIST_HEAD(&thread->namespaces_list);
48 		INIT_LIST_HEAD(&thread->comm_list);
49 		init_rwsem(&thread->namespaces_lock);
50 		init_rwsem(&thread->comm_lock);
51 
52 		comm_str = malloc(32);
53 		if (!comm_str)
54 			goto err_thread;
55 
56 		snprintf(comm_str, 32, ":%d", tid);
57 		comm = comm__new(comm_str, 0, false);
58 		free(comm_str);
59 		if (!comm)
60 			goto err_thread;
61 
62 		list_add(&comm->list, &thread->comm_list);
63 		refcount_set(&thread->refcnt, 1);
64 		RB_CLEAR_NODE(&thread->rb_node);
65 		/* Thread holds first ref to nsdata. */
66 		thread->nsinfo = nsinfo__new(pid);
67 	}
68 
69 	return thread;
70 
71 err_thread:
72 	free(thread);
73 	return NULL;
74 }
75 
thread__delete(struct thread * thread)76 void thread__delete(struct thread *thread)
77 {
78 	struct namespaces *namespaces, *tmp_namespaces;
79 	struct comm *comm, *tmp_comm;
80 
81 	BUG_ON(!RB_EMPTY_NODE(&thread->rb_node));
82 
83 	thread_stack__free(thread);
84 
85 	if (thread->mg) {
86 		map_groups__put(thread->mg);
87 		thread->mg = NULL;
88 	}
89 	down_write(&thread->namespaces_lock);
90 	list_for_each_entry_safe(namespaces, tmp_namespaces,
91 				 &thread->namespaces_list, list) {
92 		list_del(&namespaces->list);
93 		namespaces__free(namespaces);
94 	}
95 	up_write(&thread->namespaces_lock);
96 
97 	down_write(&thread->comm_lock);
98 	list_for_each_entry_safe(comm, tmp_comm, &thread->comm_list, list) {
99 		list_del(&comm->list);
100 		comm__free(comm);
101 	}
102 	up_write(&thread->comm_lock);
103 
104 	unwind__finish_access(thread);
105 	nsinfo__zput(thread->nsinfo);
106 
107 	exit_rwsem(&thread->namespaces_lock);
108 	exit_rwsem(&thread->comm_lock);
109 	free(thread);
110 }
111 
thread__get(struct thread * thread)112 struct thread *thread__get(struct thread *thread)
113 {
114 	if (thread)
115 		refcount_inc(&thread->refcnt);
116 	return thread;
117 }
118 
thread__put(struct thread * thread)119 void thread__put(struct thread *thread)
120 {
121 	if (thread && refcount_dec_and_test(&thread->refcnt)) {
122 		/*
123 		 * Remove it from the dead_threads list, as last reference
124 		 * is gone.
125 		 */
126 		list_del_init(&thread->node);
127 		thread__delete(thread);
128 	}
129 }
130 
__thread__namespaces(const struct thread * thread)131 static struct namespaces *__thread__namespaces(const struct thread *thread)
132 {
133 	if (list_empty(&thread->namespaces_list))
134 		return NULL;
135 
136 	return list_first_entry(&thread->namespaces_list, struct namespaces, list);
137 }
138 
thread__namespaces(const struct thread * thread)139 struct namespaces *thread__namespaces(const struct thread *thread)
140 {
141 	struct namespaces *ns;
142 
143 	down_read((struct rw_semaphore *)&thread->namespaces_lock);
144 	ns = __thread__namespaces(thread);
145 	up_read((struct rw_semaphore *)&thread->namespaces_lock);
146 
147 	return ns;
148 }
149 
__thread__set_namespaces(struct thread * thread,u64 timestamp,struct namespaces_event * event)150 static int __thread__set_namespaces(struct thread *thread, u64 timestamp,
151 				    struct namespaces_event *event)
152 {
153 	struct namespaces *new, *curr = __thread__namespaces(thread);
154 
155 	new = namespaces__new(event);
156 	if (!new)
157 		return -ENOMEM;
158 
159 	list_add(&new->list, &thread->namespaces_list);
160 
161 	if (timestamp && curr) {
162 		/*
163 		 * setns syscall must have changed few or all the namespaces
164 		 * of this thread. Update end time for the namespaces
165 		 * previously used.
166 		 */
167 		curr = list_next_entry(new, list);
168 		curr->end_time = timestamp;
169 	}
170 
171 	return 0;
172 }
173 
thread__set_namespaces(struct thread * thread,u64 timestamp,struct namespaces_event * event)174 int thread__set_namespaces(struct thread *thread, u64 timestamp,
175 			   struct namespaces_event *event)
176 {
177 	int ret;
178 
179 	down_write(&thread->namespaces_lock);
180 	ret = __thread__set_namespaces(thread, timestamp, event);
181 	up_write(&thread->namespaces_lock);
182 	return ret;
183 }
184 
thread__comm(const struct thread * thread)185 struct comm *thread__comm(const struct thread *thread)
186 {
187 	if (list_empty(&thread->comm_list))
188 		return NULL;
189 
190 	return list_first_entry(&thread->comm_list, struct comm, list);
191 }
192 
thread__exec_comm(const struct thread * thread)193 struct comm *thread__exec_comm(const struct thread *thread)
194 {
195 	struct comm *comm, *last = NULL, *second_last = NULL;
196 
197 	list_for_each_entry(comm, &thread->comm_list, list) {
198 		if (comm->exec)
199 			return comm;
200 		second_last = last;
201 		last = comm;
202 	}
203 
204 	/*
205 	 * 'last' with no start time might be the parent's comm of a synthesized
206 	 * thread (created by processing a synthesized fork event). For a main
207 	 * thread, that is very probably wrong. Prefer a later comm to avoid
208 	 * that case.
209 	 */
210 	if (second_last && !last->start && thread->pid_ == thread->tid)
211 		return second_last;
212 
213 	return last;
214 }
215 
____thread__set_comm(struct thread * thread,const char * str,u64 timestamp,bool exec)216 static int ____thread__set_comm(struct thread *thread, const char *str,
217 				u64 timestamp, bool exec)
218 {
219 	struct comm *new, *curr = thread__comm(thread);
220 
221 	/* Override the default :tid entry */
222 	if (!thread->comm_set) {
223 		int err = comm__override(curr, str, timestamp, exec);
224 		if (err)
225 			return err;
226 	} else {
227 		new = comm__new(str, timestamp, exec);
228 		if (!new)
229 			return -ENOMEM;
230 		list_add(&new->list, &thread->comm_list);
231 
232 		if (exec)
233 			unwind__flush_access(thread);
234 	}
235 
236 	thread->comm_set = true;
237 
238 	return 0;
239 }
240 
__thread__set_comm(struct thread * thread,const char * str,u64 timestamp,bool exec)241 int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
242 		       bool exec)
243 {
244 	int ret;
245 
246 	down_write(&thread->comm_lock);
247 	ret = ____thread__set_comm(thread, str, timestamp, exec);
248 	up_write(&thread->comm_lock);
249 	return ret;
250 }
251 
thread__set_comm_from_proc(struct thread * thread)252 int thread__set_comm_from_proc(struct thread *thread)
253 {
254 	char path[64];
255 	char *comm = NULL;
256 	size_t sz;
257 	int err = -1;
258 
259 	if (!(snprintf(path, sizeof(path), "%d/task/%d/comm",
260 		       thread->pid_, thread->tid) >= (int)sizeof(path)) &&
261 	    procfs__read_str(path, &comm, &sz) == 0) {
262 		comm[sz - 1] = '\0';
263 		err = thread__set_comm(thread, comm, 0);
264 	}
265 
266 	return err;
267 }
268 
__thread__comm_str(const struct thread * thread)269 static const char *__thread__comm_str(const struct thread *thread)
270 {
271 	const struct comm *comm = thread__comm(thread);
272 
273 	if (!comm)
274 		return NULL;
275 
276 	return comm__str(comm);
277 }
278 
thread__comm_str(const struct thread * thread)279 const char *thread__comm_str(const struct thread *thread)
280 {
281 	const char *str;
282 
283 	down_read((struct rw_semaphore *)&thread->comm_lock);
284 	str = __thread__comm_str(thread);
285 	up_read((struct rw_semaphore *)&thread->comm_lock);
286 
287 	return str;
288 }
289 
290 /* CHECKME: it should probably better return the max comm len from its comm list */
thread__comm_len(struct thread * thread)291 int thread__comm_len(struct thread *thread)
292 {
293 	if (!thread->comm_len) {
294 		const char *comm = thread__comm_str(thread);
295 		if (!comm)
296 			return 0;
297 		thread->comm_len = strlen(comm);
298 	}
299 
300 	return thread->comm_len;
301 }
302 
thread__fprintf(struct thread * thread,FILE * fp)303 size_t thread__fprintf(struct thread *thread, FILE *fp)
304 {
305 	return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
306 	       map_groups__fprintf(thread->mg, fp);
307 }
308 
thread__insert_map(struct thread * thread,struct map * map)309 int thread__insert_map(struct thread *thread, struct map *map)
310 {
311 	int ret;
312 
313 	ret = unwind__prepare_access(thread, map, NULL);
314 	if (ret)
315 		return ret;
316 
317 	map_groups__fixup_overlappings(thread->mg, map, stderr);
318 	map_groups__insert(thread->mg, map);
319 
320 	return 0;
321 }
322 
__thread__prepare_access(struct thread * thread)323 static int __thread__prepare_access(struct thread *thread)
324 {
325 	bool initialized = false;
326 	int err = 0;
327 	struct maps *maps = &thread->mg->maps;
328 	struct map *map;
329 
330 	down_read(&maps->lock);
331 
332 	for (map = maps__first(maps); map; map = map__next(map)) {
333 		err = unwind__prepare_access(thread, map, &initialized);
334 		if (err || initialized)
335 			break;
336 	}
337 
338 	up_read(&maps->lock);
339 
340 	return err;
341 }
342 
thread__prepare_access(struct thread * thread)343 static int thread__prepare_access(struct thread *thread)
344 {
345 	int err = 0;
346 
347 	if (symbol_conf.use_callchain)
348 		err = __thread__prepare_access(thread);
349 
350 	return err;
351 }
352 
thread__clone_map_groups(struct thread * thread,struct thread * parent)353 static int thread__clone_map_groups(struct thread *thread,
354 				    struct thread *parent)
355 {
356 	/* This is new thread, we share map groups for process. */
357 	if (thread->pid_ == parent->pid_)
358 		return thread__prepare_access(thread);
359 
360 	if (thread->mg == parent->mg) {
361 		pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
362 			 thread->pid_, thread->tid, parent->pid_, parent->tid);
363 		return 0;
364 	}
365 
366 	/* But this one is new process, copy maps. */
367 	if (map_groups__clone(thread, parent->mg) < 0)
368 		return -ENOMEM;
369 
370 	return 0;
371 }
372 
thread__fork(struct thread * thread,struct thread * parent,u64 timestamp)373 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
374 {
375 	if (parent->comm_set) {
376 		const char *comm = thread__comm_str(parent);
377 		int err;
378 		if (!comm)
379 			return -ENOMEM;
380 		err = thread__set_comm(thread, comm, timestamp);
381 		if (err)
382 			return err;
383 	}
384 
385 	thread->ppid = parent->tid;
386 	return thread__clone_map_groups(thread, parent);
387 }
388 
thread__find_cpumode_addr_location(struct thread * thread,u64 addr,struct addr_location * al)389 void thread__find_cpumode_addr_location(struct thread *thread, u64 addr,
390 					struct addr_location *al)
391 {
392 	size_t i;
393 	const u8 cpumodes[] = {
394 		PERF_RECORD_MISC_USER,
395 		PERF_RECORD_MISC_KERNEL,
396 		PERF_RECORD_MISC_GUEST_USER,
397 		PERF_RECORD_MISC_GUEST_KERNEL
398 	};
399 
400 	for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
401 		thread__find_symbol(thread, cpumodes[i], addr, al);
402 		if (al->map)
403 			break;
404 	}
405 }
406 
thread__main_thread(struct machine * machine,struct thread * thread)407 struct thread *thread__main_thread(struct machine *machine, struct thread *thread)
408 {
409 	if (thread->pid_ == thread->tid)
410 		return thread__get(thread);
411 
412 	if (thread->pid_ == -1)
413 		return NULL;
414 
415 	return machine__find_thread(machine, thread->pid_, thread->pid_);
416 }
417