Linux Perf
cs-etm-decoder.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright(C) 2015-2018 Linaro Limited.
4  *
5  * Author: Tor Jeremiassen <tor@ti.com>
6  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
7  */
8 
9 #include <linux/err.h>
10 #include <linux/list.h>
11 #include <stdlib.h>
12 #include <opencsd/c_api/opencsd_c_api.h>
13 #include <opencsd/etmv4/trc_pkt_types_etmv4.h>
14 #include <opencsd/ocsd_if_types.h>
15 
16 #include "cs-etm.h"
17 #include "cs-etm-decoder.h"
18 #include "intlist.h"
19 #include "util.h"
20 
21 #define MAX_BUFFER 1024
22 
23 /* use raw logging */
24 #ifdef CS_DEBUG_RAW
25 #define CS_LOG_RAW_FRAMES
26 #ifdef CS_RAW_PACKED
27 #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT | \
28  OCSD_DFRMTR_PACKED_RAW_OUT)
29 #else
30 #define CS_RAW_DEBUG_FLAGS (OCSD_DFRMTR_UNPACKED_RAW_OUT)
31 #endif
32 #endif
33 
35  void *data;
36  void (*packet_printer)(const char *msg);
37  bool trace_on;
38  dcd_tree_handle_t dcd_tree;
40  ocsd_datapath_resp_t prev_return;
42  u32 head;
43  u32 tail;
45 };
46 
47 static u32
48 cs_etm_decoder__mem_access(const void *context,
49  const ocsd_vaddr_t address,
50  const ocsd_mem_space_acc_t mem_space __maybe_unused,
51  const u32 req_size,
52  u8 *buffer)
53 {
54  struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
55 
56  return decoder->mem_access(decoder->data,
57  address,
58  req_size,
59  buffer);
60 }
61 
63  u64 start, u64 end,
64  cs_etm_mem_cb_type cb_func)
65 {
66  decoder->mem_access = cb_func;
67 
68  if (ocsd_dt_add_callback_mem_acc(decoder->dcd_tree, start, end,
69  OCSD_MEM_SPACE_ANY,
71  return -1;
72 
73  return 0;
74 }
75 
77 {
78  ocsd_datapath_resp_t dp_ret;
79 
80  decoder->prev_return = OCSD_RESP_CONT;
81 
82  dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
83  0, 0, NULL, NULL);
84  if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
85  return -1;
86 
87  return 0;
88 }
89 
91  struct cs_etm_packet *packet)
92 {
93  if (!decoder || !packet)
94  return -EINVAL;
95 
96  /* Nothing to do, might as well just return */
97  if (decoder->packet_count == 0)
98  return 0;
99  /*
100  * The queueing process in function cs_etm_decoder__buffer_packet()
101  * increments the tail *before* using it. This is somewhat counter
102  * intuitive but it has the advantage of centralizing tail management
103  * at a single location. Because of that we need to follow the same
104  * heuristic with the head, i.e we increment it before using its
105  * value. Otherwise the first element of the packet queue is not
106  * used.
107  */
108  decoder->head = (decoder->head + 1) & (MAX_BUFFER - 1);
109 
110  *packet = decoder->packet_buffer[decoder->head];
111 
112  decoder->packet_count--;
113 
114  return 1;
115 }
116 
118  ocsd_etmv4_cfg *config)
119 {
120  config->reg_configr = params->etmv4.reg_configr;
121  config->reg_traceidr = params->etmv4.reg_traceidr;
122  config->reg_idr0 = params->etmv4.reg_idr0;
123  config->reg_idr1 = params->etmv4.reg_idr1;
124  config->reg_idr2 = params->etmv4.reg_idr2;
125  config->reg_idr8 = params->etmv4.reg_idr8;
126  config->reg_idr9 = 0;
127  config->reg_idr10 = 0;
128  config->reg_idr11 = 0;
129  config->reg_idr12 = 0;
130  config->reg_idr13 = 0;
131  config->arch_ver = ARCH_V8;
132  config->core_prof = profile_CortexA;
133 }
134 
135 static void cs_etm_decoder__print_str_cb(const void *p_context,
136  const char *msg,
137  const int str_len)
138 {
139  if (p_context && str_len)
140  ((struct cs_etm_decoder *)p_context)->packet_printer(msg);
141 }
142 
143 static int
145  struct cs_etm_decoder *decoder)
146 {
147  int ret = 0;
148 
149  if (d_params->packet_printer == NULL)
150  return -1;
151 
152  decoder->packet_printer = d_params->packet_printer;
153 
154  /*
155  * Set up a library default logger to process any printers
156  * (packet/raw frame) we add later.
157  */
158  ret = ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
159  if (ret != 0)
160  return -1;
161 
162  /* no stdout / err / file output */
163  ret = ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
164  if (ret != 0)
165  return -1;
166 
167  /*
168  * Set the string CB for the default logger, passes strings to
169  * perf print logger.
170  */
171  ret = ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
172  (void *)decoder,
174  if (ret != 0)
175  ret = -1;
176 
177  return 0;
178 }
179 
180 #ifdef CS_LOG_RAW_FRAMES
181 static void
183  struct cs_etm_decoder *decoder)
184 {
185  /* Only log these during a --dump operation */
186  if (d_params->operation == CS_ETM_OPERATION_PRINT) {
187  /* set up a library default logger to process the
188  * raw frame printer we add later
189  */
190  ocsd_def_errlog_init(OCSD_ERR_SEV_ERROR, 1);
191 
192  /* no stdout / err / file output */
193  ocsd_def_errlog_config_output(C_API_MSGLOGOUT_FLG_NONE, NULL);
194 
195  /* set the string CB for the default logger,
196  * passes strings to perf print logger.
197  */
198  ocsd_def_errlog_set_strprint_cb(decoder->dcd_tree,
199  (void *)decoder,
201 
202  /* use the built in library printer for the raw frames */
203  ocsd_dt_set_raw_frame_printer(decoder->dcd_tree,
204  CS_RAW_DEBUG_FLAGS);
205  }
206 }
207 #else
208 static void
210  struct cs_etm_decoder_params *d_params __maybe_unused,
211  struct cs_etm_decoder *decoder __maybe_unused)
212 {
213 }
214 #endif
215 
217  const char *decoder_name,
218  void *trace_config)
219 {
220  u8 csid;
221 
222  if (ocsd_dt_create_decoder(decoder->dcd_tree, decoder_name,
223  OCSD_CREATE_FLG_PACKET_PROC,
224  trace_config, &csid))
225  return -1;
226 
227  if (ocsd_dt_set_pkt_protocol_printer(decoder->dcd_tree, csid, 0))
228  return -1;
229 
230  return 0;
231 }
232 
233 static int
235  struct cs_etm_decoder *decoder)
236 {
237  const char *decoder_name;
238  ocsd_etmv4_cfg trace_config_etmv4;
239  void *trace_config;
240 
241  switch (t_params->protocol) {
242  case CS_ETM_PROTO_ETMV4i:
243  cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
244  decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
245  trace_config = &trace_config_etmv4;
246  break;
247  default:
248  return -1;
249  }
250 
252  decoder_name,
253  trace_config);
254 }
255 
256 static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
257 {
258  int i;
259 
260  decoder->head = 0;
261  decoder->tail = 0;
262  decoder->packet_count = 0;
263  for (i = 0; i < MAX_BUFFER; i++) {
264  decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL;
265  decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
266  decoder->packet_buffer[i].last_instr_taken_branch = false;
267  decoder->packet_buffer[i].exc = false;
268  decoder->packet_buffer[i].exc_ret = false;
269  decoder->packet_buffer[i].cpu = INT_MIN;
270  }
271 }
272 
273 static ocsd_datapath_resp_t
275  const u8 trace_chan_id,
276  enum cs_etm_sample_type sample_type)
277 {
278  u32 et = 0;
279  struct int_node *inode = NULL;
280 
281  if (decoder->packet_count >= MAX_BUFFER - 1)
282  return OCSD_RESP_FATAL_SYS_ERR;
283 
284  /* Search the RB tree for the cpu associated with this traceID */
285  inode = intlist__find(traceid_list, trace_chan_id);
286  if (!inode)
287  return OCSD_RESP_FATAL_SYS_ERR;
288 
289  et = decoder->tail;
290  et = (et + 1) & (MAX_BUFFER - 1);
291  decoder->tail = et;
292  decoder->packet_count++;
293 
294  decoder->packet_buffer[et].sample_type = sample_type;
295  decoder->packet_buffer[et].exc = false;
296  decoder->packet_buffer[et].exc_ret = false;
297  decoder->packet_buffer[et].cpu = *((int *)inode->priv);
298  decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL;
299  decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL;
300 
301  if (decoder->packet_count == MAX_BUFFER - 1)
302  return OCSD_RESP_WAIT;
303 
304  return OCSD_RESP_CONT;
305 }
306 
307 static ocsd_datapath_resp_t
309  const ocsd_generic_trace_elem *elem,
310  const uint8_t trace_chan_id)
311 {
312  int ret = 0;
313  struct cs_etm_packet *packet;
314 
315  ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
316  CS_ETM_RANGE);
317  if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
318  return ret;
319 
320  packet = &decoder->packet_buffer[decoder->tail];
321 
322  packet->start_addr = elem->st_addr;
323  packet->end_addr = elem->en_addr;
324  switch (elem->last_i_type) {
325  case OCSD_INSTR_BR:
326  case OCSD_INSTR_BR_INDIRECT:
327  packet->last_instr_taken_branch = elem->last_instr_exec;
328  break;
329  case OCSD_INSTR_ISB:
330  case OCSD_INSTR_DSB_DMB:
331  case OCSD_INSTR_OTHER:
332  default:
333  packet->last_instr_taken_branch = false;
334  break;
335  }
336 
337  return ret;
338 }
339 
340 static ocsd_datapath_resp_t
342  const uint8_t trace_chan_id)
343 {
344  return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
346 }
347 
348 static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
349  const void *context,
350  const ocsd_trc_index_t indx __maybe_unused,
351  const u8 trace_chan_id __maybe_unused,
352  const ocsd_generic_trace_elem *elem)
353 {
354  ocsd_datapath_resp_t resp = OCSD_RESP_CONT;
355  struct cs_etm_decoder *decoder = (struct cs_etm_decoder *) context;
356 
357  switch (elem->elem_type) {
358  case OCSD_GEN_TRC_ELEM_UNKNOWN:
359  break;
360  case OCSD_GEN_TRC_ELEM_NO_SYNC:
361  decoder->trace_on = false;
362  break;
363  case OCSD_GEN_TRC_ELEM_TRACE_ON:
364  resp = cs_etm_decoder__buffer_trace_on(decoder,
365  trace_chan_id);
366  decoder->trace_on = true;
367  break;
368  case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
369  resp = cs_etm_decoder__buffer_range(decoder, elem,
370  trace_chan_id);
371  break;
372  case OCSD_GEN_TRC_ELEM_EXCEPTION:
373  decoder->packet_buffer[decoder->tail].exc = true;
374  break;
375  case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
376  decoder->packet_buffer[decoder->tail].exc_ret = true;
377  break;
378  case OCSD_GEN_TRC_ELEM_PE_CONTEXT:
379  case OCSD_GEN_TRC_ELEM_EO_TRACE:
380  case OCSD_GEN_TRC_ELEM_ADDR_NACC:
381  case OCSD_GEN_TRC_ELEM_TIMESTAMP:
382  case OCSD_GEN_TRC_ELEM_CYCLE_COUNT:
383  case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN:
384  case OCSD_GEN_TRC_ELEM_EVENT:
385  case OCSD_GEN_TRC_ELEM_SWTRACE:
386  case OCSD_GEN_TRC_ELEM_CUSTOM:
387  default:
388  break;
389  }
390 
391  return resp;
392 }
393 
395  struct cs_etm_trace_params *t_params,
396  struct cs_etm_decoder *decoder)
397 {
398  const char *decoder_name;
399  ocsd_etmv4_cfg trace_config_etmv4;
400  void *trace_config;
401  u8 csid;
402 
403  switch (t_params->protocol) {
404  case CS_ETM_PROTO_ETMV4i:
405  cs_etm_decoder__gen_etmv4_config(t_params, &trace_config_etmv4);
406  decoder_name = OCSD_BUILTIN_DCD_ETMV4I;
407  trace_config = &trace_config_etmv4;
408  break;
409  default:
410  return -1;
411  }
412 
413  if (ocsd_dt_create_decoder(decoder->dcd_tree,
414  decoder_name,
415  OCSD_CREATE_FLG_FULL_DECODER,
416  trace_config, &csid))
417  return -1;
418 
419  if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree,
421  decoder))
422  return -1;
423 
424  return 0;
425 }
426 
427 static int
429  struct cs_etm_trace_params *t_params,
430  struct cs_etm_decoder *decoder)
431 {
432  if (d_params->operation == CS_ETM_OPERATION_PRINT)
434  decoder);
435  else if (d_params->operation == CS_ETM_OPERATION_DECODE)
437  decoder);
438 
439  return -1;
440 }
441 
442 struct cs_etm_decoder *
443 cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params,
444  struct cs_etm_trace_params t_params[])
445 {
446  struct cs_etm_decoder *decoder;
447  ocsd_dcd_tree_src_t format;
448  u32 flags;
449  int i, ret;
450 
451  if ((!t_params) || (!d_params))
452  return NULL;
453 
454  decoder = zalloc(sizeof(*decoder));
455 
456  if (!decoder)
457  return NULL;
458 
459  decoder->data = d_params->data;
460  decoder->prev_return = OCSD_RESP_CONT;
462  format = (d_params->formatted ? OCSD_TRC_SRC_FRAME_FORMATTED :
463  OCSD_TRC_SRC_SINGLE);
464  flags = 0;
465  flags |= (d_params->fsyncs ? OCSD_DFRMTR_HAS_FSYNCS : 0);
466  flags |= (d_params->hsyncs ? OCSD_DFRMTR_HAS_HSYNCS : 0);
467  flags |= (d_params->frame_aligned ? OCSD_DFRMTR_FRAME_MEM_ALIGN : 0);
468 
469  /*
470  * Drivers may add barrier frames when used with perf, set up to
471  * handle this. Barriers const of FSYNC packet repeated 4 times.
472  */
473  flags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC;
474 
475  /* Create decode tree for the data source */
476  decoder->dcd_tree = ocsd_create_dcd_tree(format, flags);
477 
478  if (decoder->dcd_tree == 0)
479  goto err_free_decoder;
480 
481  /* init library print logging support */
482  ret = cs_etm_decoder__init_def_logger_printing(d_params, decoder);
483  if (ret != 0)
484  goto err_free_decoder_tree;
485 
486  /* init raw frame logging if required */
487  cs_etm_decoder__init_raw_frame_logging(d_params, decoder);
488 
489  for (i = 0; i < num_cpu; i++) {
490  ret = cs_etm_decoder__create_etm_decoder(d_params,
491  &t_params[i],
492  decoder);
493  if (ret != 0)
494  goto err_free_decoder_tree;
495  }
496 
497  return decoder;
498 
499 err_free_decoder_tree:
500  ocsd_destroy_dcd_tree(decoder->dcd_tree);
501 err_free_decoder:
502  free(decoder);
503  return NULL;
504 }
505 
507  u64 indx, const u8 *buf,
508  size_t len, size_t *consumed)
509 {
510  int ret = 0;
511  ocsd_datapath_resp_t cur = OCSD_RESP_CONT;
512  ocsd_datapath_resp_t prev_return = decoder->prev_return;
513  size_t processed = 0;
514  u32 count;
515 
516  while (processed < len) {
517  if (OCSD_DATA_RESP_IS_WAIT(prev_return)) {
518  cur = ocsd_dt_process_data(decoder->dcd_tree,
519  OCSD_OP_FLUSH,
520  0,
521  0,
522  NULL,
523  NULL);
524  } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) {
525  cur = ocsd_dt_process_data(decoder->dcd_tree,
526  OCSD_OP_DATA,
527  indx + processed,
528  len - processed,
529  &buf[processed],
530  &count);
531  processed += count;
532  } else {
533  ret = -EINVAL;
534  break;
535  }
536 
537  /*
538  * Return to the input code if the packet buffer is full.
539  * Flushing will get done once the packet buffer has been
540  * processed.
541  */
542  if (OCSD_DATA_RESP_IS_WAIT(cur))
543  break;
544 
545  prev_return = cur;
546  }
547 
548  decoder->prev_return = cur;
549  *consumed = processed;
550 
551  return ret;
552 }
553 
555 {
556  if (!decoder)
557  return;
558 
559  ocsd_destroy_dcd_tree(decoder->dcd_tree);
560  decoder->dcd_tree = NULL;
561  free(decoder);
562 }
static void cs_etm_decoder__gen_etmv4_config(struct cs_etm_trace_params *params, ocsd_etmv4_cfg *config)
void(* packet_printer)(const char *msg)
void * priv
Definition: intlist.h:13
struct cs_etm_packet packet_buffer[MAX_BUFFER]
#define MAX_BUFFER
void(* packet_printer)(const char *msg)
ocsd_datapath_resp_t prev_return
static int cs_etm_decoder__create_etm_decoder(struct cs_etm_decoder_params *d_params, struct cs_etm_trace_params *t_params, struct cs_etm_decoder *decoder)
u32(* cs_etm_mem_cb_type)(struct cs_etm_queue *, u64, size_t, u8 *)
#define config
static ocsd_datapath_resp_t cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, const u8 trace_chan_id, enum cs_etm_sample_type sample_type)
enum cs_etm_sample_type sample_type
static void cs_etm_decoder__init_raw_frame_logging(struct cs_etm_decoder_params *d_params __maybe_unused, struct cs_etm_decoder *decoder __maybe_unused)
static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(const void *context, const ocsd_trc_index_t indx __maybe_unused, const u8 trace_chan_id __maybe_unused, const ocsd_generic_trace_elem *elem)
struct cs_etmv4_trace_params etmv4
cs_etm_mem_cb_type mem_access
struct int_node * intlist__find(struct intlist *ilist, int i)
Definition: intlist.c:81
static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
int cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder, u64 start, u64 end, cs_etm_mem_cb_type cb_func)
u8 last_instr_taken_branch
struct cs_etm_decoder * cs_etm_decoder__new(int num_cpu, struct cs_etm_decoder_params *d_params, struct cs_etm_trace_params t_params[])
static ocsd_datapath_resp_t cs_etm_decoder__buffer_trace_on(struct cs_etm_decoder *decoder, const uint8_t trace_chan_id)
static int cs_etm_decoder__create_packet_printer(struct cs_etm_decoder *decoder, const char *decoder_name, void *trace_config)
int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder, u64 indx, const u8 *buf, size_t len, size_t *consumed)
static int cs_etm_decoder__create_etm_packet_printer(struct cs_etm_trace_params *t_params, struct cs_etm_decoder *decoder)
u64 start
Definition: hists_common.c:25
static int cs_etm_decoder__init_def_logger_printing(struct cs_etm_decoder_params *d_params, struct cs_etm_decoder *decoder)
u32 flags
Definition: numa.c:71
static int cs_etm_decoder__create_etm_packet_decoder(struct cs_etm_trace_params *t_params, struct cs_etm_decoder *decoder)
void free(void *)
dcd_tree_handle_t dcd_tree
struct intlist * traceid_list
Definition: cs-etm.h:57
static void cs_etm_decoder__print_str_cb(const void *p_context, const char *msg, const int str_len)
static ocsd_datapath_resp_t cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder, const ocsd_generic_trace_elem *elem, const uint8_t trace_chan_id)
void cs_etm_decoder__free(struct cs_etm_decoder *decoder)
int cs_etm_decoder__get_packet(struct cs_etm_decoder *decoder, struct cs_etm_packet *packet)
cs_etm_sample_type
static u32 cs_etm_decoder__mem_access(const void *context, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space __maybe_unused, const u32 req_size, u8 *buffer)
void static void * zalloc(size_t size)
Definition: util.h:20