blob: fbfd0549379c773b659705f4a8c1b28649ba8c49 [file] [log] [blame] [edit]
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "/usr/local/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_dma, 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 <file(s)>\n", name);
fprintf(stdout, "%s:\t Parse traces logs\n", name);
fprintf(stdout, "%s:\t -l *.ldc_file\t-d dma_dump_file\n", name);
exit(0);
}
static int fetch_entry(FILE *f_ldc, FILE *f_dma, 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_dma);
if (ret != entry.header.params_num) {
ret = -ferror(f_dma);
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;
}
int main(int argc, char *argv[])
{
struct dma_log dma_log;
struct snd_sof_logs_header snd;
int ret;
int opt;
const char *ldc_dir = NULL;
const char *dma_dump = NULL;
while ((opt = getopt(argc, argv, "l:d:")) != -1) {
switch (opt) {
case 'l':
ldc_dir = optarg;
break;
case 'd':
dma_dump = optarg;
break;
default:
usage(argv[0]);
}
}
if (!ldc_dir) {
fprintf(stderr, "error: invalid ldc file.\n");
return -EINVAL;
}
if (!dma_dump) {
fprintf(stderr, "error: invalid dma_dump file.\n");
return -EINVAL;
}
FILE *f_ldc = fopen(ldc_dir, "r");
FILE *f_dma = fopen(dma_dump, "r");
if (f_ldc == NULL) {
fprintf(stderr, "Error while opening %s. \n", ldc_dir);
ret = errno;
goto out;
}
if (f_dma == NULL) {
fprintf(stderr, "Error while opening %s. \n", dma_dump);
ret = errno;
goto out;
}
/* set file positions to the beginning */
rewind(f_ldc);
rewind(f_dma);
/* 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;
}
print_table_header();
while (!feof(f_dma)) {
/* getting entry parameters from dma dump */
ret = fread(&dma_log, sizeof(dma_log), 1, f_dma);
if (!ret) {
ret = -ferror(f_dma);
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_dma, snd.base_address,
snd.data_offset, dma_log);
if (ret) goto out;
}
ret = 0;
out:
if (f_dma) fclose(f_dma);
if (f_ldc) fclose(f_ldc);
return ret;
}