Branch data Line data Source code
1 : : /* Populate process Dwfl_Frame from perf_events sample.
2 : :
3 : : Copyright (C) 2025-2026 Red Hat, Inc.
4 : : This file is part of elfutils.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <stdlib.h>
35 : : #include <assert.h>
36 : :
37 : : #include <libeblP.h>
38 : :
39 : : bool
40 : 0 : ebl_sample_sp_pc (Ebl *ebl,
41 : : const Dwarf_Word *regs, uint32_t n_regs,
42 : : const int *regs_mapping, size_t n_regs_mapping,
43 : : Dwarf_Word *sp, Dwarf_Word *pc)
44 : : {
45 [ # # ]: 0 : assert (ebl->sample_sp_pc != NULL);
46 : 0 : return ebl->sample_sp_pc (regs, n_regs,
47 : : regs_mapping, n_regs_mapping,
48 : : sp, pc);
49 : : }
50 : :
51 : : bool
52 : 0 : ebl_set_initial_registers_sample (Ebl *ebl,
53 : : const Dwarf_Word *regs, uint32_t n_regs,
54 : : const int *regs_mapping, size_t n_regs_mapping,
55 : : ebl_tid_registers_t *setfunc,
56 : : void *arg)
57 : : {
58 : : /* If set_initial_registers_sample is defined for this arch, use it. */
59 [ # # ]: 0 : if (ebl->set_initial_registers_sample != NULL)
60 : 0 : return ebl->set_initial_registers_sample (regs, n_regs,
61 : : regs_mapping, n_regs_mapping,
62 : : setfunc, arg);
63 : :
64 : : /* If perf_frame_regs_mask is zero, then the sample_regs
65 : : functionality is unsupported by this Ebl: */
66 [ # # ]: 0 : if (ebl->perf_frame_regs_mask == 0)
67 : : return false;
68 : :
69 : : /* If set_initial_registers_sample is unspecified, and
70 : : perf_frame_regs_mask is nonzero, then it is safe to use the
71 : : following generic code to populate a contiguous small array of
72 : : dwarf_regs: */
73 : 0 : Dwarf_Word dwarf_regs[64];
74 : : /* An Ebl that fails this assert is missing a custom
75 : : set_initial_registers_sample implementation: */
76 [ # # ]: 0 : assert (ebl->frame_nregs < 64);
77 : : size_t i;
78 [ # # ]: 0 : for (i = 0; i < ebl->frame_nregs; i++)
79 : 0 : dwarf_regs[i] = 0x0;
80 [ # # ]: 0 : for (i = 0; i < n_regs; i++)
81 : : {
82 [ # # ]: 0 : if (i >= n_regs_mapping)
83 : : break;
84 [ # # # # ]: 0 : if (regs_mapping[i] < 0 || regs_mapping[i] >= (int)ebl->frame_nregs)
85 : 0 : continue;
86 : 0 : dwarf_regs[regs_mapping[i]] = regs[i];
87 : : }
88 : 0 : return setfunc (0, ebl->frame_nregs, dwarf_regs, arg);
89 : : }
90 : :
91 : : bool
92 : 0 : ebl_sample_perf_regs_mapping (Ebl *ebl,
93 : : uint64_t perf_regs_mask, uint32_t abi,
94 : : const int **regs_mapping, size_t *n_regs_mapping)
95 : : {
96 : : /* If sample_perf_regs_mapping is unsupported then perf_frame_regs_mask is zero. */
97 [ # # ]: 0 : if (ebl->perf_frame_regs_mask == 0)
98 : : return false;
99 : :
100 : : /* If sample_perf_regs_mapping is defined for this arch, use it. */
101 [ # # ]: 0 : if (ebl->sample_perf_regs_mapping != NULL)
102 : 0 : return ebl->sample_perf_regs_mapping (ebl, perf_regs_mask, abi,
103 : : regs_mapping, n_regs_mapping);
104 : :
105 : : /* If sample_perf_regs_mapping is unspecified, then it is safe
106 : : to return a linear 1:1 mapping between perf_regs and dwarf_regs. */
107 : :
108 [ # # ]: 0 : if (ebl->cached_perf_regs_mask != 0
109 [ # # ]: 0 : && ebl->cached_perf_regs_mask == perf_regs_mask)
110 : : {
111 : 0 : *regs_mapping = ebl->cached_regs_mapping;
112 : 0 : *n_regs_mapping = ebl->cached_n_regs_mapping;
113 : 0 : return true;
114 : : }
115 : :
116 : : /* XXX Unwind-relevant register file should be no bigger than this: */
117 : 0 : int count = 64;
118 : :
119 [ # # ]: 0 : if (ebl->cached_regs_mapping != NULL)
120 : 0 : free (ebl->cached_regs_mapping);
121 : 0 : ebl->cached_regs_mapping = (int *)calloc (count, sizeof(int));
122 [ # # ]: 0 : if (ebl->cached_regs_mapping == NULL)
123 : : return false;
124 : 0 : ebl->cached_perf_regs_mask = perf_regs_mask;
125 : 0 : ebl->cached_n_regs_mapping = count;
126 : :
127 : 0 : int j, k; uint64_t bit;
128 : 0 : for (j = 0, k = 0, bit = 1;
129 [ # # ]: 0 : k < count; k++, bit <<= 1)
130 : : {
131 : 0 : ebl->cached_regs_mapping[k] = -1;
132 [ # # ]: 0 : if ((bit & perf_regs_mask)) {
133 : 0 : ebl->cached_regs_mapping[j] = k;
134 : 0 : j++;
135 : : }
136 : : }
137 : :
138 : 0 : *regs_mapping = ebl->cached_regs_mapping;
139 : 0 : *n_regs_mapping = ebl->cached_n_regs_mapping;
140 : 0 : return true;
141 : :
142 : : }
143 : :
144 : : uint64_t
145 : 8 : ebl_perf_frame_regs_mask (Ebl *ebl)
146 : : {
147 : : /* ebl is declared NN */
148 : 8 : return ebl->perf_frame_regs_mask;
149 : : }
|