Merge pull request #88 from akloniex/unify-logger

logger/rmbox: unify implementation of new logger tool with old rmbox
This commit is contained in:
Liam Girdwood 2018-10-08 20:40:37 +01:00 committed by GitHub
commit e37aa3f422
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 769 additions and 625 deletions

View File

@ -1,4 +1,4 @@
SUBDIRS = logger rmbox topology eqctl
SUBDIRS = rmbox topology eqctl
TESTDIR = topology/test
tests:

View File

@ -18,7 +18,6 @@ AC_PROG_CC
AC_OUTPUT([
Makefile
logger/Makefile
rmbox/Makefile
eqctl/Makefile
topology/Makefile

View File

@ -1,4 +0,0 @@
bin_PROGRAMS = sof_logger
sof_logger_SOURCES = \
logger.c

View File

@ -1,316 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sof/uapi/logging.h>
#define CEIL(a, b) ((a+b-1)/b)
/* elf signature params */
#define SND_SOF_LOGS_SIG_SIZE 4
#define SND_SOF_LOGS_SIG "Logs"
struct snd_sof_logs_header {
/* "Logs" */
unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
/* address of log entries section */
uint32_t base_address;
/* amount of bytes following this header */
uint32_t data_length;
/* offset to first entry in this file */
uint32_t data_offset;
};
struct ldc_entry_header {
uint32_t level;
uint32_t component_id;
uint32_t params_num;
uint32_t line_idx;
uint32_t file_name_len;
};
struct ldc_entry {
struct ldc_entry_header header;
char *file_name;
uint32_t text_len;
char *text;
uint32_t *params;
};
struct dma_log {
struct log_entry_header header;
uint32_t address;
};
static int fetch_entry(FILE *f_ldc, FILE *f_in, uint32_t base_address,
uint32_t data_offset, struct dma_log dma_log);
static void print_table_header(void);
static void print_entry_params(struct dma_log dma_log, struct ldc_entry);
static void usage(char *name);
static inline void print_table_header(void)
{
fprintf(stdout, "%10s %8s %8s %14s %16s %24s\t%s\n",
"ADDRESS",
"CORE_ID",
"LEVEL",
"COMPONENT_ID",
"TIMESTAMP",
"FILE_NAME",
"CONTENT");
}
static void print_entry_params(struct dma_log dma_log,
struct ldc_entry entry)
{
fprintf(stdout, "%10x %8u %8u %14u %16lu %20s:%u\t",
dma_log.address,
dma_log.header.core_id,
entry.header.level,
entry.header.component_id,
dma_log.header.timestamp,
entry.file_name,
entry.header.line_idx);
switch (entry.header.params_num){
case 0:
fprintf(stdout, "%s", entry.text);
break;
case 1:
fprintf(stdout, entry.text, entry.params[0]);
break;
case 2:
fprintf(stdout, entry.text, entry.params[0],
entry.params[1]);
break;
case 3:
fprintf(stdout, entry.text, entry.params[0], entry.params[1],
entry.params[2]);
break;
}
fprintf(stdout, "\n");
}
static void usage(char *name)
{
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
fprintf(stdout, "%s:\t \t\t\tParse traces logs\n", name);
fprintf(stdout, "%s:\t -l *.ldc_file\t-i in_file\n", name);
fprintf(stdout, "%s:\t -t\t\t\tDisplay dma trace data\n", name);
exit(0);
}
static int fetch_entry(FILE *f_ldc, FILE *f_in, uint32_t base_address,
uint32_t data_offset, struct dma_log dma_log)
{
struct ldc_entry entry;
long int padding;
uint32_t entry_offset;
uint32_t text_len;
int ret;
entry.file_name = NULL;
entry.text = NULL;
entry.params = NULL;
/* evaluate entry offset in input file */
entry_offset = dma_log.address - base_address;
/* set file position to beginning of processed entry */
fseek(f_ldc, entry_offset + data_offset, SEEK_SET);
/* fetching elf header params */
ret = fread(&entry.header, sizeof(entry.header), 1, f_ldc);
if (!ret) {
ret = -ferror(f_ldc);
goto out;
}
entry.file_name = (char *) malloc(entry.header.file_name_len);
if (!entry.file_name){
fprintf(stderr, "error: can't allocate %d byte for "
"entry.file_name\n", entry.header.file_name_len);
ret = -ENOMEM;
goto out;
}
ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
f_ldc);
if (ret != entry.header.file_name_len) {
ret = -ferror(f_ldc);
goto out;
}
/* padding - sequences of chars are aligned to DWORDS */
fseek(f_ldc, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
/* fetching text length */
ret = fread(&entry.text_len, sizeof(entry.text_len), 1, f_ldc);
if (!ret) {
ret = -ferror(f_ldc);
goto out;
}
/* fetching text */
entry.text = (char *) malloc(entry.text_len);
if (entry.text == NULL) {
fprintf(stderr, "error: can't allocate %d byte for "
"entry.text\n", entry.text_len);
ret = -ENOMEM;
goto out;
}
ret = fread(entry.text, sizeof(char), entry.text_len, f_ldc);
if (ret != entry.text_len) {
ret = -ferror(f_ldc);
goto out;
}
/* fetching entry params from dma dump */
entry.params = (uint32_t *) malloc(sizeof(uint32_t) *
entry.header.params_num);
ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num,
f_in);
if (ret != entry.header.params_num) {
ret = -ferror(f_in);
goto out;
}
/* printing entry content */
print_entry_params(dma_log, entry);
/* set f_ldc file position to the beginning */
rewind(f_ldc);
ret = 0;
out:
/* free alocated memory */
free(entry.params);
free(entry.text);
free(entry.file_name);
return ret;
}
static int logger_read(const char *in_file, FILE *f_ldc, struct snd_sof_logs_header *snd)
{
struct dma_log dma_log;
FILE *f_in = NULL;
int ret = 0;
f_in = fopen(in_file, "r");
if (f_in == NULL) {
fprintf(stderr, "Error while opening %s. \n", in_file);
ret = errno;
goto out;
}
print_table_header();
while (!feof(f_in)) {
/* getting entry parameters from dma dump */
ret = fread(&dma_log, sizeof(dma_log), 1, f_in);
if (!ret) {
ret = -ferror(f_in);
goto out;
}
/* checking log address */
if ((dma_log.address < snd->base_address) ||
(dma_log.address > (snd->base_address + snd->data_length)))
continue;
/* fetching entry from elf dump*/
ret = fetch_entry(f_ldc, f_in, snd->base_address,
snd->data_offset, dma_log);
if (ret)
break;
}
out:
if (f_ldc) fclose(f_ldc);
if (f_in) fclose(f_in);
return ret;
}
int main(int argc, char *argv[])
{
struct snd_sof_logs_header snd;
const char *ldc_file = NULL;
const char *in_file = NULL;
int opt, trace = 0, ret = 0;
FILE *f_ldc = NULL;
while ((opt = getopt(argc, argv, "l:i:th")) != -1) {
switch (opt) {
case 'l':
ldc_file = optarg;
break;
case 'i':
in_file = optarg;
break;
case 't':
trace = 1;
break;
case 'h':
default:
usage(argv[0]);
}
}
if (!ldc_file) {
fprintf(stderr, "error: invalid ldc file.\n");
usage(argv[0]);
return -EINVAL;
}
f_ldc = fopen(ldc_file, "r");
if (f_ldc == NULL) {
fprintf(stderr, "Error while opening %s. \n", ldc_file);
ret = errno;
goto out;
}
/* set file positions to the beginning */
rewind(f_ldc);
/* veryfing ldc signature */
ret = fread(&snd, sizeof(snd), 1, f_ldc);
if (!ret) {
ret = -ferror(f_ldc);
goto out;
}
if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
fprintf(stderr, "Error: Invalid ldc file signature. \n");
ret = -EINVAL;
goto out;
}
/* dma trace requested */
if (trace)
return logger_read("/sys/kernel/debug/sof/trace", f_ldc, &snd);
/* default option with no infile is to dump errors/debug data */
if (!in_file)
return logger_read("/sys/kernel/debug/sof/etrace", f_ldc, &snd);
return logger_read(in_file, f_ldc, &snd);
out:
if (f_ldc) fclose(f_ldc);
return ret;
}

View File

@ -1,4 +1,12 @@
bin_PROGRAMS = rmbox
bin_PROGRAMS = rmbox logger
rmbox_SOURCES = \
rmbox.c
rmbox.c \
rmbox_convert.c
logger_SOURCES = \
rmbox.c \
logger_convert.c
logger_CFLAGS = \
-DLOGGER_FORMAT

41
rmbox/convert.h Normal file
View File

@ -0,0 +1,41 @@
/*
* debug log converter interface.
*
* Copyright (c) 2018, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdio.h>
#include <sof/uapi/logging.h>
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
static double to_usecs(uint64_t time, double clk)
{
/* trace timestamp uses CPU system clock at default 25MHz ticks */
// TODO: support variable clock rates
return (double)time / clk;
}
struct convert_config {
const char *out_file;
const char *in_file;
FILE *out_fd;
FILE *in_fd;
double clock;
int trace;
#ifdef LOGGER_FORMAT
const char *ldc_file;
FILE* ldc_fd;
#endif
};
int convert(struct convert_config *config);

286
rmbox/logger_convert.c Normal file
View File

@ -0,0 +1,286 @@
/*
* debug log converter, using new logger format.
*
* Copyright (c) 2018, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
#include "convert.h"
#define CEIL(a, b) ((a+b-1)/b)
/* logs file signature */
#define SND_SOF_LOGS_SIG_SIZE 4
#define SND_SOF_LOGS_SIG "Logs"
struct snd_sof_logs_header {
/* "Logs" */
unsigned char sig[SND_SOF_LOGS_SIG_SIZE];
/* address of log entries section */
uint32_t base_address;
/* amount of bytes following this header */
uint32_t data_length;
/* offset to first entry in this file */
uint32_t data_offset;
};
struct ldc_entry_header {
uint32_t level;
uint32_t component_id;
uint32_t params_num;
uint32_t line_idx;
uint32_t file_name_len;
};
struct ldc_entry {
struct ldc_entry_header header;
char *file_name;
uint32_t text_len;
char *text;
uint32_t *params;
};
struct dma_log {
struct log_entry_header header;
uint32_t address;
};
static inline void print_table_header(FILE *out_fd)
{
fprintf(out_fd, "%5s %6s %8s %16s %16s %24s\t%s\n",
"CORE",
"LEVEL",
"COMP_ID",
"TIMESTAMP",
"DELTA",
"FILE_NAME",
"CONTENT");
}
#define CASE(x) \
case(TRACE_CLASS_##x): return #x
static const char * get_component_name(uint32_t component_id) {
switch (component_id) {
CASE(IRQ);
CASE(IPC);
CASE(PIPE);
CASE(HOST);
CASE(DAI);
CASE(DMA);
CASE(SSP);
CASE(COMP);
CASE(WAIT);
CASE(LOCK);
CASE(MEM);
CASE(MIXER);
CASE(BUFFER);
CASE(VOLUME);
CASE(SWITCH);
CASE(MUX);
CASE(SRC);
CASE(TONE);
CASE(EQ_FIR);
CASE(EQ_IIR);
CASE(SA);
CASE(DMIC);
CASE(POWER);
default: return "unknown";
}
}
static void print_entry_params(FILE *out_fd, struct dma_log dma_log,
struct ldc_entry entry, uint64_t last_timestamp, double clock)
{
float dt = to_usecs(dma_log.header.timestamp - last_timestamp, clock);
if (dt < 0 || dt > 1000.0 * 1000.0 * 1000.0)
dt = NAN;
fprintf(out_fd, "%s%5u %6u %8s %16.6f %16.6f %20s:%u\t",
entry.header.level == LOG_LEVEL_CRITICAL ? KRED : KNRM,
dma_log.header.core_id,
entry.header.level,
get_component_name(entry.header.component_id),
to_usecs(dma_log.header.timestamp, clock),
dt,
entry.file_name,
entry.header.line_idx);
switch (entry.header.params_num) {
case 0:
fprintf(out_fd, "%s", entry.text);
break;
case 1:
fprintf(out_fd, entry.text, entry.params[0]);
break;
case 2:
fprintf(out_fd, entry.text, entry.params[0], entry.params[1]);
break;
case 3:
fprintf(out_fd, entry.text, entry.params[0], entry.params[1],
entry.params[2]);
break;
}
fprintf(out_fd, "\n");
}
static int fetch_entry(struct convert_config *config, uint32_t base_address,
uint32_t data_offset, struct dma_log dma_log, uint64_t *last_timestamp)
{
struct ldc_entry entry;
long int padding;
uint32_t entry_offset;
uint32_t text_len;
int ret;
entry.file_name = NULL;
entry.text = NULL;
entry.params = NULL;
/* evaluate entry offset in input file */
entry_offset = dma_log.address - base_address;
/* set file position to beginning of processed entry */
fseek(config->ldc_fd, entry_offset + data_offset, SEEK_SET);
/* fetching elf header params */
ret = fread(&entry.header, sizeof(entry.header), 1, config->ldc_fd);
if (!ret) {
ret = -ferror(config->ldc_fd);
goto out;
}
entry.file_name = (char *)malloc(entry.header.file_name_len);
if (!entry.file_name) {
fprintf(stderr, "error: can't allocate %d byte for "
"entry.file_name\n", entry.header.file_name_len);
ret = -ENOMEM;
goto out;
}
ret = fread(entry.file_name, sizeof(char), entry.header.file_name_len,
config->ldc_fd);
if (ret != entry.header.file_name_len) {
ret = -ferror(config->ldc_fd);
goto out;
}
/* padding - sequences of chars are aligned to DWORDS */
fseek(config->ldc_fd, CEIL(entry.header.file_name_len, sizeof(uint32_t)) *
sizeof(uint32_t) - entry.header.file_name_len, SEEK_CUR);
/* fetching text length */
ret = fread(&entry.text_len, sizeof(entry.text_len), 1, config->ldc_fd);
if (!ret) {
ret = -ferror(config->ldc_fd);
goto out;
}
/* fetching text */
entry.text = (char *)malloc(entry.text_len);
if (entry.text == NULL) {
fprintf(stderr, "error: can't allocate %d byte for "
"entry.text\n", entry.text_len);
ret = -ENOMEM;
goto out;
}
ret = fread(entry.text, sizeof(char), entry.text_len, config->ldc_fd);
if (ret != entry.text_len) {
ret = -ferror(config->ldc_fd);
goto out;
}
/* fetching entry params from dma dump */
entry.params = (uint32_t *)malloc(sizeof(uint32_t) *
entry.header.params_num);
ret = fread(entry.params, sizeof(uint32_t), entry.header.params_num,
config->in_fd);
if (ret != entry.header.params_num) {
ret = -ferror(config->in_fd);
goto out;
}
/* printing entry content */
print_entry_params(config->out_fd, dma_log, entry, *last_timestamp,
config->clock);
*last_timestamp = dma_log.header.timestamp;
/* set f_ldc file position to the beginning */
rewind(config->ldc_fd);
ret = 0;
out:
/* free alocated memory */
free(entry.params);
free(entry.text);
free(entry.file_name);
return ret;
}
static int logger_read(struct convert_config *config,
struct snd_sof_logs_header *snd)
{
struct dma_log dma_log;
int ret = 0;
print_table_header(config->out_fd);
uint64_t last_timestamp = 0;
while (!feof(config->in_fd)) {
/* getting entry parameters from dma dump */
ret = fread(&dma_log, sizeof(dma_log), 1, config->in_fd);
if (!ret) {
return -ferror(config->in_fd);
}
/* checking log address */
if ((dma_log.address < snd->base_address) ||
dma_log.address > snd->base_address + snd->data_length)
continue;
/* fetching entry from elf dump */
ret = fetch_entry(config, snd->base_address, snd->data_offset,
dma_log, &last_timestamp);
if (ret)
break;
}
return ret;
}
int convert(struct convert_config *config) {
struct snd_sof_logs_header snd;
int count, ret = 0;
count = fread(&snd, sizeof(snd), 1, config->ldc_fd);
if (!count) {
fprintf(stderr, "Error while reading %s. \n", config->ldc_file);
return -ferror(config->ldc_fd);
}
if (strncmp(snd.sig, SND_SOF_LOGS_SIG, SND_SOF_LOGS_SIG_SIZE)) {
fprintf(stderr, "Error: Invalid ldc file signature. \n");
return -EINVAL;
}
return logger_read(config, &snd);
}

View File

@ -12,259 +12,43 @@
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
// TODO: include all this stuff
#define TRACE_CLASS_IRQ (1 << 24)
#define TRACE_CLASS_IPC (2 << 24)
#define TRACE_CLASS_PIPE (3 << 24)
#define TRACE_CLASS_HOST (4 << 24)
#define TRACE_CLASS_DAI (5 << 24)
#define TRACE_CLASS_DMA (6 << 24)
#define TRACE_CLASS_SSP (7 << 24)
#define TRACE_CLASS_COMP (8 << 24)
#define TRACE_CLASS_WAIT (9 << 24)
#define TRACE_CLASS_LOCK (10 << 24)
#define TRACE_CLASS_MEM (11 << 24)
#define TRACE_CLASS_MIXER (12 << 24)
#define TRACE_CLASS_BUFFER (13 << 24)
#define TRACE_CLASS_VOLUME (14 << 24)
#define TRACE_CLASS_SWITCH (15 << 24)
#define TRACE_CLASS_MUX (16 << 24)
#define TRACE_CLASS_SRC (17 << 24)
#define TRACE_CLASS_TONE (18 << 24)
#define TRACE_CLASS_EQ_FIR (19 << 24)
#define TRACE_CLASS_EQ_IIR (20 << 24)
#define TRACE_CLASS_SA (21 << 24)
#define TRACE_CLASS_DMIC (22 << 24)
#define TRACE_CLASS_POWER (23 << 24)
#include "convert.h"
#ifdef LOGGER_FORMAT
#define APP_NAME "logger"
#else
#define APP_NAME "rmbox"
#endif
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define TRACE_BLOCK_SIZE 8
static inline char get_char(uint32_t val, int idx)
{
char c = (val >> (idx * 8)) & 0xff;
if (c < '0' || c > 'z')
return '.';
else
return c;
}
static void usage(char *name)
{
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", name);
fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", name);
fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", name);
fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", name);
fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", name);
fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", name);
exit(0);
}
static double to_usecs(uint64_t time, double clk)
{
/* trace timestamp uses CPU system clock at default 25MHz ticks */
// TODO: support variable clock rates
return (double)time / clk;
}
static void show_trace(uint64_t val, uint64_t addr, uint64_t *timestamp, double clk)
{
const char *trace;
uint32_t class;
uint64_t delta = val - *timestamp;
double fdelta = to_usecs(delta, clk);
double us = 0.0f;
/* timestamp or value ? */
if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
delta = val - *timestamp;
fdelta = to_usecs(delta, clk);
/* 64-bit timestamp */
us = to_usecs(val, clk);
/* empty data ? */
if (val == 0) {
*timestamp = 0;
return;
}
/* detect wrap around */
if (fdelta < 1000.0 * 1000.0 * 1000.0)
printf("0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
us / 1000000.0 , fdelta / 1000000.0);
else
printf("0x%lx [%6.6f]\tdelta [********]\t", addr,
us / 1000000.0);
*timestamp = val;
return;
} else if (*timestamp == 0)
return;
/* check for printable values - otherwise it's a value */
if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
printf("value 0x%16.16lx\n", val);
return;
}
class = val & 0xff000000;
if (class == TRACE_CLASS_IRQ)
trace = "irq";
else if (class == TRACE_CLASS_IPC)
trace = "ipc";
else if (class == TRACE_CLASS_PIPE)
trace = "pipe";
else if (class == TRACE_CLASS_HOST)
trace = "host";
else if (class == TRACE_CLASS_DAI)
trace = "dai";
else if (class == TRACE_CLASS_DMA)
trace = "dma";
else if (class == TRACE_CLASS_SSP)
trace = "ssp";
else if (class == TRACE_CLASS_COMP)
trace = "comp";
else if (class == TRACE_CLASS_WAIT)
trace = "wait";
else if (class == TRACE_CLASS_LOCK)
trace = "lock";
else if (class == TRACE_CLASS_MEM)
trace = "mem";
else if (class == TRACE_CLASS_MIXER)
trace = "mixer";
else if (class == TRACE_CLASS_BUFFER)
trace = "buffer";
else if (class == TRACE_CLASS_VOLUME)
trace = "volume";
else if (class == TRACE_CLASS_SWITCH)
trace = "switch";
else if (class == TRACE_CLASS_MUX)
trace = "mux";
else if (class == TRACE_CLASS_SRC)
trace = "src";
else if (class == TRACE_CLASS_TONE)
trace = "tone";
else if (class == TRACE_CLASS_EQ_FIR)
trace = "eq-fir";
else if (class == TRACE_CLASS_EQ_IIR)
trace = "eq-iir";
else if (class == TRACE_CLASS_SA)
trace = "sa";
else if (class == TRACE_CLASS_DMIC)
trace = "dmic";
else if (class == TRACE_CLASS_POWER)
trace = "pm";
else {
printf("value 0x%8.8x\n", (uint32_t)val);
return;
}
switch ((char)(val >> 16)) {
case 'e':
case 'E':
case 'x':
case 'X':
printf("%s%s %c%c%c%s\n", KRED, trace,
(char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
break;
default:
printf("%s %c%c%c\n", trace,
(char)(val >> 16), (char)(val >> 8), (char)val);
break;
}
}
static int trace_read(const char *in_file, const char *out_file, double clk)
{
int count, i;
FILE *in_fd = NULL, *out_fd = NULL;
char c, tmp[TRACE_BLOCK_SIZE] = {0};
uint64_t addr = 0, val, timestamp = 0;
in_fd = fopen(in_file, "r");
if (in_fd == NULL) {
fprintf(stderr, "error: unable to open %s for reading %d\n",
in_file, errno);
return -EIO;
}
if (out_file == NULL)
goto trace;
out_fd = fopen(out_file, "w");
if (out_fd == NULL) {
fprintf(stderr, "error: unable to open %s for writing %d\n",
out_file, errno);
}
trace:
fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
while (1) {
count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, in_fd);
if (count != TRACE_BLOCK_SIZE)
break;
val = *((uint64_t*)tmp);
for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
c = tmp[i];
tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
tmp[TRACE_BLOCK_SIZE - i - 1] = c;
}
show_trace(val, addr, &timestamp, clk);
if (out_fd) {
count = fwrite(&tmp[0], 1, TRACE_BLOCK_SIZE, out_fd);
if (count != TRACE_BLOCK_SIZE)
break;
}
addr += TRACE_BLOCK_SIZE;
}
fclose(in_fd);
if (out_fd)
fclose(out_fd);
return 0;
}
static void show_data(uint32_t val, uint32_t addr)
{
printf("data: 0x%x = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
(unsigned int)addr,
val, val,
get_char(val, 3), get_char(val, 2),
get_char(val, 1), get_char(val, 0));
}
static const char *debugfs[] = {
"dmac0", "dmac1", "ssp0", "ssp1",
"ssp2", "iram", "dram", "shim",
"mbox", "etrace",
};
static void usage(void)
{
fprintf(stdout, "Usage %s <option(s)> <file(s)>\n", APP_NAME);
fprintf(stdout, "%s:\t \t\t\tDisplay mailbox contents\n", APP_NAME);
fprintf(stdout, "%s:\t -i infile -o outfile\tDump infile contents to outfile\n", APP_NAME);
#ifdef LOGGER_FORMAT
fprintf(stdout, "%s:\t -l *.ldc_file\t-i in_file\n", APP_NAME);
#endif
fprintf(stdout, "%s:\t -c\t\t\tSet timestamp clock in MHz\n", APP_NAME);
fprintf(stdout, "%s:\t -s\t\t\tTake a snapshot of state\n", APP_NAME);
fprintf(stdout, "%s:\t -t\t\t\tDisplay trace data\n", APP_NAME);
exit(0);
}
static int snapshot(const char *name)
{
const char *path = "/sys/kernel/debug/sof";
@ -324,99 +108,112 @@ static int snapshot(const char *name)
int main(int argc, char *argv[])
{
int opt, count, trace = 0;
const char * out_file = NULL, *in_file = NULL;
struct convert_config config;
int opt, count, ret = 0;
FILE *in_fd = NULL, *out_fd = NULL;
char c, tmp[8] = {0};
uint64_t addr = 0, val, timestamp = 0, align = 4, i;
double clk = 19.2;
config.trace = 0;
config.clock = 19.2;
config.in_file = NULL;
config.out_file = NULL;
config.out_fd = NULL;
config.in_fd = NULL;
#ifdef LOGGER_FORMAT
config.ldc_file = NULL;
#endif
#ifdef LOGGER_FORMAT
while ((opt = getopt(argc, argv, "ho:i:l:s:m:c:t")) != -1) {
#else
while ((opt = getopt(argc, argv, "ho:i:s:m:c:t")) != -1) {
#endif
switch (opt) {
case 'o':
out_file = optarg;
config.out_file = optarg;
break;
case 'i':
in_file = optarg;
config.in_file = optarg;
break;
case 't':
trace = 1;
config.trace = 1;
break;
case 'c':
clk = atof(optarg);
config.clock = atof(optarg);
break;
case 's':
return snapshot(optarg);
#ifdef LOGGER_FORMAT
case 'l':
config.ldc_file = optarg;
break;
#endif
case 'h':
default: /* '?' */
usage(argv[0]);
usage();
}
}
#ifdef LOGGER_FORMAT
if (!config.ldc_file) {
fprintf(stderr, "error: Missing ldc file");
usage();
}
config.ldc_fd = fopen(config.ldc_file, "r");
if (!config.ldc_fd) {
fprintf(stderr, "error: Unable to open ldc file %s\n",
config.ldc_file);
ret = -errno;
goto out;
}
#endif
if (config.out_file) {
config.out_fd = fopen(config.out_file, "w");
if (!config.out_fd) {
fprintf(stderr, "error: Unable to open out file %s\n",
config.out_file);
ret = -errno;
goto out;
}
} else {
config.out_fd = stdout;
}
/* trace requested ? */
if (trace)
return trace_read("/sys/kernel/debug/sof/trace",
out_file, clk);
if (config.trace)
config.in_file = "/sys/kernel/debug/sof/trace";
/* default option with no infile is to dump errors/debug data */
if (in_file == NULL) {
fprintf(stdout, "\nError log:\n");
return trace_read("/sys/kernel/debug/sof/etrace",
out_file, clk);
}
if (!config.in_file)
config.in_file = "/sys/kernel/debug/sof/etrace";
/* open infile for reading */
in_fd = fopen(in_file, "r");
if (in_fd == NULL) {
fprintf(stderr, "error: unable to open %s for reading %d\n",
in_file, errno);
return -EIO;
}
/* open outfile for writing */
if (out_file == NULL)
goto convert;
out_fd = fopen(out_file, "w");
if (out_fd == NULL) {
fprintf(stderr, "error: unable to open %s for writing %d\n",
out_file, errno);
fclose(in_fd);
return -EIO;
}
/* start to converting mailbox */
convert:
fprintf(stdout, "using %2.2fMHz timestamp clock\n", clk);
while (1) {
count = fread(&tmp[0], 1, align, in_fd);
if (count != align)
break;
val = *((uint64_t*)tmp);
for (i = 0; i < align / 2; i++) {
c = tmp[i];
tmp[i] = tmp[align - i - 1];
tmp[align - i - 1] = c;
if (config.in_file) {
config.in_fd = fopen(config.in_file, "r");
if (!config.in_fd) {
fprintf(stderr, "error: Unable to open in file %s\n",
config.in_file);
ret = -errno;
goto out;
}
show_data(val, addr);
if (out_fd) {
count = fwrite(&tmp[0], 1, align, out_fd);
if (count != align)
break;
}
addr += align;
}
convert(&config);
out:
/* close files */
fclose(in_fd);
if (out_fd)
fclose(out_fd);
if (config.out_file)
fclose(config.out_fd);
return 0;
if (config.in_fd)
fclose(config.in_fd);
#ifdef LOGGER_FORMAT
if (config.ldc_fd)
fclose(config.ldc_fd);
#endif
return ret;
}

142
rmbox/rmbox_convert.c Normal file
View File

@ -0,0 +1,142 @@
/*
* debug log converter, using old rmbox format.
*
* Copyright (c) 2018, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "convert.h"
#define TRACE_BLOCK_SIZE 8
#define CASE(x) case(TRACE_CLASS_##x): trace = #x; break
static void show_trace(FILE *out_fd, uint64_t val, uint64_t addr,
uint64_t *timestamp, double clk)
{
const char *trace;
uint32_t class;
uint64_t delta = val - *timestamp;
double fdelta = to_usecs(delta, clk);
double us = 0.0f;
/* timestamp or value ? */
if ((addr % (TRACE_BLOCK_SIZE * 2)) == 0) {
delta = val - *timestamp;
fdelta = to_usecs(delta, clk);
/* 64-bit timestamp */
us = to_usecs(val, clk);
/* empty data ? */
if (val == 0) {
*timestamp = 0;
return;
}
/* detect wrap around */
if (fdelta < 1000.0 * 1000.0 * 1000.0)
fprintf(out_fd, "0x%lx [%6.6f]\tdelta [%6.6f]\t", addr,
us / 1000000.0, fdelta / 1000000.0);
else
fprintf(out_fd, "0x%lx [%6.6f]\tdelta [********]\t", addr,
us / 1000000.0);
*timestamp = val;
return;
}
else if (*timestamp == 0)
return;
/* check for printable values - otherwise it's a value */
if (!isprint((char)(val >> 16)) || !isprint((char)(val >> 8)) || !isprint((char)val)) {
fprintf(out_fd, "value 0x%16.16lx\n", val);
return;
}
class = val & 0xff000000;
switch (class)
{
CASE(IRQ);
CASE(IPC);
CASE(PIPE);
CASE(HOST);
CASE(DAI);
CASE(DMA);
CASE(SSP);
CASE(COMP);
CASE(WAIT);
CASE(LOCK);
CASE(MEM);
CASE(MIXER);
CASE(BUFFER);
CASE(VOLUME);
CASE(SWITCH);
CASE(MUX);
CASE(SRC);
CASE(TONE);
CASE(EQ_FIR);
CASE(EQ_IIR);
CASE(SA);
CASE(DMIC);
CASE(POWER);
default:
fprintf(out_fd, "value 0x%8.8x\n", (uint32_t)val);
return;
}
switch ((char)(val >> 16)) {
case 'e':
case 'E':
case 'x':
case 'X':
fprintf(out_fd, "%s%s %c%c%c%s\n", KRED, trace,
(char)(val >> 16), (char)(val >> 8), (char)val, KNRM);
break;
default:
fprintf(out_fd, "%s %c%c%c\n", trace,
(char)(val >> 16), (char)(val >> 8), (char)val);
break;
}
}
int convert(struct convert_config *config)
{
int count, i;
char c, tmp[TRACE_BLOCK_SIZE] = { 0 };
uint64_t addr = 0, val, timestamp = 0;
fprintf(stdout, "using %2.2fMHz timestamp clock\n", config->clock);
while (1) {
count = fread(&tmp[0], 1, TRACE_BLOCK_SIZE, config->in_fd);
if (count != TRACE_BLOCK_SIZE)
break;
val = *((uint64_t*)tmp);
for (i = 0; i < TRACE_BLOCK_SIZE / 2; i++) {
c = tmp[i];
tmp[i] = tmp[TRACE_BLOCK_SIZE - i - 1];
tmp[TRACE_BLOCK_SIZE - i - 1] = c;
}
show_trace(config->out_fd, val, addr, &timestamp, config->clock);
addr += TRACE_BLOCK_SIZE;
}
return 0;
}

76
rmbox/sof/uapi/abi.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
/**
* \file include/uapi/abi.h
* \brief ABI definitions
* \author Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
#ifndef __INCLUDE_UAPI_ABI_H__
#define __INCLUDE_UAPI_ABI_H__
/** \brief SOF ABI version number. */
#define SOF_ABI_VER(major, minor, micro) \
(((major)<<8)|((minor)<<4)|(micro))
#define SOF_ABI_VERSION_MAJOR(version) (((version)>>8) & 0xff)
#define SOF_ABI_VERSION_MINOR(version) (((version)>>4) & 0xf)
#define SOF_ABI_VERSION_MICRO(version) ((version) & 0xf)
#define SOF_ABI_VERSION_INCOMPATIBLE(sof_ver, client_ver) \
(SOF_ABI_VERSION_MAJOR(sof_ver) != SOF_ABI_VERSION_MAJOR(client_ver) ||\
(SOF_ABI_VERSION_MAJOR(sof_ver) == SOF_ABI_VERSION_MAJOR(client_ver) &&\
SOF_ABI_VERSION_MINOR(sof_ver) != SOF_ABI_VERSION_MINOR(client_ver)))
#define SOF_ABI_MAJOR 1
#define SOF_ABI_MINOR 0
#define SOF_ABI_MICRO 0
#define SOF_ABI_VERSION SOF_ABI_VER(SOF_ABI_MAJOR, SOF_ABI_MINOR, SOF_ABI_MICRO)
/** \brief SOF ABI magic number "SOF\0". */
#define SOF_ABI_MAGIC 0x00464F53
/**
* \brief Header for all non IPC ABI data.
*
* Identifies data type, size and ABI.
* Used by any bespoke component data structures or binary blobs.
*/
struct sof_abi_hdr {
uint32_t magic; /**< 'S', 'O', 'F', '\0' */
uint32_t type; /**< component specific type */
uint32_t size; /**< size in bytes of data excl. this struct */
uint32_t abi; /**< SOF ABI version */
uint32_t comp_abi; /**< component specific ABI version */
char data[0]; /**< data */
} __attribute__((packed));
#endif

115
rmbox/sof/uapi/logging.h Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 2018, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Bartosz Kokoszko <bartoszx.kokoszko@linux.intel.com>
* Artur Kloniecki <arturx.kloniecki@linux.intel.com>
*/
#ifndef __INCLUDE_LOGGING__
#define __INCLUDE_LOGGING__
#include <stdint.h>
/*
* Host system time.
*
* This property is used by the driver to pass down information about
* current system time. It is expressed in us.
* FW translates timestamps (in log entries, probe pockets) to this time
* domain.
*
* (cavs: SystemTime).
*/
struct system_time {
uint32_t val_l; /* Lower dword of current host time value */
uint32_t val_u; /* Upper dword of current host time value */
};
/* trace event classes - high 8 bits*/
#define TRACE_CLASS_IRQ (1 << 24)
#define TRACE_CLASS_IPC (2 << 24)
#define TRACE_CLASS_PIPE (3 << 24)
#define TRACE_CLASS_HOST (4 << 24)
#define TRACE_CLASS_DAI (5 << 24)
#define TRACE_CLASS_DMA (6 << 24)
#define TRACE_CLASS_SSP (7 << 24)
#define TRACE_CLASS_COMP (8 << 24)
#define TRACE_CLASS_WAIT (9 << 24)
#define TRACE_CLASS_LOCK (10 << 24)
#define TRACE_CLASS_MEM (11 << 24)
#define TRACE_CLASS_MIXER (12 << 24)
#define TRACE_CLASS_BUFFER (13 << 24)
#define TRACE_CLASS_VOLUME (14 << 24)
#define TRACE_CLASS_SWITCH (15 << 24)
#define TRACE_CLASS_MUX (16 << 24)
#define TRACE_CLASS_SRC (17 << 24)
#define TRACE_CLASS_TONE (18 << 24)
#define TRACE_CLASS_EQ_FIR (19 << 24)
#define TRACE_CLASS_EQ_IIR (20 << 24)
#define TRACE_CLASS_SA (21 << 24)
#define TRACE_CLASS_DMIC (22 << 24)
#define TRACE_CLASS_POWER (23 << 24)
#define TRACE_CLASS_IDC (24 << 24)
#define TRACE_CLASS_CPU (25 << 24)
#define LOG_ENABLE 1 /* Enable logging */
#define LOG_DISABLE 0 /* Disable logging */
#define LOG_LEVEL_CRITICAL 1 /* (FDK fatal) */
#define LOG_LEVEL_VERBOSE 2
/*
* Layout of a log fifo.
*/
struct log_buffer_layout {
uint32_t read_ptr; /*read pointer */
uint32_t write_ptr; /* write pointer */
uint32_t buffer[0]; /* buffer */
};
/*
* Log buffer status reported by FW.
*/
struct log_buffer_status {
uint32_t core_id; /* ID of core that logged to other half */
};
/*
* Log entry header.
*
* The header is followed by an array of arguments (uint32_t[]).
* Number of arguments is specified by the params_num field of log_entry,
* and is 0-based value (entry_len=0 means there is 1 argument).
*/
struct log_entry_header {
uint32_t rsvd : 24; /* Unused */
uint32_t core_id : 8; /* Reporting core's id */
uint64_t timestamp; /* Timestamp (in dsp ticks) */
} __attribute__((__packed__));
#endif //#ifndef __INCLUDE_LOGGING__