From d2b0cb2d4936ade8c7eeaeeffeec68b2fa1b87bc Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 24 Oct 2024 11:49:57 +0200 Subject: [PATCH] Decode Fixes in orbuculum decode files for instruction tracing. --- Inc/loadelf.h | 8 +- Inc/traceDecoder.h | 7 +- Src/loadelf.c | 298 +++++++++++++++++++++++----------------- Src/traceDecoder_etm4.c | 152 ++++++++++++++++---- 4 files changed, 309 insertions(+), 156 deletions(-) diff --git a/Inc/loadelf.h b/Inc/loadelf.h index 34375539..7f71bfed 100644 --- a/Inc/loadelf.h +++ b/Inc/loadelf.h @@ -1,5 +1,6 @@ #ifndef _LOADELF_H_ +#define _LOADELF_H_ #include #include @@ -42,6 +43,7 @@ struct symbolLineStore struct symbolFunctionStore { char *funcname; /* What is the name of the function */ + char *manglename; /* What is the manged name, if any */ unsigned int producer; /* What code/options produced it? */ unsigned int filename; /* What filename + path off the source root? */ unsigned int startline; /* Start line in source file of function */ @@ -87,7 +89,7 @@ struct symbol csh caphandle; }; -enum instructionClass { LE_IC_NONE, LE_IC_JUMP = ( 1 << 0 ), LE_IC_4BYTE = ( 1 << 1 ), LE_IC_CALL = ( 1 << 2 ), LE_IC_IMMEDIATE = ( 1 << 3 ), LE_IC_IRET = ( 1 << 4 ) }; +enum instructionClass { LE_IC_NONE, LE_IC_JUMP = ( 1 << 0 ), LE_IC_4BYTE = ( 1 << 1 ), LE_IC_CALL = ( 1 << 2 ), LE_IC_IMMEDIATE = ( 1 << 3 ), LE_IC_IRET = ( 1 << 4 ), LE_IC_SYNC_BARRIER = ( 1 << 5 ), LE_IC_COPROCESSOR = ( 1 << 6 )}; // ==================================================================================================== @@ -119,13 +121,13 @@ const char *symbolGetFilename( struct symbol *p, unsigned int index ); symbolMemptr symbolCodeAt( struct symbol *p, symbolMemaddr addr, unsigned int *len ); /* Return assembly code representing this line, with annotations */ -char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbolMemaddr addr, symbolMemaddr *newaddr ); +char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbolMemaddr addr, symbolMemaddr *newaddr); /* Delete symbol set */ void symbolDelete( struct symbol *p ); /* Collect symbol set with specified components */ -struct symbol *symbolAcquire( char *filename, bool loadlines, bool loadmem, bool loadsource ); +struct symbol *symbolAcquire( char *filename, bool loadmem, bool loadsource ); /* Check if current symbols are valid */ bool symbolSetValid( struct symbol *p ); diff --git a/Inc/traceDecoder.h b/Inc/traceDecoder.h index fc7b85de..f8b1ea2f 100644 --- a/Inc/traceDecoder.h +++ b/Inc/traceDecoder.h @@ -54,6 +54,7 @@ enum TRACEchanges EV_CH_VMID, EV_CH_TSTAMP, EV_CH_CYCLECOUNT, + EV_CH_ASYNC, EV_CH_CONTEXTID, EV_CH_TRIGGER, EV_CH_SECURE, @@ -143,6 +144,10 @@ struct TRACECPUState // Convinience, for debug reporting genericsReportCB report; + + // Debugging + uint64_t overflows; + uint64_t ASyncs; }; // ============================================================================ @@ -163,7 +168,7 @@ struct TRACEDecoderEngine const char ( *name ) ( void ); /* Config specific to ETM3.5 */ - void ( *altAddrEncode ) ( struct TRACEDecoderEngine *e, bool using ); + void ( *altAddrEncode ) ( struct TRACEDecoderEngine *e, bool _using ); }; struct TRACEDecoder diff --git a/Src/loadelf.c b/Src/loadelf.c index 4ac4ffc9..87642534 100644 --- a/Src/loadelf.c +++ b/Src/loadelf.c @@ -13,10 +13,10 @@ #include "generics.h" #include "readsource.h" -#define MAX_LINE_LEN (4095) +#define DP_MAX_LINE_LEN (4095) #define IS_INFO (true) -static char _print_buffer[MAX_LINE_LEN]; +static char _print_buffer[DP_MAX_LINE_LEN]; // ==================================================================================================== // ==================================================================================================== @@ -171,8 +171,6 @@ static bool _readProg( struct symbol *p ) return false; } - // fprintf(stderr, "%c ADDR=%08lx Type=%8x Flags=%04lx Size=%08lx Name=%s\n",((shdr.sh_flags & SHF_ALLOC) && (shdr.sh_type==SHT_PROGBITS))?'L':' ', shdr.sh_addr, shdr.sh_type, shdr.sh_flags, shdr.sh_size, name); - if ( ( shdr.sh_flags & SHF_ALLOC ) && ( shdr.sh_type == SHT_PROGBITS ) ) { Elf_Data *data = NULL; @@ -284,7 +282,7 @@ static void _getSourceLines( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die ) { dwarf_srclines_from_linecontext( linecontext, &linebuf, &linecount, 0 ); tracked_addr = 0; - zero_start_dont_store = true; + zero_start_dont_store = false; /* If a line address starts at zero, or is a direct continuation of a line that started at zero, then we dispose of it */ /* We consider any line that is within 16 bytes of the previous one to be a continuation, to allow for padding. */ @@ -294,28 +292,17 @@ static void _getSourceLines( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die ) dwarf_lineaddr( linebuf[i], &line_addr, 0 ); dwarf_linebeginstatement( linebuf[i], &begin, 0 ); - //dwarf_prologue_end_etc(linebuf[i], &ispend, &ispbegin, &isa, &disc, 0); - //if(isa) - // fprintf(stderr,"\nDisc=%lld isa=%llx\n",disc,isa); - if ( ( isset ) && ( line_addr == 0 ) ) { zero_start_dont_store = true; } - //if (begin) - // fprintf(stderr,"\nBEGIN(%08x):",(uint32_t)line_addr); - if ( ( zero_start_dont_store && ( ( !begin ) || ( !line_addr ) || ( ( line_addr - tracked_addr ) < 16 ) ) ) ) { zero_start_dont_store = true; - // sprintf(stderr,"!"); } else { - /* We are going to store this one */ - // if (zero_start_dont_store) fprintf(stderr,"\n%08x: ",(uint32_t)line_addr); - //else fprintf(stderr,"*"); zero_start_dont_store = false; dwarf_lineno( linebuf[i], &line_num, 0 ); dwarf_linesrc( linebuf[i], &file_name, 0 ); @@ -357,22 +344,20 @@ void _dwarf_print( void *p, const char *line ) static void _processFunctionDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die, int filenameN, int producerN, Dwarf_Addr cu_base_addr ) { - char *name = ""; + char *name = NULL; + char *manglename = NULL; Dwarf_Addr h = 0; Dwarf_Addr l = 0; - enum Dwarf_Form_Class formclass; + enum Dwarf_Form_Class formclass = DW_FORM_CLASS_UNKNOWN; Dwarf_Attribute attr_data; Dwarf_Half attr_tag; + Dwarf_Die name_die = die; bool isinline = false; struct symbolFunctionStore *newFunc; - attr_tag = DW_AT_inline; - - if ( dwarf_attr( die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) - { - return; - } + Dwarf_Off specification_offset; + Dwarf_Die specification_die; /* See if this is an inline die usage */ attr_tag = DW_AT_abstract_origin; @@ -385,42 +370,48 @@ static void _processFunctionDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die di attr_tag = DW_AT_abstract_origin; dwarf_attr( die, attr_tag, &attr_data, 0 ); dwarf_global_formref( attr_data, &abstract_origin_offset, 0 ); - dwarf_offdie_b( dbg, abstract_origin_offset, IS_INFO, &abstract_origin_die, 0 ); - fprintf( stderr, "Instance at %08x...%08x\n\n\n", ( uint32_t )l, ( uint32_t )h ); - isinline = true; - } - else - { - dwarf_highpc_b ( die, &h, 0, &formclass, 0 ); - dwarf_lowpc ( die, &l, 0 ); + if (DW_DLV_OK == dwarf_offdie_b( dbg, abstract_origin_offset, IS_INFO, &abstract_origin_die, 0 )) + { + isinline = true; + name_die = abstract_origin_die; + } } + dwarf_highpc_b ( die, &h, 0, &formclass, 0 ); + dwarf_lowpc ( die, &l, 0 ); + if ( formclass == DW_FORM_CLASS_CONSTANT ) { h += l; } - if ( l && ( l != h ) ) + specification_die = die; + + /* Get the possibly mangled linkage name if it exists */ + if ( DW_DLV_OK == dwarf_attr( die, DW_AT_linkage_name, &attr_data, 0 ) ) + { + dwarf_formstring( attr_data, &manglename, 0 ); + } + + if ( DW_DLV_OK != dwarf_diename( name_die, &name, 0 ) ) { - if ( DW_DLV_OK != dwarf_diename( die, &name, 0 ) ) + /* Name will be hidden in a specification reference */ + attr_tag = DW_AT_specification; + + if ( dwarf_attr( name_die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) { - /* Name will be hidden in a specification reference */ - attr_tag = DW_AT_specification; + dwarf_attr( name_die, attr_tag, &attr_data, 0 ); - if ( dwarf_attr( die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) + if ( DW_DLV_OK == dwarf_global_formref( attr_data, &specification_offset, 0 ) ) { - Dwarf_Off specification_offset; - Dwarf_Die specification_die; - dwarf_attr( die, attr_tag, &attr_data, 0 ); - - if ( DW_DLV_OK == dwarf_global_formref( attr_data, &specification_offset, 0 ) ) - { - dwarf_offdie_b( dbg, specification_offset, IS_INFO, &specification_die, 0 ); - dwarf_diename( specification_die, &name, 0 ); - } + dwarf_offdie_b( dbg, specification_offset, IS_INFO, &specification_die, 0 ); + dwarf_diename( specification_die, &name, 0 ); } } + } + if ( name && l && h ) + { p->func = ( struct symbolFunctionStore ** )realloc( p->func, sizeof( struct symbolFunctionStore * ) * ( p->nfunc + 1 ) ); newFunc = p->func[p->nfunc] = ( struct symbolFunctionStore * )calloc( 1, sizeof( struct symbolFunctionStore ) ); newFunc->isinline = isinline; @@ -432,10 +423,15 @@ static void _processFunctionDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die di newFunc->lowaddr = l; newFunc->highaddr = h - 1; + if ( manglename ) + { + newFunc->manglename = strdup( manglename ); + } + /* Collect start of function line and column */ attr_tag = DW_AT_decl_line; - if ( dwarf_attr( die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) + if ( dwarf_attr( specification_die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) { Dwarf_Unsigned no; dwarf_formudata( attr_data, &no, 0 ); @@ -444,7 +440,7 @@ static void _processFunctionDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die di attr_tag = DW_AT_decl_column; - if ( dwarf_attr( die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) + if ( dwarf_attr( specification_die, attr_tag, &attr_data, 0 ) == DW_DLV_OK ) { Dwarf_Unsigned no; dwarf_formudata( attr_data, &no, 0 ); @@ -455,7 +451,7 @@ static void _processFunctionDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die di // ==================================================================================================== -static void _processDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die, int level, int filenameN, int producerN, Dwarf_Addr cu_base_addr ) +static void _processDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die, int level, int filenameN,char *name, int producerN, Dwarf_Addr cu_base_addr ) { Dwarf_Half tag; @@ -463,6 +459,12 @@ static void _processDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die, int l Dwarf_Die sib = die; + // arm_exception is filename and funcname handle this + if ( strstr( name, "arm_exception" ) ) + { + _processFunctionDie(p,dbg,sib,filenameN,producerN,cu_base_addr); + } + while ( DW_DLV_OK == dwarf_siblingof_b( dbg, sib, IS_INFO, &sib, 0 ) ) { dwarf_tag( sib, &tag, 0 ); @@ -477,7 +479,7 @@ static void _processDie( struct symbol *p, Dwarf_Debug dbg, Dwarf_Die die, int l if ( DW_DLV_OK == dwarf_child( die, &child, 0 ) ) { - _processDie( p, dbg, child, level + 1, filenameN, producerN, cu_base_addr ); + _processDie( p, dbg, child, level + 1, filenameN,name, producerN, cu_base_addr ); dwarf_dealloc( dbg, child, DW_DLA_DIE ); } } @@ -541,6 +543,10 @@ static bool _readLines( struct symbol *p ) unsigned int filenameN; unsigned int producerN; + Dwarf_Addr h = 0; + Dwarf_Addr l = 0; + enum Dwarf_Form_Class formclass = DW_FORM_CLASS_UNKNOWN; + if ( 0 != dwarf_init_b( p->fd, DW_GROUPNUMBER_ANY, NULL, NULL, &dbg, &err ) ) { return false; @@ -551,7 +557,7 @@ static bool _readLines( struct symbol *p ) .dp_user_pointer = p, .dp_fptr = &_dwarf_print, .dp_buffer = _print_buffer, - .dp_buffer_len = MAX_LINE_LEN, + .dp_buffer_len = DP_MAX_LINE_LEN, .dp_buffer_user_provided = true, .dp_reserved = NULL @@ -582,6 +588,7 @@ static bool _readLines( struct symbol *p ) dwarf_siblingof_b( dbg, NULL, IS_INFO, &cu_die, 0 ); dwarf_diename( cu_die, &name, 0 ); + dwarf_die_text( cu_die, DW_AT_producer, &producer, 0 ); dwarf_die_text( cu_die, DW_AT_comp_dir, &compdir, 0 ); @@ -594,7 +601,7 @@ static bool _readLines( struct symbol *p ) /* Kickoff the process for the DIE and its children to get the functions in this cu */ dwarf_lowpc( cu_die, &cu_low_addr, 0 ); - _processDie( p, dbg, cu_die, 0, filenameN, producerN, cu_low_addr ); + _processDie( p, dbg, cu_die, 0, filenameN, name, producerN, cu_low_addr ); /* ...and the source lines */ _getSourceLines( p, dbg, cu_die ); @@ -602,78 +609,90 @@ static bool _readLines( struct symbol *p ) dwarf_dealloc( dbg, cu_die, DW_DLA_DIE ); } - /* 2: We have the lines and functions. Clean them up and interlink them so they're useful to applications */ - /* ------------------------------------------------------------------------------------------------------ */ - /* Sort tables into address order, just in case they're not ... no gaurantees from the DWARF */ - qsort( p->line, p->nlines, sizeof( struct symbolLineStore * ), _compareLineMem ); - qsort( p->func, p->nfunc, sizeof( struct symbolFunctionStore * ), _compareFunc ); - - /* Combine addresses in the lines table which have the same memory location...those aren't too useful for us */ - for ( int i = 1; i < p->nlines; i++ ) + if ( p->nlines && p->nfunc ) { - while ( ( i < p->nlines ) && ( ( p->line[i]->filename == p->line[i - 1]->filename ) ) && ( ( p->line[i]->lowaddr == p->line[i - 1]->lowaddr ) ) ) + /* 2: We have the lines and functions. Clean them up and interlink them so they're useful to applications */ + /* ------------------------------------------------------------------------------------------------------ */ + /* Sort tables into address order, just in case they're not ... no gaurantees from the DWARF */ + qsort( p->line, p->nlines, sizeof( struct symbolLineStore * ), _compareLineMem ); + qsort( p->func, p->nfunc, sizeof( struct symbolFunctionStore * ), _compareFunc ); + + /* Combine addresses in the lines table which have the same memory location...those aren't too useful for us */ + int nlines = 0; + struct symbolLineStore **nls = NULL; + + for ( int i = 0; i < p->nlines - 1; i++ ) { - /* This line needs to be freed in memory 'cos otherwise there is no reference to it anywhere */ - free( p->line[i - 1] ); + nls = ( struct symbolLineStore ** )realloc( nls, sizeof( struct symbolLineStore * ) * ( nlines + 1 ) ); + nls[nlines] = p->line[i]; - /* ...and move the following lines down */ - for ( int j = i; j < p->nlines; j++ ) + /* Roll forward through all lines which have the same start address */ + while ( ( ++i < p->nlines - 1 ) && + ( ( nls[nlines]->filename == p->line[i]->filename ) ) && + ( ( nls[nlines]->lowaddr == p->line[i]->lowaddr ) ) ) { - p->line[j - 1] = p->line[j]; + /* This line needs to be freed in memory 'cos otherwise there is no reference to it anywhere */ + free( p->line[i] ); } - p->nlines--; + nlines++; } - } - /* Now do the same for lines with the same line number and file */ - /* We can also set the high memory extent for each line here */ - for ( int i = 1; i < p->nlines; i++ ) - { - while ( ( i < p->nlines ) && - ( p->line[i]->startline == p->line[i - 1]->startline ) && - ( p->line[i]->filename == p->line[i - 1]->filename ) ) - { + free( p->line ); + p->line = nls; + p->nlines = nlines; - p->line[i]->lowaddr = p->line[i - 1]->lowaddr; - free( p->line[i - 1] ); + nlines = 0; + nls = NULL; - for ( int j = i; j < p->nlines; j++ ) + /* Now do the same for lines with the same line number and file */ + /* We can also set the high memory extent for each line here */ + for ( int i = 0; i < p->nlines - 1; i++ ) + { + nls = ( struct symbolLineStore ** )realloc( nls, sizeof( struct symbolLineStore * ) * ( nlines + 1 ) ); + nls[nlines] = p->line[i]; + + while ( ( ++i < p->nlines - 1 ) && + ( nls[nlines]->startline == p->line[i]->startline ) && + ( nls[nlines]->filename == p->line[i]->filename ) ) { - p->line[j - 1] = p->line[j]; + free( p->line[i] ); } - p->nlines--; + nls[nlines]->highaddr = p->line[i]->lowaddr - 1; + nlines++; } - p->line[i - 1]->highaddr = p->line[i]->lowaddr - 1; - } - - if ( !p->nlines ) - { - fprintf( stderr, "No lines found in file\n" ); - } - else - { - p->line[p->nlines - 1]->highaddr = p->line[p->nlines - 1]->lowaddr + 2; - p->line[0]->lowaddr = p->line[0]->highaddr - 2; + free( p->line ); + p->line = nls; + p->nlines = nlines; - /* Allocate lines to functions ... these will be in address order 'cos the lines already are */ - for ( int i = 0; i < p->nlines; i++ ) + if ( !p->nlines ) { - struct symbolFunctionStore *f = symbolFunctionAt( p, p->line[i]->lowaddr ); - p->line[i]->function = f; - p->line[i]->isinline = false; + fprintf( stderr, "No lines found in file\n" ); + } + else + { + p->line[p->nlines - 1]->highaddr = p->line[p->nlines - 1]->lowaddr + 2; + p->line[0]->lowaddr = p->line[0]->highaddr - 2; - if ( f ) + /* Allocate lines to functions ... these will be in address order 'cos the lines already are */ + for ( int i = 0; i < p->nlines; i++ ) { - f->line = ( struct symbolLineStore ** )realloc( f->line, sizeof( struct symbolLineStore * ) * ( f->nlines + 1 ) ); - f->line[f->nlines] = p->line[i]; - f->nlines++; + struct symbolFunctionStore *f = symbolFunctionAt( p, p->line[i]->lowaddr ); + p->line[i]->function = f; + p->line[i]->isinline = false; + + if ( f ) + { + f->line = ( struct symbolLineStore ** )realloc( f->line, sizeof( struct symbolLineStore * ) * ( f->nlines + 1 ) ); + f->line[f->nlines] = p->line[i]; + f->nlines++; + } } - } - retval = true; + retval = true; + } } dwarf_finish( dbg ); @@ -707,7 +726,13 @@ static bool _loadSource( struct symbol *p ) store->linetext[store->nlines++] = r; /* Spin forwards for next newline or eof */ - while ( ( l-- > 0 ) && ( *r++ != '\n' ) ) {}; + while ( ( --l > 0 ) && ( *r++ != '\n' ) ) {}; + + if ( l ) + { + *r++ = 0; + l--; + } } } @@ -911,6 +936,12 @@ void symbolDelete( struct symbol *p ) free( f->funcname ); } + if ( f->manglename ) + { + /* Remove the mangled name, assuming we have one */ + free( f->manglename ); + } + if ( f->line ) { /* ...and any source code cross-references */ @@ -957,11 +988,9 @@ void symbolDelete( struct symbol *p ) } // ==================================================================================================== - -char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbolMemaddr addr, symbolMemaddr *newaddr ) +char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbolMemaddr addr, symbolMemaddr *newaddr) /* Return assembly code representing this line */ - { cs_insn *insn; size_t count; @@ -977,7 +1006,7 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol if ( !p->caphandle ) { /* Disassembler isn't initialised yet */ - if ( cs_open( CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN, &p->caphandle ) != CS_ERR_OK ) + if ( cs_open( CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN + CS_MODE_MCLASS, &p->caphandle ) != CS_ERR_OK ) { return NULL; } @@ -993,10 +1022,10 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol return NULL; } + // This line disassembles the code with the handler initialised above count = cs_disasm( p->caphandle, m, 4, addr, 0, &insn ); *ic = LE_IC_NONE; - if ( count > 0 ) { /* Characterise the instruction using rules from F1.3 of ARM IHI0064H.a */ @@ -1008,18 +1037,30 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol *ic |= ( ( insn->id == ARM_INS_BL ) || ( insn->id == ARM_INS_BLX ) ) ? LE_IC_JUMP | LE_IC_CALL : 0; /* Was it a regular call? */ - *ic |= ( ( insn->id == ARM_INS_B ) || ( insn->id == ARM_INS_BX ) || ( insn->id == ARM_INS_ISB ) || + *ic |= ( ( insn->id == ARM_INS_B ) || ( insn->id == ARM_INS_BX ) || ( insn->id == ARM_INS_WFI ) || ( insn->id == ARM_INS_WFE ) || ( insn->id == ARM_INS_TBB ) || ( insn->id == ARM_INS_TBH ) || ( insn->id == ARM_INS_BXJ ) || ( insn->id == ARM_INS_CBZ ) || ( insn->id == ARM_INS_CBNZ ) || ( insn->id == ARM_INS_WFI ) || ( insn->id == ARM_INS_WFE ) ) ? LE_IC_JUMP : 0; - *ic |= ( ( ( ( insn->id == ARM_INS_SUB ) || ( insn->id == ARM_INS_MOV ) || - ( insn->id == ARM_INS_LDM ) || ( insn->id == ARM_INS_POP ) ) + ( insn->id == ARM_INS_LDM ) || ( insn->id == ARM_INS_POP ) || + ( insn->id == ARM_INS_ISB ) || ( insn->id == ARM_INS_ORR ) ) && strstr( insn->op_str, "pc" ) ) ) ? LE_IC_JUMP : 0; + *ic |= ( + ( ( insn->id == ARM_INS_ISB ) && strstr( insn->op_str, "sy" ) ) + ) ? LE_IC_SYNC_BARRIER : 0; + *ic |= (insn->id == ARM_INS_STC2L) ? LE_IC_COPROCESSOR : 0; + /* create a copy to check if load in pc */ + char *copy = strdup(insn->op_str); + *ic |= ( + ( ( ( insn->id == ARM_INS_LDR ) ) + && strstr(strtok(copy,","), "pc" ) ) + ) ? LE_IC_JUMP : 0; + /* free the copy */ + free(copy); /* Was it an exception return? */ *ic |= ( ( insn->id == ARM_INS_ERET ) ) ? LE_IC_JUMP | LE_IC_IRET : 0; @@ -1039,19 +1080,21 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol if ( detail->arm.op_count ) { - for ( int n = 0; n < insn->detail->arm.op_count; n++ ) { - if ( insn->detail->arm.operands[n].type == ARM_OP_IMM ) + if (n<2) { - *ic |= LE_IC_IMMEDIATE; - - if ( newaddr ) + if ( insn->detail->arm.operands[n].type == ARM_OP_IMM ) { - *newaddr = detail->arm.operands[0].imm; - } + *ic |= LE_IC_IMMEDIATE; + + if ( newaddr ) + { + *newaddr = detail->arm.operands[n].imm; + } - break; + break; + } } } } @@ -1069,7 +1112,6 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol } cs_free( insn, count ); - return op; } @@ -1103,7 +1145,7 @@ bool symbolSetValid( struct symbol *p ) // ==================================================================================================== -struct symbol *symbolAcquire( char *filename, bool loadlines, bool loadmem, bool loadsource ) +struct symbol *symbolAcquire( char *filename, bool loadmem, bool loadsource ) /* Collect symbol set with specified components */ @@ -1129,14 +1171,14 @@ struct symbol *symbolAcquire( char *filename, bool loadlines, bool loadmem, bool } /* Load the functions and source code line mappings if requested */ - if ( loadlines && !_readLines( p ) ) + if ( !_readLines( p ) ) { symbolDelete( p ); return NULL; } /* ...finally, the source code if requested. This can only be done if mem or functions we requested */ - if ( ( loadsource && ( loadmem || loadlines ) ) && !_loadSource( p ) ) + if ( ( loadsource && loadmem ) && !_loadSource( p ) ) { symbolDelete( p ); return NULL; @@ -1181,7 +1223,8 @@ bool _listFunctions( struct symbol *p, bool includeLines ) while ( f = symbolFunctionIndex( p, iter++ ) ) { - fprintf( stderr, MEMADDRF "..." MEMADDRF " %s ( %s %d,%d )" EOL, f->lowaddr, f->highaddr, f->funcname, symbolGetFilename( p, f->filename ), f->startline, f->startcol ); + fprintf( stderr, MEMADDRF "..." MEMADDRF " %s ( %s %d,%d ) %s" EOL, f->lowaddr, f->highaddr, f->funcname, symbolGetFilename( p, f->filename ), f->startline, f->startcol, + f->manglename ? f->manglename : "" ); if ( includeLines ) { @@ -1238,7 +1281,7 @@ void main( int argc, char *argv[] ) { enum instructionClass ic; - struct symbol *p = symbolAcquire( argv[1], true, true, true ); + struct symbol *p = symbolAcquire( argv[1], true, true ); if ( !p ) { @@ -1246,9 +1289,6 @@ void main( int argc, char *argv[] ) exit( -1 ); } - _listFunctions( p, false ); - exit( -1 ); - struct symbolLineStore *s; for ( int i = 0; i < p->nlines; i++ ) diff --git a/Src/traceDecoder_etm4.c b/Src/traceDecoder_etm4.c index 2d8d3e38..65c6bab2 100644 --- a/Src/traceDecoder_etm4.c +++ b/Src/traceDecoder_etm4.c @@ -26,6 +26,9 @@ enum TRACE_ETM4protoState TRACE_UNSYNCED, TRACE_IDLE, TRACE_GET_CYCLECOUNT, + TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT, + TRACE_GET_CYCLECOUNT_FORMAT_1_COUNT, + TRACE_GET_CYCLECOUNT_FORMAT_2, TRACE_WAIT_INFO, TRACE_GET_INFO_PLCTL, TRACE_GET_INFO_INFO, @@ -51,6 +54,9 @@ static const char *_protoStateName[] = "UNSYNCED", "IDLE", "GET_CYCLECOUNT", + "TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT", + "TRACE_GET_CYCLECOUNT_FORMAT_1_COUNT", + "GET_CYCLECOUNT_FORMAT_2", "WAIT_INFO", "GET_INFO_PLCTL", "GET_INFO_INFO", @@ -99,6 +105,7 @@ struct ETM4DecodeState uint32_t nextrhkey; /* Next rh key expected in the stream */ uint32_t spec; /* Max speculation depth to be expected */ uint32_t cyct; /* Cycnt threshold */ + bool cc_is_known; /* Indicator for Cycle Count Packet Format 1*/ uint8_t ex0; /* First info byte for exception */ @@ -109,7 +116,7 @@ struct ETM4DecodeState { uint64_t addr; enum InstSet inst; - } q[3]; /* Address queue for pushed addresses */ + } q[3]; /* Address queue for pushed addresses */ }; #define DEBUG(...) { if ( cpu->report ) cpu->report( V_DEBUG, __VA_ARGS__); } @@ -161,7 +168,6 @@ static void _stackQ( struct ETM4DecodeState *j ) } // ==================================================================================================== - static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu, uint8_t c ) /* Pump next byte into the protocol decoder */ @@ -180,13 +186,20 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu if ( ( j->asyncCount == 11 ) && ( c == 0x80 ) ) { DEBUG( "A-Sync Accumulation complete" EOL ); + _stateChange( cpu, EV_CH_ASYNC ); + retVal = TRACE_EV_MSG_RXED; j->rxedISYNC = true; - newState = TRACE_WAIT_INFO; + newState = TRACE_IDLE; + cpu->ASyncs++; } else { + if( c == 0x05 && j->asyncCount == 1) + { + cpu->overflows++; + DEBUG( "Overflow Detected. ReSync Trace Stream:" EOL ); + } j->asyncCount = c ? 0 : j->asyncCount + 1; - switch ( j->p ) { // ----------------------------------------------------- @@ -197,7 +210,22 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu case TRACE_IDLE: switch ( c ) { + case 0b00001111: + j->cc_is_known = false; + j->idx = 0; + newState = TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT; + break; + case 0b00001110: + j->cc_is_known = true; + j->idx = 0; + newState = TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT; + break; + case 0b00001100 ... 0b00001101: + j->idx = 0; + newState = TRACE_GET_CYCLECOUNT_FORMAT_2; + break; case 0b00000001: + j->idx = 0; newState = TRACE_GET_INFO_PLCTL; break; @@ -211,13 +239,11 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu cpu->disposition = c & 1; DEBUG( "Atom Format 1 [%b]", cpu->disposition ); - if ( cpu->addr != ADDRESS_UNKNOWN ) { retVal = TRACE_EV_MSG_RXED; _stateChange( cpu, EV_CH_ENATOMS ); } - break; case 0b11011000 ... 0b11011011: /* Atom Format 2, Figure 6-40, Pg 6-304 */ @@ -336,13 +362,15 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu case 0b11000000 ... 0b11010100: case 0b11100000 ... 0b11110100: /* Atom format 6, Figure 6-44, Pg 6.307 */ - cpu->eatoms = ( c & 0x1f ) + 3; + cpu->eatoms = ( c & 0x1f ) + 3 + 1; cpu->instCount = cpu->eatoms; - cpu->disposition = ( 1 << ( cpu->eatoms + 1 ) ) - 1; + cpu->disposition = ( 1 << ( cpu->eatoms ) ) - 1; + /* Deal with last instruction to be executed */ if ( c & ( 1 << 5 ) ) { - cpu->disposition &= 0xfffffffe; + DEBUG( "Got a non-execute" ); + cpu->disposition &= ~( 1 << ( cpu->eatoms - 1 ) ); cpu->eatoms--; cpu->natoms = 1; } @@ -402,6 +430,8 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu cpu->addr = j->q[match].addr; retVal = TRACE_EV_MSG_RXED; _stateChange( cpu, EV_CH_ADDRESS ); + _stackQ( j ); + j->q[0].addr = cpu->addr; break; case 0b10010101: /* Short address, IS0 short, Figure 6-32, Pg 6-294 */ @@ -556,8 +586,30 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu newState = TRACE_COMMIT; break; + case 0b00111000 ... 0b00111111: /* Cancel Format 3 Instruction trace packet */ + // Check if E Atom has occured (E atom indicates the instruction executed was a taken branch) + // uint32_t e_atom = ( c & 0x01 ); + // Get the amount of cancelled instructions + // int cancel_elements = (c & 0x06); + //retVal = TRACE_EV_MSG_RXED; + //newState = TRACE_IDLE; + //_stateChange( cpu, EV_CH_CANCELLED ); + //printf("Cancel Format 3 Instruction trace packet" EOL); + break; + default: - DEBUG( "Unknown element %02x in TRACE_IDLE" EOL, c ); + // catch short cycle count packet, where data and identifier are both in the header + if ( (c & 0xfc) == 0b00010000 ) + { + cpu->cycleCount += (c & 0x03)+j->cyct; + // Commit Elements not implemented + _stateChange( cpu, EV_CH_CYCLECOUNT ); + retVal = TRACE_EV_MSG_RXED; + } + else + { + DEBUG("Unknown element %02x in TRACE_IDLE" EOL, c ); + } break; } @@ -602,10 +654,14 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu case TRACE_GET_EXCEPTIONINFO2: cpu->exception = ( ( j->ex0 >> 1 ) & 0x1f ) | ( ( c & 0x1f ) << 5 ); + if (cpu->exception > 0b0000010111) + { + cpu->exception += -0b1000001000 + 8; + } cpu->serious = 0 != ( c & ( 1 << 5 ) ); _stateChange( cpu, EV_CH_EX_ENTRY ); - /* We aren't really returning idle, but we need to collect a standard formatted address packet */ + /* We aren't really returning idle, but we neued to collect a standard formatted address packet */ /* Then, when the address is delivered to the CPU Processor, it will have the EV_CH_EXCEPTION set */ /* too, which the code must recogise as setting a preferred return address. */ newState = TRACE_IDLE; @@ -683,7 +739,7 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu } else { - if ( j->idx == 8 ) + if ( j->idx == 9 ) { /* Second byte of IS1 case - mask MSB */ j->q[0].addr = ( j->q[0].addr & ( ~( 0x7F << j->idx ) ) ) | ( ( c & 0x7f ) << ( j->idx ) ); @@ -800,33 +856,61 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu break; // ----------------------------------------------------- - case TRACE_GET_TS_CC: /* Part of timestamp, Figure 6-7, Pg 6-264 */ - if ( j->idx < 2 ) + case TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT: + if( (c & 0x80) == 0x80 ) { - j->cntUpdate |= ( c & 0x7f ) << ( j->idx * 7 ); + // commit handling not implemented + newState = TRACE_GET_CYCLECOUNT_FORMAT_1_COMMIT; } else { - j->cntUpdate |= ( c & 0x7f ) << ( j->idx * 7 ); + if(j->cc_is_known) + { + newState = TRACE_GET_CYCLECOUNT_FORMAT_1_COUNT; + } + else + { + newState = TRACE_IDLE; + } } - - j->idx++; - - if ( ( j->idx == 3 ) || ( c & 0x80 ) ) + break; + + case TRACE_GET_CYCLECOUNT_FORMAT_1_COUNT: + if(j->idx==2) { - - cpu->cycleCount += j->cntUpdate; + cpu->cycleCount += ((c & 0x3f) << (j->idx*7)); + }else + { + cpu->cycleCount += ((c & 0x7f) << (j->idx*7)); + } + if( ((c & 0x80) == 0x80) && (j->idx!=2)) + { + newState = TRACE_GET_CYCLECOUNT_FORMAT_1_COUNT; + } + else + { + cpu->cycleCount += j->cyct; retVal = TRACE_EV_MSG_RXED; _stateChange( cpu, EV_CH_CYCLECOUNT ); newState = TRACE_IDLE; } + j->idx++; + break; + case TRACE_GET_CYCLECOUNT_FORMAT_2: + cpu->cycleCount += ( c & 0x0f ) + j->cyct; + retVal = TRACE_EV_MSG_RXED; + _stateChange( cpu, EV_CH_CYCLECOUNT ); + newState = TRACE_IDLE; break; + // ----------------------------------------------------- case TRACE_EXTENSION: switch ( c ) { + case 0b00000000: /* A-Sync packet */ + break; case 0b00000011: /* Discard packet, Figure 6.4, Pg 6-262 */ _stateChange( cpu, EV_CH_DISCARD ); _stateChange( cpu, EV_CH_TRACESTOP ); @@ -839,6 +923,8 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu case 0b00000111: /* Branch future flush */ break; + case 0b10000000: /* End of A-Sync packet*/ + DEBUG( "Reserved extension packet" EOL ); default: DEBUG( "Reserved extension packet" EOL ); break; @@ -939,7 +1025,6 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu if ( j->plctl & ( 1 << 3 ) ) { - _reportInfo( cpu, j ); newState = TRACE_GET_INFO_CYCT; } else @@ -951,6 +1036,27 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu break; + case TRACE_GET_INFO_CYCT: + if ( j->idx == 1 ) + { + j->cyct += ((c & 0x1f) << (j->idx*7)); + }else + { + j->cyct = ((c & 0x7f) << (j->idx*7)); + } + if ( ((c & 0x80) == 0x80) && (j->idx !=1)) + { + newState = TRACE_GET_INFO_CYCT; + } + else + { + _reportInfo( cpu, j ); + retVal = TRACE_EV_MSG_RXED; + newState = TRACE_IDLE; + } + j->idx++; + break; + // ----------------------------------------------------- default: