@@ -102,12 +102,24 @@ static void cs_etm__free_events(struct perf_session *session)
102
102
103
103
static void cs_etm__free (struct perf_session * session )
104
104
{
105
+ int i ;
106
+ struct int_node * inode , * tmp ;
105
107
struct cs_etm_auxtrace * aux = container_of (session -> auxtrace ,
106
108
struct cs_etm_auxtrace ,
107
109
auxtrace );
108
110
cs_etm__free_events (session );
109
111
session -> auxtrace = NULL ;
110
112
113
+ /* First remove all traceID/CPU# nodes for the RB tree */
114
+ intlist__for_each_entry_safe (inode , tmp , traceid_list )
115
+ intlist__remove (traceid_list , inode );
116
+ /* Then the RB tree itself */
117
+ intlist__delete (traceid_list );
118
+
119
+ for (i = 0 ; i < aux -> num_cpu ; i ++ )
120
+ zfree (& aux -> metadata [i ]);
121
+
122
+ zfree (& aux -> metadata );
111
123
zfree (& aux );
112
124
}
113
125
@@ -151,15 +163,69 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
151
163
return timeless_decoding ;
152
164
}
153
165
166
+ static const char * const cs_etm_global_header_fmts [] = {
167
+ [CS_HEADER_VERSION_0 ] = " Header version %llx\n" ,
168
+ [CS_PMU_TYPE_CPUS ] = " PMU type/num cpus %llx\n" ,
169
+ [CS_ETM_SNAPSHOT ] = " Snapshot %llx\n" ,
170
+ };
171
+
172
+ static const char * const cs_etm_priv_fmts [] = {
173
+ [CS_ETM_MAGIC ] = " Magic number %llx\n" ,
174
+ [CS_ETM_CPU ] = " CPU %lld\n" ,
175
+ [CS_ETM_ETMCR ] = " ETMCR %llx\n" ,
176
+ [CS_ETM_ETMTRACEIDR ] = " ETMTRACEIDR %llx\n" ,
177
+ [CS_ETM_ETMCCER ] = " ETMCCER %llx\n" ,
178
+ [CS_ETM_ETMIDR ] = " ETMIDR %llx\n" ,
179
+ };
180
+
181
+ static const char * const cs_etmv4_priv_fmts [] = {
182
+ [CS_ETM_MAGIC ] = " Magic number %llx\n" ,
183
+ [CS_ETM_CPU ] = " CPU %lld\n" ,
184
+ [CS_ETMV4_TRCCONFIGR ] = " TRCCONFIGR %llx\n" ,
185
+ [CS_ETMV4_TRCTRACEIDR ] = " TRCTRACEIDR %llx\n" ,
186
+ [CS_ETMV4_TRCIDR0 ] = " TRCIDR0 %llx\n" ,
187
+ [CS_ETMV4_TRCIDR1 ] = " TRCIDR1 %llx\n" ,
188
+ [CS_ETMV4_TRCIDR2 ] = " TRCIDR2 %llx\n" ,
189
+ [CS_ETMV4_TRCIDR8 ] = " TRCIDR8 %llx\n" ,
190
+ [CS_ETMV4_TRCAUTHSTATUS ] = " TRCAUTHSTATUS %llx\n" ,
191
+ };
192
+
193
+ static void cs_etm__print_auxtrace_info (u64 * val , int num )
194
+ {
195
+ int i , j , cpu = 0 ;
196
+
197
+ for (i = 0 ; i < CS_HEADER_VERSION_0_MAX ; i ++ )
198
+ fprintf (stdout , cs_etm_global_header_fmts [i ], val [i ]);
199
+
200
+ for (i = CS_HEADER_VERSION_0_MAX ; cpu < num ; cpu ++ ) {
201
+ if (val [i ] == __perf_cs_etmv3_magic )
202
+ for (j = 0 ; j < CS_ETM_PRIV_MAX ; j ++ , i ++ )
203
+ fprintf (stdout , cs_etm_priv_fmts [j ], val [i ]);
204
+ else if (val [i ] == __perf_cs_etmv4_magic )
205
+ for (j = 0 ; j < CS_ETMV4_PRIV_MAX ; j ++ , i ++ )
206
+ fprintf (stdout , cs_etmv4_priv_fmts [j ], val [i ]);
207
+ else
208
+ /* failure.. return */
209
+ return ;
210
+ }
211
+ }
212
+
154
213
int cs_etm__process_auxtrace_info (union perf_event * event ,
155
214
struct perf_session * session )
156
215
{
157
216
struct auxtrace_info_event * auxtrace_info = & event -> auxtrace_info ;
158
217
struct cs_etm_auxtrace * etm = NULL ;
218
+ struct int_node * inode ;
219
+ unsigned int pmu_type ;
159
220
int event_header_size = sizeof (struct perf_event_header );
160
221
int info_header_size ;
161
222
int total_size = auxtrace_info -> header .size ;
162
- int err = 0 ;
223
+ int priv_size = 0 ;
224
+ int num_cpu ;
225
+ int err = 0 , idx = -1 ;
226
+ int i , j , k ;
227
+ u64 * ptr , * hdr = NULL ;
228
+ u64 * * metadata = NULL ;
163
229
164
230
/*
165
231
* sizeof(auxtrace_info_event::type) +
@@ -170,10 +236,117 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
170
236
if (total_size < (event_header_size + info_header_size ))
171
237
return - EINVAL ;
172
238
239
+ priv_size = total_size - event_header_size - info_header_size ;
240
+
241
+ /* First the global part */
242
+ ptr = (u64 * ) auxtrace_info -> priv ;
243
+
244
+ /* Look for version '0' of the header */
245
+ if (ptr [0 ] != 0 )
246
+ return - EINVAL ;
247
+
248
+ hdr = zalloc (sizeof (* hdr ) * CS_HEADER_VERSION_0_MAX );
249
+ if (!hdr )
250
+ return - ENOMEM ;
251
+
252
+ /* Extract header information - see cs-etm.h for format */
253
+ for (i = 0 ; i < CS_HEADER_VERSION_0_MAX ; i ++ )
254
+ hdr [i ] = ptr [i ];
255
+ num_cpu = hdr [CS_PMU_TYPE_CPUS ] & 0xffffffff ;
256
+ pmu_type = (unsigned int ) ((hdr [CS_PMU_TYPE_CPUS ] >> 32 ) &
257
+ 0xffffffff );
258
+
259
+ /*
260
+ * Create an RB tree for traceID-CPU# tuple. Since the conversion has
261
+ * to be made for each packet that gets decoded, optimizing access in
262
+ * anything other than a sequential array is worth doing.
263
+ */
264
+ traceid_list = intlist__new (NULL );
265
+ if (!traceid_list ) {
266
+ err = - ENOMEM ;
267
+ goto err_free_hdr ;
268
+ }
269
+
270
+ metadata = zalloc (sizeof (* metadata ) * num_cpu );
271
+ if (!metadata ) {
272
+ err = - ENOMEM ;
273
+ goto err_free_traceid_list ;
274
+ }
275
+
276
+ /*
277
+ * The metadata is stored in the auxtrace_info section and encodes
278
+ * the configuration of the ARM embedded trace macrocell which is
279
+ * required by the trace decoder to properly decode the trace due
280
+ * to its highly compressed nature.
281
+ */
282
+ for (j = 0 ; j < num_cpu ; j ++ ) {
283
+ if (ptr [i ] == __perf_cs_etmv3_magic ) {
284
+ metadata [j ] = zalloc (sizeof (* metadata [j ]) *
285
+ CS_ETM_PRIV_MAX );
286
+ if (!metadata [j ]) {
287
+ err = - ENOMEM ;
288
+ goto err_free_metadata ;
289
+ }
290
+ for (k = 0 ; k < CS_ETM_PRIV_MAX ; k ++ )
291
+ metadata [j ][k ] = ptr [i + k ];
292
+
293
+ /* The traceID is our handle */
294
+ idx = metadata [j ][CS_ETM_ETMTRACEIDR ];
295
+ i += CS_ETM_PRIV_MAX ;
296
+ } else if (ptr [i ] == __perf_cs_etmv4_magic ) {
297
+ metadata [j ] = zalloc (sizeof (* metadata [j ]) *
298
+ CS_ETMV4_PRIV_MAX );
299
+ if (!metadata [j ]) {
300
+ err = - ENOMEM ;
301
+ goto err_free_metadata ;
302
+ }
303
+ for (k = 0 ; k < CS_ETMV4_PRIV_MAX ; k ++ )
304
+ metadata [j ][k ] = ptr [i + k ];
305
+
306
+ /* The traceID is our handle */
307
+ idx = metadata [j ][CS_ETMV4_TRCTRACEIDR ];
308
+ i += CS_ETMV4_PRIV_MAX ;
309
+ }
310
+
311
+ /* Get an RB node for this CPU */
312
+ inode = intlist__findnew (traceid_list , idx );
313
+
314
+ /* Something went wrong, no need to continue */
315
+ if (!inode ) {
316
+ err = PTR_ERR (inode );
317
+ goto err_free_metadata ;
318
+ }
319
+
320
+ /*
321
+ * The node for that CPU should not be taken.
322
+ * Back out if that's the case.
323
+ */
324
+ if (inode -> priv ) {
325
+ err = - EINVAL ;
326
+ goto err_free_metadata ;
327
+ }
328
+ /* All good, associate the traceID with the CPU# */
329
+ inode -> priv = & metadata [j ][CS_ETM_CPU ];
330
+ }
331
+
332
+ /*
333
+ * Each of CS_HEADER_VERSION_0_MAX, CS_ETM_PRIV_MAX and
334
+ * CS_ETMV4_PRIV_MAX mark how many double words are in the
335
+ * global metadata, and each cpu's metadata respectively.
336
+ * The following tests if the correct number of double words was
337
+ * present in the auxtrace info section.
338
+ */
339
+ if (i * 8 != priv_size ) {
340
+ err = - EINVAL ;
341
+ goto err_free_metadata ;
342
+ }
343
+
173
344
etm = zalloc (sizeof (* etm ));
174
345
175
- if (!etm )
346
+ if (!etm ) {
176
347
err = - ENOMEM ;
348
+ goto err_free_metadata ;
349
+ }
177
350
178
351
err = auxtrace_queues__init (& etm -> queues );
179
352
if (err )
@@ -182,6 +355,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
182
355
etm -> session = session ;
183
356
etm -> machine = & session -> machines .host ;
184
357
358
+ etm -> num_cpu = num_cpu ;
359
+ etm -> pmu_type = pmu_type ;
360
+ etm -> snapshot_mode = (hdr [CS_ETM_SNAPSHOT ] != 0 );
361
+ etm -> metadata = metadata ;
185
362
etm -> auxtrace_type = auxtrace_info -> type ;
186
363
etm -> timeless_decoding = cs_etm__is_timeless_decoding (etm );
187
364
@@ -192,8 +369,10 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
192
369
etm -> auxtrace .free = cs_etm__free ;
193
370
session -> auxtrace = & etm -> auxtrace ;
194
371
195
- if (dump_trace )
372
+ if (dump_trace ) {
373
+ cs_etm__print_auxtrace_info (auxtrace_info -> priv , num_cpu );
196
374
return 0 ;
375
+ }
197
376
198
377
err = auxtrace_queues__process_index (& etm -> queues , session );
199
378
if (err )
@@ -208,6 +387,15 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
208
387
session -> auxtrace = NULL ;
209
388
err_free_etm :
210
389
zfree (& etm );
390
+ err_free_metadata :
391
+ /* No need to check @metadata[j], free(NULL) is supported */
392
+ for (j = 0 ; j < num_cpu ; j ++ )
393
+ free (metadata [j ]);
394
+ zfree (& metadata );
395
+ err_free_traceid_list :
396
+ intlist__delete (traceid_list );
397
+ err_free_hdr :
398
+ zfree (& hdr );
211
399
212
400
return - EINVAL ;
213
401
}
0 commit comments