diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml index 68797735..cc3ade32 100644 --- a/.github/workflows/build-osx.yml +++ b/.github/workflows/build-osx.yml @@ -6,8 +6,9 @@ on: jobs: osx: - runs-on: macos-12 + runs-on: macos-14 steps: + - run: python3 -m pip config set global.break-system-packages true - run: brew install zmq sdl2 libelf - run: pip3 install meson - run: pip3 install ninja diff --git a/CHANGES.md b/CHANGES.md index 5b0cd5d7..a27bdca4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,20 @@ -In Progress (Version 2.2.0) - +Version 2.3.0 In progress +* Modify orblcd to receive shorter messages than word-length (if appropriate) +* Extend from-target timestamping to 1/10th microsecond resolution with rounding +* Add support for ITM rollover counters in orbtop (if they deliver information, they will be displayed) +* Add STM32 CORTEX-M33 support (Tested on STM32U5A5) +* Add communications pacing to orbtop for direct file reads +* Remove memory leak from orbtop +* Remove reference ro TPIU and ETM LAR's...they don't exist (per #156) +* Remove redundant access to DBGMCU on SAMD5 per #$157 +* Fix legacy port reflection when monitoring is not switched on it orbuculum +* Fixup bug in _processFunctionDie & other loadelf fixes +* Improve demangling of C++ names + +21st Sept 2024 (Version 2.2.0) + +* Add COBS draining state to re-sync as quickly as possible +* Report when client is disconnected for not keeping up * Addition of orbflow support (COBS over arbitary bearer with protocol on top) * Support for ORBTrace 1.4 series gateware * Support in-probe TPIU frame stripping diff --git a/Docs/BlackMagicProbe-Interface b/Docs/BlackMagicProbe-Interface index 11920f49..8a483d9a 100644 --- a/Docs/BlackMagicProbe-Interface +++ b/Docs/BlackMagicProbe-Interface @@ -4,10 +4,7 @@ Using the Black Magic Debug Probe When connecting to a Black Magic Debug probe the command line for Orbuculum will be something like; ->./orbuculum -b swo/ -c 0,text,c - -...which will create the fifo 'text' in a subdirectory swo of the current -directory, delivering SWO channel 0. The directory must exist already. +>./orbuculum -m 500 By default on BMP the SWO baudrate is 2.25MBps but that can be changed as an optional parameter to the monitor traceswo command at the gdb diff --git a/Inc/cobs.h b/Inc/cobs.h index 2b0827f7..a4199186 100644 --- a/Inc/cobs.h +++ b/Inc/cobs.h @@ -26,7 +26,8 @@ extern "C" { enum COBSPumpState { COBS_IDLE, - COBS_RXING + COBS_RXING, + COBS_DRAINING }; struct Frame diff --git a/Inc/generics.h b/Inc/generics.h index 7f1d8b23..1a7ff3e4 100644 --- a/Inc/generics.h +++ b/Inc/generics.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #define EOL "\n" @@ -20,6 +21,7 @@ extern "C" { #endif /* Error return codes .. may already be defined by ncurses */ +typedef int errcode; #ifndef OK #define OK 0 #endif @@ -97,7 +99,7 @@ char *genericsUnescape( char *str ); uint64_t genericsTimestampuS( void ); uint32_t genericsTimestampmS( void ); bool genericsSetReportLevel( enum verbLevel lset ); -void genericsPrintf( const char *fmt, ... ); +void genericsFPrintf( FILE *stream, const char *fmt, ... ); char *genericsGetBaseDirectory( void ); const char *genericsBasename( const char *n ); const char *genericsBasenameN( const char *n, int c ); diff --git a/Inc/orblcd_protocol.h b/Inc/orblcd_protocol.h index 30fa8081..d0b5fd49 100644 --- a/Inc/orblcd_protocol.h +++ b/Inc/orblcd_protocol.h @@ -14,19 +14,24 @@ #define ORBLCD_CMD_CLEAR (3) #define ORBLCD_CMD_GOTOXY (4) +#define LCD_BE (0) +#define LCD_LE (1) + #define ORBLCD_ENCODE_X(x) ((x&0xfff)<<0) #define ORBLCD_ENCODE_Y(x) ((x&0xfff)<<12) #define ORBLCD_ENCODE_D(x) ((x&0x03)<<24) #define ORBLCD_ENCODE_C(x) ((x&0x3f)<<26) +#define ORBLCD_ENCODE_L(x) ((x&0x01)<<31) #define ORBLCD_DECODE_X(x) ((x>>0)&0xfff) #define ORBLCD_DECODE_Y(x) ((x>>12)&0xfff) #define ORBLCD_DECODE_D(x) ((x>>24)&0x03) -#define ORBLCD_DECODE_C(x) ((x>>26)&0x3f) +#define ORBLCD_DECODE_C(x) ((x>>26)&0x1f) +#define ORBLCD_DECODE_L(x) ((x>>31)&0x01) #define ORBLCD_GET_DEPTH(x) (((int[]){1,8,16,24})[ORBLCD_DECODE_D(x)]) #define ORBLCD_PIXELS_PER_WORD(x) (((int[]){32,4,2,1})[ORBLCD_DECODE_D(x)]) -#define ORBLCD_OPEN_SCREEN(x,y,d) (ORBLCD_ENCODE_C(ORBLCD_CMD_INIT_LCD)|ORBLCD_ENCODE_D(d)|ORBLCD_ENCODE_X(x)|ORBLCD_ENCODE_Y(y)) +#define ORBLCD_OPEN_SCREEN(x,y,d,l) (ORBLCD_ENCODE_L(l)|ORBLCD_ENCODE_C(ORBLCD_CMD_INIT_LCD)|ORBLCD_ENCODE_D(d)|ORBLCD_ENCODE_X(x)|ORBLCD_ENCODE_Y(y)) #define ORBLCD_CLOSE_SCREEN (ORBLCD_ENCODE_C(ORBLCD_CMD_CLOSE_SCREEN)) #define ORBLCD_CLEAR (ORBLCD_ENCODE_C(ORBLCD_CMD_CLEAR)) diff --git a/Inc/symbols.h b/Inc/symbols.h index 19aa5548..1f3dd016 100644 --- a/Inc/symbols.h +++ b/Inc/symbols.h @@ -26,11 +26,11 @@ extern "C" { #define NO_FUNCTION 0xffffffff /* No function defined */ #define NO_DESTADDRESS 0xffffffe0 /* No address defined */ -#define SPECIALS_MASK 0xfffffff0 -#define FN_SLEEPING (SPECIALS_MASK|0xb) /* Marker for sleeping case */ +#define SPECIALS_MASK 0xffffff80 +#define FN_SLEEPING (SPECIALS_MASK|0xfb) /* Marker for sleeping case */ #define FN_SLEEPING_STR "** Sleeping **" /* String for sleeping case */ -#define INTERRUPT (SPECIALS_MASK|0xd) +#define INTERRUPT (SPECIALS_MASK|0xfd) #define FN_INTERRUPT_STR "INTERRUPT" enum symbolErr { SYMBOL_OK, SYMBOL_NOELF, SYMBOL_NOOBJDUMP, SYMBOL_UNSPECIFIED }; diff --git a/Inc/traceDecoder.h b/Inc/traceDecoder.h index a134f191..9063540d 100644 --- a/Inc/traceDecoder.h +++ b/Inc/traceDecoder.h @@ -143,6 +143,9 @@ struct TRACECPUState // Convinience, for debug reporting genericsReportCB report; + + // Debugging + uint64_t overflows; }; // ============================================================================ diff --git a/README.md b/README.md index 32f45296..cccb5d64 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ![Screenshot](https://raw.githubusercontent.com/orbcode/orbuculum/main/Docs/title.png) -This (orbflow) is the development branch for V2.2.0. Development is generally done in feature branches and folded into main as those features mature, but the changes in orbflow are significant and disruptive, with limited user visible benefit, so we want to keep them off main for a little while longer. +This is Orbuculum V2.2.0. Bugfixes for 2.2.x will be done in this branch. Development is generally done in feature branches and folded into main as those features mature - those are post 2.2.0. Version 2.2.0 builds on 2.1.0 and adds several new CPU families, improved client application handling and the start of ETM4 support. Stats and timing are also much improved and the whole communications subsystem has been simplified and streamlined. Most importantly though, we have moved from 'legacy' protocol (basically, the exact same protocol that flows from the chip) for communications to 'orbflow' protocol. Orbflow protocol is an extensible packet oriented protocol which provides a more compact representation of the probe data. By default orbflow is used transparently between orbuculum and client applications. If you have an ORBTrace 1.4.0 or higher version then it is also used for communication from the probe to orbuculum. If you have your own legacy applications, or a version of ORBTrace less that 1.4.0, then the system will fall back to legacy protocol transparently. You can have a hybrid arrangement where some clients use legacy protocol and some use orbflow no problem. As you might imagine this can quickly become complex so please yell up if any edge cases don't seem to work correctly! @@ -45,8 +45,6 @@ used as a base interface to the target by other programs in the suite. Generally this for the TRACE tool you're using and then you can just leave it running. It will grab data from the target and make it available to clients whenever it can. -* orbfifo: The fifo pump: Turns a trace feed into a set of fifos or, optionally, permanent files. - * orbcat: A simple cat utility for ITM channel data. * orbdump: A utility for dumping raw SWO data to a file for post-processing. @@ -98,7 +96,7 @@ from the target; * SEGGER JLink * generic USB TTL Serial Interfaces * FTDI High speed serial interfaces -* OpenOCD (Add a line like `tpiu config internal :3443 uart off 32000000` to your openocd config to use it.) +* OpenOCD (Add a line like `tpiu config internal :3443 uart off 32000000` to your openocd config to use it...more detailed configuration info at the bottom of this document) * PyOCD (Add options like `enable_swv: True`, `swv_system_clock: 32000000` to your `pyocd.yml` to use it.) * ECPIX-5 ECP5 Breakout Board for parallel trace * Anything capable of saving the raw SWO data to a file @@ -245,12 +243,21 @@ Building on Linux Dependencies ------------ * libusb-1.0 -* libczmq-dev -* ncurses -* libsdl +* cmake +* pkg-config +* libczmq5-dev +* ncurses-dev +* libsdl2-dev +* libzstd-dev * libelf-dev * libcapstone-dev +On Debian 12, at least, the following command should get you everything you need; + +``` +sudo apt-get install libusb-1.0-0-dev cmake pkg-config libczmq5-dev ncurses-dev libelf-dev libsdl2-dev libzstd-dev libcapstone-dev +``` + Build ----- @@ -275,7 +282,7 @@ A udev rules files is included in ```Support/60-orbcode.rules``` The default ins Building on OSX =============== -* `brew install libusb zmq sdl2` +* `brew install libusb zmq sdl2 libelf` If you are on an Intel Mac: @@ -412,7 +419,7 @@ probes are found you will get the option to choose between them. To avoid this c serial number for the probe you want to use on the command line. The command above will start the daemon with a monitor reporting interval of 100ms. Orbuculum exposes TCP ports 3402 and 3443 to which network clients can connect. 3402 delivers orbflow, 3443+x deliver raw frames. Both will relay to any -client that is connected (such as orbcat, orbfifo or orbtop). +client that is connected (such as orbcat or orbtop). The practical limit to the number of clients that can connect is set by the speed of the host machine....but there's nothing stopping you using another one on the local network :-) Orbuculum can optionally call out to `orbtrace` when a probe first connects. this is typically used to set configuration parameters for the problem. For example, if you've got an @@ -474,79 +481,6 @@ For `orbuculum`, the specific command line options of note are; `-t, --tag x,y,...`: List of streams to decode (and onward route) from the probe (low stream numbers are TPIU channels). *By default only stream 1 (ITM) is routed over legacy protocol, add additional streams via this command* - -Orbfifo -------- - -**Note:** `orbfifo` is not supported on Windows. Use `orbzmq` instead. - -The easiest way to use the output from orbuculum is with one of the utilities -such as `orbfifo`. This creates a set of fifos or permanent files in a given -directory containing the decoded streams which apps can exploit directly. It also has -a few other tricks up it's sleeve like filewriter capability. It used to be integrated into -`orbuculum` but seperating it out splits the trace interface from the user space utilities, this is a -Good Thing(tm). - -A typical command line would be; - -```>orbfifo -b swo/ -c 0,text,"%c" -v 1``` - -The directory 'swo/' is expected to already exist, into which will be placed -a file 'text' which delivers the output from swo channel 0 in character -format. Multiple -c options can be provided to set up fifos for individual channels -from the debug device. The format of the -c option is; - -```-c ChannelNum,ChannelName,FormatString``` - -ChannelNum is 0..31 and corresponds to the ITM channel. The name is the one -that will appear in the directory and the FormatString can present the data -using any printf-compatable formatting you prefer, so, the following are all -legal channel specifiers; - - -c 7,temperature,"%d \260C\n" - -c 2,hexAddress,"%08x," - -c 0,volume,"\l%d\b\n" - -Be aware that if you start making the formatting or screen handling too complex -its quite possible your machine might not keep up...and then the client will be dropped and you will loose data! - -While you've got `orbfifo` running a further fifo `hwevent` will be found in -the output directory, which reports on events from the hardware, one event per line as follows; - -* `0,[Status],[TS]` : Time status and timestamp. -* `1,[EventType],[ExceptionNumber]` : Hardware exception. Event type is one of [Enter, Exit, Resume]. -* `2,[PCAddr]` : Report Program Counter Sample. -* `3,[DWTEvent]` : Report on DWT event from the set [CPI,Exc,Sleep,LSU,Fold and Cyc]. -* `4,[Comp],[RW],[Data]` : Report Read/Write event. -* `5,[Comp],[Addr]` : Report data access watchpoint event. -* `6,[Comp],[Ofs]` : Report data offset event. -* `7` : Currently unused. -* `8,[Status],[Address]` : ISYNC event. - -The command line options are; - - `-b, --basedir [basedir]`: for channels, terminated with a trailing directory seperator, - so if you put xyz/chan then all ITM software channels will end up in a directory - xyz/chan. If xyz/chan doesn't exist, then channel creation will fail silently. - - `-c, --channel [Number],[Name],[Format]`: of channel to populate (repeat per channel) using printf formatting. - - `-E`: When reading from file, terminate when file exhausts, rather than waiting for more data to arrive. - - `-f, --input-file [filename]`: Take input from specified file (CTRL-C to abort from this). - - `-h, --help`: Brief help. - - `-P, --permanent`: Create permanent files rather than fifos - useful when you want to use the processed data later. - - `-s [address]:[port]`: Set address for Source connection, (default localhost:3443). - - `-t, --tag`: Which orbflow tag to use (normally 1). - - `-v, --verbose`: Verbose mode 0==Errors only, 1=Warnings (Default) 2=Info, 3=Full Debug. - - `-W, --writer-path [path]` : Enable filewriter functionality with output in specified directory (disabled by default). - Orbzmq ------ `orbzmq` is utility that connects to orbuculum over the network and outputs data from various ITM HW and SW channels that it finds. This output is sent over a [ZeroMQ](https://zeromq.org/) PUBLISH socket bound to the specified URL. Each published message is composed of two parts: **topic** and **payload**. Topic can be used by consumers to filter incoming messages, payload contains actual message data - for SW channels formatted or raw data and predefined format for HW channels. @@ -716,7 +650,8 @@ options for orbcat are; `-w, --window [string]`: Title for on-screen window. - + `-x, --exceptions`: Include exception information in output, in time order + Orbtop ------ @@ -737,7 +672,8 @@ line for orbtop would be; One useful command line option for orbtop (and indeed, for the majority of the rest of the suite) is `-s localhost:2332`, which will connect directly to any source you might have exporting -SWO data on its TCP its port, with no requirement for the orbuculum multiplexer in the way. +SWO data on its TCP its port, with no requirement for the orbuculum multiplexer in the way. If +you set the source explicitly, you also need to set the protocol explicitly using `-p`. Command line options for orbtop are; @@ -769,6 +705,10 @@ Command line options for orbtop are; `-O, --objdump-opts [opts]`: Set options to pass directly to objdump + `-p, --protocol [OFLOW|ITM]`: Protocol to communicate. Must be set explicitly if -s is set + + `-P, --pace `: Delay in block of data transmission to clients + `-r, --routines `: Number of lines to record in history file `-R, --report-file [filename]`: Report filenames as part of function discriminator @@ -1132,3 +1072,43 @@ In order to ease pain of this issue, Orbuculum distribution for Windows built on The later approach (file replacement) works fine for PyOCD (replace `libusb-1.0.dll` file in `/Lib/site-packages/libusb_package`) and fails to work with xPack OpenOCD (due to the way `libftdi.dll` is built). Please report both success (this will increase chances of merging patch to upstream libusb) and failures (so we will be able to identify and fix issues introduced by patch) with this approach. + +Notes on using orbuculum with openocd +===================================== + +Taylorh140 made some good notes about getting openocd working with orbuculum on a STM32F429 target. +They are repeated here; + +Openocd has a directory of scripts it uses for connecting. These are typically located in the +`..../share/scripts` folder so if you're connecting to a particular board or chip using one of +these you need to add a line to it to it. A typical file with line to open a tcp server listening to port 3443 +and let the SWV know that the cpu clock rate is 168Mhz would be; + +``` +source [find interface/stlink.cfg] +transport select hla_swd +set WORKAREASIZE 0x20000 +source [find target/stm32f4x.cfg] +reset_config srst_only + +tpiu config internal :3443 uart off 168000000 +``` + +You can then start openocd with a command like `openocd -f `. You might see a line +like `Info : DEPRECIATED 'tpiu config'` but that should be ok. You should now be able to connect +orb clients directly to openocd, something like; + +``` +> orbcat -s localhost:3443 -c0,"%c" +ABCDEFGHIJKLMNOPQRSTUVWXYZ +ABCDEFGHIJKLMNOPQRSTUVWXYZ +ABCDEFGHIJKL...etc +``` + +Things to try if this doesn't work; + +* make sure your device is connected +* make sure its powered on +* make sure there is no typo's in the .cfg file. +* make sure your application is running ('c' in gdb) +* get help from the openocd or orbuculum discord servers diff --git a/Src/cobs.c b/Src/cobs.c index be1c2930..36f4ae17 100644 --- a/Src/cobs.c +++ b/Src/cobs.c @@ -132,6 +132,14 @@ void COBSPump( struct COBS *t, const uint8_t *incoming, int len, break; + case COBS_DRAINING: // --------------------------------------------------------------- + if ( COBS_SYNC_CHAR == *fp ) + { + t->s = COBS_IDLE; + } + + break; + case COBS_RXING: // ------------------------------------------------------------------- t->intervalCount--; @@ -160,7 +168,7 @@ void COBSPump( struct COBS *t, const uint8_t *incoming, int len, if ( ( t->f.len > COBS_MAX_PACKET_LEN ) || ( COBS_SYNC_CHAR == *fp ) ) { t->error++; - t->s = COBS_IDLE; + t->s = COBS_DRAINING; } else { diff --git a/Src/generics.c b/Src/generics.c index ae8843d7..9a71c253 100644 --- a/Src/generics.c +++ b/Src/generics.c @@ -338,7 +338,7 @@ char *genericsGetBaseDirectory( void ) #endif } // ==================================================================================================== -void genericsPrintf( const char *fmt, ... ) +void genericsFPrintf( FILE *stream, const char *fmt, ... ) /* Print to output stream */ @@ -355,7 +355,7 @@ void genericsPrintf( const char *fmt, ... ) { if ( *p != CMD_ALERT[0] ) { - putc( *p++, stderr ); + putc( *p++, stream ); } else { @@ -367,7 +367,7 @@ void genericsPrintf( const char *fmt, ... ) case 'a'...'f': if ( _screenHandling ) { - fprintf( stderr, CC_COLOUR, _htoi( *p ) > 7, _htoi( *p ) & 7 ); + fprintf( stream, CC_COLOUR, _htoi( *p ) > 7, _htoi( *p ) & 7 ); } p++; @@ -376,7 +376,7 @@ void genericsPrintf( const char *fmt, ... ) case 'u': if ( _screenHandling ) { - fprintf( stderr, CC_PREV_LN ); + fprintf( stream, CC_PREV_LN ); } p++; @@ -385,7 +385,7 @@ void genericsPrintf( const char *fmt, ... ) case 'U': if ( _screenHandling ) { - fprintf( stderr, CC_CLR_LN ); + fprintf( stream, CC_CLR_LN ); } p++; @@ -394,7 +394,7 @@ void genericsPrintf( const char *fmt, ... ) case 'r': if ( _screenHandling ) { - fprintf( stderr, CC_RES ); + fprintf( stream, CC_RES ); } p++; @@ -402,7 +402,7 @@ void genericsPrintf( const char *fmt, ... ) case 'z': /* We'll take a flyer on it being vt100 compatible */ - fprintf( stderr, CC_CLEAR_SCREEN ); + fprintf( stream, CC_CLEAR_SCREEN ); p++; break; @@ -412,7 +412,7 @@ void genericsPrintf( const char *fmt, ... ) } } - fflush( stdout ); + fflush( stream ); } // ==================================================================================================== void genericsReport( enum verbLevel l, const char *fmt, ... ) @@ -426,13 +426,13 @@ void genericsReport( enum verbLevel l, const char *fmt, ... ) if ( l <= lstore ) { fflush( stdout ); - genericsPrintf( colours[l] ); + genericsFPrintf( stderr, colours[l] ); va_list va; va_start( va, fmt ); vsnprintf( op, MAX_STRLEN, fmt, va ); va_end( va ); - genericsPrintf( "%s", op ); - genericsPrintf( C_RESET ); + genericsFPrintf( stderr, "%s", op ); + genericsFPrintf( stderr, C_RESET ); fflush( stderr ); } } @@ -447,9 +447,9 @@ void genericsExit( int status, const char *fmt, ... ) va_start( va, fmt ); vsnprintf( op, MAX_STRLEN, fmt, va ); va_end( va ); - genericsPrintf( C_VERB_ERROR ); - genericsPrintf( op ); - genericsPrintf( C_RESET ); + genericsFPrintf( stderr, C_VERB_ERROR ); + genericsFPrintf( stderr, op ); + genericsFPrintf( stderr, C_RESET ); fflush( stderr ); exit( status ); diff --git a/Src/itmDecoder.c b/Src/itmDecoder.c index 2543a647..853c8730 100644 --- a/Src/itmDecoder.c +++ b/Src/itmDecoder.c @@ -14,6 +14,9 @@ #include "itmDecoder.h" #include "msgDecoder.h" +// Define this to get transitions printed out +#define DEBUG + #ifdef DEBUG #include #include "generics.h" @@ -28,7 +31,6 @@ #define MAX_PACKET (5) #define DEFAULT_PAGE_REGISTER (0x07) -// Define this to get transitions printed out // ==================================================================================================== struct ITMDecoder *ITMDecoderCreate( void ) diff --git a/Src/itmfifos.c b/Src/itmfifos.c deleted file mode 100644 index d4de0f2d..00000000 --- a/Src/itmfifos.c +++ /dev/null @@ -1,835 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ -/* - * Fifo support - * ============ - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "git_version_info.h" -#include "generics.h" -#include "itmDecoder.h" -#include "oflow.h" -#include "fileWriter.h" -#include "itmfifos.h" -#include "msgDecoder.h" - -#ifndef O_BINARY - #define O_BINARY 0 -#endif - -#define MAX_STRING_LENGTH (100) /* Maximum length that will be output from a fifo for a single event */ - -struct runThreadParams /* Structure for parameters passed to a software task thread */ -{ - int portNo; - int listenHandle; - bool permafile; - struct Channel *c; -}; - -struct Channel /* Information for an individual channel */ -{ - char *chanName; /* Filename to be used for the fifo */ - char *presFormat; /* Format of data presentation to be used */ - - /* Runtime state */ - int handle; /* Handle to the fifo */ - pthread_t thread; /* Thread on which it's running */ - struct runThreadParams params; /* Parameters for running thread */ - char *fifoName; /* Constructed fifo name (from chanPath and name) */ - bool ending; /* Flag indicating its time to disappear */ -}; - -struct itmfifosHandle - -{ - /* The decoders and the packets from them */ - struct ITMDecoder i; - struct ITMPacket h; - struct OFLOW ot; - enum timeDelay timeStatus; /* Indicator of if this time is exact */ - uint64_t timeStamp; /* Latest received time */ - - /* Timestamp info */ - uint64_t lastHWExceptionTS; - - /* Configuration information */ - char *chanPath; /* Path to where to put the fifos */ - bool filewriter; /* Is the filewriter in use? */ - bool forceITMSync; /* Is ITM to be forced into sync? */ - bool permafile; /* Use permanent files rather than fifos */ - int tag; /* Which OFLOW stream are we decoding? */ - bool amEnding; /* Flag indicating end is in progress */ - - enum Prot protocol; /* What protocol to communicate (default to OFLOW (== orbuculum)) */ - - struct Channel c[NUM_CHANNELS + 1]; /* Output for each channel */ -}; - - -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -// Private routines -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== - -// ==================================================================================================== -// Handlers for the fifos -// ==================================================================================================== -static void *_runFifo( void *arg ) - -/* This is the control loop for the channel fifos (for each software port) */ - -{ - struct runThreadParams *params = ( struct runThreadParams * )arg; - struct Channel *c = params->c; - struct swMsg m; - uint32_t w; - - char constructString[MAX_STRING_LENGTH]; - int opfile; - size_t readDataLen, writeDataLen, written = 0; - - assert( ¶ms->c->params == params ); - - /* Remove the file if it exists */ - unlink( c->fifoName ); - - if ( !params->permafile ) - { - /* This is a 'conventional' fifo, so it must be created */ - if ( mkfifo( c->fifoName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) < 0 ) - { - pthread_exit( NULL ); - } - } - - do - { - /* Keep on opening the file (in case the fifo is opened/closed multiple times) */ - /* We use RDWR to allow the open to proceed without a remote end */ - - if ( !params->permafile ) - { - opfile = open( c->fifoName, O_RDWR | O_BINARY | O_NONBLOCK ); - } - else - { - opfile = open( c->fifoName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); - } - - do - { - /* ....get the packet. This will hang here until a packet arrives or the link closes */ - readDataLen = read( params->listenHandle, &m, sizeof( struct swMsg ) ); - - if ( readDataLen < 0 ) - { - continue; - } - - if ( c->presFormat ) - { - // formatted output....start with specials - if ( strstr( c->presFormat, "%f" ) ) - { - /* type punning on same host, after correctly building 32bit val - * only unsafe on systems where u32/float have diff byte order */ - float *nastycast = ( float * )&m.value; - writeDataLen = snprintf( constructString, MAX_STRING_LENGTH, c->presFormat, *nastycast, *nastycast, *nastycast, *nastycast ); - } - else if ( strstr( c->presFormat, "%c" ) ) - { - /* Format contains %c, so execute repeatedly for all characters in sent data */ - writeDataLen = 0; - uint8_t op[4] = {m.value & 0xff, ( m.value >> 8 ) & 0xff, ( m.value >> 16 ) & 0xff, ( m.value >> 24 ) & 0xff}; - - uint32_t l = 0; - - do - { - writeDataLen += snprintf( &constructString[writeDataLen], MAX_STRING_LENGTH - writeDataLen, c->presFormat, op[l], op[l], op[l], op[l] ); - } - while ( ++l < m.len ); - } - else - { - writeDataLen = snprintf( constructString, MAX_STRING_LENGTH, c->presFormat, m.value, m.value, m.value, m.value ); - } - - written = write( opfile, constructString, ( writeDataLen < MAX_STRING_LENGTH ) ? writeDataLen : MAX_STRING_LENGTH ); - } - else - { - // raw output. - written = write( opfile, &w, sizeof ( w ) ); - } - } - while ( ( written > 0 ) && ( !c->ending ) ); - - /* Falling out on writen fail means we can re-open the fifo if it overflowed */ - close( opfile ); - } - while ( !c->ending ); - - pthread_exit( NULL ); -} -// ==================================================================================================== -static void *_runHWFifo( void *arg ) - -/* This is the control loop for the hardware fifo */ - -{ - struct runThreadParams *params = ( struct runThreadParams * )arg; - struct Channel *c = params->c; - int opfile; - size_t readDataLen = 0, writeDataLen = 0; - uint8_t p[MAX_STRING_LENGTH]; - - /* Remove the file if it exists */ - unlink( c->fifoName ); - - if ( !params->permafile ) - { - /* This is a 'conventional' fifo, so it must be created */ - if ( mkfifo( c->fifoName, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ) < 0 ) - { - pthread_exit( NULL ); - } - } - - do - { - if ( !params->permafile ) - { - /* We use RDWR to allow the open to proceed without a remote end */ - opfile = open( c->fifoName, O_RDWR | O_BINARY | O_NONBLOCK ); - } - else - { - opfile = open( c->fifoName, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); - } - - do - { - /* ....get the packet. We will hang here until a packet arrives or the link closes */ - readDataLen = read( params->listenHandle, p, MAX_STRING_LENGTH ); - - if ( readDataLen > 0 ) - { - writeDataLen = write( opfile, p, readDataLen ); - } - } - while ( ( writeDataLen > 0 ) && ( !c->ending ) ); - - /* Falling out on writeDataLen fail means we can re-open the fifo if it overflowed */ - close( opfile ); - } - while ( !c->ending ); - - pthread_exit( NULL ); -} -// ==================================================================================================== -// Decoders for each message -// ==================================================================================================== -void _handleException( struct excMsg *m, struct itmfifosHandle *f ) - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - const char *exNames[] = {"Thread", "Reset", "NMI", "HardFault", "MemManage", "BusFault", "UsageFault", "UNKNOWN_7", - "UNKNOWN_8", "UNKNOWN_9", "UNKNOWN_10", "SVCall", "Debug Monitor", "UNKNOWN_13", "PendSV", "SysTick" - }; - const char *exEvent[] = {"Unknown", "Enter", "Exit", "Resume"}; - - f->lastHWExceptionTS = m->ts; - - if ( m->exceptionNumber < 16 ) - { - /* This is a system based exception */ - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64 ",%s,%s" EOL, HWEVENT_EXCEPTION, eventdifftS, exEvent[m->eventType & 0x03], exNames[m->exceptionNumber & 0x0F] ); - } - else - { - /* This is a CPU defined exception */ - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64 ",%s,External,%d" EOL, HWEVENT_EXCEPTION, eventdifftS, exEvent[m->eventType & 0x03], m->exceptionNumber - 16 ); - } - - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _handleDWTEvent( struct dwtMsg *m, struct itmfifosHandle *f ) - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - -#define NUM_EVENTS 6 - const char *evName[NUM_EVENTS] = {"CPI", "Exc", "Sleep", "LSU", "Fold", "Cyc"}; - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - f->lastHWExceptionTS = m->ts; - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64, HWEVENT_DWT, eventdifftS ); - - for ( uint32_t i = 0; i < NUM_EVENTS; i++ ) - { - if ( m->event & ( 1 << i ) ) - { - // Copy this event into the output string - outputString[opLen++] = ','; - const char *u = evName[i]; - - do - { - outputString[opLen++] = *u++; - } - while ( *u ); - } - } - - write( f->c[HW_CHANNEL].handle, outputString, opLen ); - write( f->c[HW_CHANNEL].handle, EOL, strlen( EOL ) ); -} -// ==================================================================================================== -void _handlePCSample( struct pcSampleMsg *m, struct itmfifosHandle *f ) - -/* We got a sample of the PC */ - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - f->lastHWExceptionTS = m->ts; - - if ( m->sleep ) - { - /* This is a sleep packet */ - opLen = snprintf( outputString, ( MAX_STRING_LENGTH - 1 ), "%d,%" PRIu64 ",**SLEEP**" EOL, HWEVENT_PCSample, eventdifftS ); - } - else - { - opLen = snprintf( outputString, ( MAX_STRING_LENGTH - 1 ), "%d,%" PRIu64 ",0x%08x" EOL, HWEVENT_PCSample, eventdifftS, m->pc ); - } - - /* We don't need to worry if this write does not succeed, it just means there is no other side of the fifo */ - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _handleDataRWWP( struct watchMsg *m, struct itmfifosHandle *f ) - -/* We got an alert due to a watch pointer */ - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - f->lastHWExceptionTS = m->ts; - - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64 ",%d,%s,0x%x" EOL, HWEVENT_RWWT, eventdifftS, m->comp, m->isWrite ? "Write" : "Read", m->data ); - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _handleDataAccessWP( struct wptMsg *m, struct itmfifosHandle *f ) - -/* We got an alert due to a watchpoint */ - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - f->lastHWExceptionTS = m->ts; - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64 ",%d,0x%08x" EOL, HWEVENT_AWP, eventdifftS, m->comp, m->data ); - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _handleDataOffsetWP( struct oswMsg *m, struct itmfifosHandle *f ) - -/* We got an alert due to an offset write event */ - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - uint64_t eventdifftS = m->ts - f->lastHWExceptionTS; - - f->lastHWExceptionTS = m->ts; - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%" PRIu64 ",%d,0x%04x" EOL, HWEVENT_OFS, eventdifftS, m->comp, m->offset ); - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _handleSW( struct swMsg *m, struct itmfifosHandle *f ) - -{ - /* Filter off filewriter packets and let the filewriter module deal with those */ - if ( ( m->srcAddr == FW_CHANNEL ) && ( f->filewriter ) ) - { - filewriterProcess( m ); - } - else - { - if ( ( m->srcAddr < NUM_CHANNELS ) && ( f->c[m->srcAddr].handle ) ) - { - write( f->c[m->srcAddr].handle, m, sizeof( struct swMsg ) ); - } - } -} -// ==================================================================================================== -void _handleNISYNC( struct nisyncMsg *m, struct itmfifosHandle *f ) - -{ - char outputString[MAX_STRING_LENGTH]; - int opLen; - - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%02x,0x%08x" EOL, HWEVENT_NISYNC, m->type, m->addr ); - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} - -// ==================================================================================================== -void _handleTS( struct TSMsg *m, struct itmfifosHandle *f ) - -/* ... a timestamp */ - -{ - assert( m->msgtype == MSG_TS ); - char outputString[MAX_STRING_LENGTH]; - int opLen; - - f->timeStamp += m->timeInc; - f->timeStatus = m->timeStatus; - - opLen = snprintf( outputString, MAX_STRING_LENGTH, "%d,%d,%" PRIu32 EOL, HWEVENT_TS, m->timeStatus, m->timeInc ); - write( f->c[HW_CHANNEL].handle, outputString, opLen ); -} -// ==================================================================================================== -void _itmPumpProcess( struct itmfifosHandle *f, char c ) - -/* Handle individual characters into the itm decoder */ - -{ - struct msg decoded; - - typedef void ( *handlers )( void *, struct itmfifosHandle * f ); - - /* Handlers for each complete message received */ - static const handlers h[MSG_NUM_MSGS] = - { - /* MSG_UNKNOWN */ NULL, - /* MSG_RESERVED */ NULL, - /* MSG_ERROR */ NULL, - /* MSG_NONE */ NULL, - /* MSG_SOFTWARE */ ( handlers )_handleSW, - /* MSG_NISYNC */ ( handlers )_handleNISYNC, - /* MSG_OSW */ ( handlers )_handleDataOffsetWP, - /* MSG_DATA_ACCESS_WP */ ( handlers )_handleDataAccessWP, - /* MSG_DATA_RWWP */ ( handlers )_handleDataRWWP, - /* MSG_PC_SAMPLE */ ( handlers )_handlePCSample, - /* MSG_DWT_EVENT */ ( handlers )_handleDWTEvent, - /* MSG_EXCEPTION */ ( handlers )_handleException, - /* MSG_TS */ ( handlers )_handleTS - }; - - switch ( ITMPump( &f->i, c ) ) - { - // ------------------------------------ - case ITM_EV_NONE: - break; - - // ------------------------------------ - case ITM_EV_UNSYNCED: - genericsReport( V_WARN, "ITM Lost Sync (%d)" EOL, ITMDecoderGetStats( &f->i )->lostSyncCount ); - break; - - // ------------------------------------ - case ITM_EV_SYNCED: - genericsReport( V_INFO, "ITM In Sync (%d)" EOL, ITMDecoderGetStats( &f->i )->syncCount ); - break; - - // ------------------------------------ - case ITM_EV_OVERFLOW: - genericsReport( V_WARN, "ITM Overflow (%d)" EOL, ITMDecoderGetStats( &f->i )->overflow ); - break; - - // ------------------------------------ - case ITM_EV_ERROR: - genericsReport( V_WARN, "ITM Error" EOL ); - break; - - // ------------------------------------ - case ITM_EV_PACKET_RXED: - ITMGetDecodedPacket( &f->i, &decoded ); - - /* See if we decoded a dispatchable match. genericMsg is just used to access */ - /* the first two members of the decoded structs in a portable way. */ - if ( h[decoded.genericMsg.msgtype] ) - { - ( h[decoded.genericMsg.msgtype] )( &decoded, f ); - } - - break; - - // ------------------------------------ - } -} -// ==================================================================================================== - -static void _OFLOWpacketRxed ( struct OFLOWFrame *p, void *param ) - -{ - struct itmfifosHandle *f = ( struct itmfifosHandle * )param; - - if ( !p->good ) - { - genericsReport( V_INFO, "Bad packet received" EOL ); - } - else - { - if ( p->tag == f->tag ) - { - for ( int i = 0; i < p->len; i++ ) - { - _itmPumpProcess( f, p->d[i] ); - } - } - } -} - -// ==================================================================================================== - -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -// Public interface -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== - -// ==================================================================================================== -// Getters and Setters -// ==================================================================================================== -void itmfifoSetChanPath( struct itmfifosHandle *f, char *s ) - -{ - if ( f->chanPath ) - { - free( f->chanPath ); - } - - f->chanPath = s ? strdup( s ) : NULL; -} - -// ==================================================================================================== -// strdup leak is deliberately ignored. That is the central purpose of this code! -#pragma GCC diagnostic push -#if !defined(__clang__) - #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" -#endif - -void itmfifoSetChannel( struct itmfifosHandle *f, int chan, char *n, char *s ) - -{ - assert( chan <= NUM_CHANNELS ); - - if ( f->c[chan].presFormat ) - { - free( f->c[chan].presFormat ); - } - - if ( f->c[chan].chanName ) - { - free( f->c[chan].chanName ); - } - - f->c[chan].chanName = strdup( n ); - - MEMCHECKV( f->c[chan].chanName ); - f->c[chan].presFormat = s ? strdup( s ) : NULL; - - MEMCHECKV( f->c[chan].presFormat ); -} -#pragma GCC diagnostic pop -// ==================================================================================================== -void itmfifoSetProtocol( struct itmfifosHandle *f, enum Prot p ) - -{ - f->protocol = p; -} -// ==================================================================================================== -void itmfifoSetForceITMSync( struct itmfifosHandle *f, bool s ) - -{ - f->forceITMSync = s; -} -// ==================================================================================================== -void itmfifoSettag( struct itmfifosHandle *f, int stream ) - -{ - f->tag = stream; -} -// ==================================================================================================== -char *itmfifoGetChannelName( struct itmfifosHandle *f, int chan ) - -{ - assert( chan <= NUM_CHANNELS ); - return f->c[chan].chanName; -} -// ==================================================================================================== -char *itmfifoGetChannelFormat( struct itmfifosHandle *f, int chan ) - -{ - assert( chan <= NUM_CHANNELS ); - return f->c[chan].chanName; -} -// ==================================================================================================== -char *itmfifoGetChanPath( struct itmfifosHandle *f ) - -{ - return f->chanPath; -} -// ==================================================================================================== -enum Prot itmfifoGetProtocol( struct itmfifosHandle *f ) - -{ - return f->protocol; -} -// ==================================================================================================== -bool itmfifoGetForceITMSync( struct itmfifosHandle *f ) - -{ - return f->forceITMSync; -} -// ==================================================================================================== -int itmfifoGettag( struct itmfifosHandle *f ) - -{ - return f->tag; -} -// ==================================================================================================== -struct ITMDecoderStats *fifoGetITMDecoderStats( struct itmfifosHandle *f ) - -{ - return ITMDecoderGetStats( &f->i ); -} -// ==================================================================================================== -// Main interface components -// ==================================================================================================== -void itmfifoProtocolPump( struct itmfifosHandle *f, uint8_t *c, int len ) - -/* Top level protocol pump */ - -{ - - if ( PROT_OFLOW == f->protocol ) - { - OFLOWPump( &f->ot, c, len, _OFLOWpacketRxed, f ); - } - else - while ( len-- ) - { - /* There's no TPIU in use, so this goes straight to the ITM layer */ - _itmPumpProcess( f, *c++ ); - } -} -// ==================================================================================================== -void itmfifoForceSync( struct itmfifosHandle *f, bool synced ) - -/* Reset and put ITM into defined state */ - -{ - ITMDecoderForceSync( &f->i, synced ); -} -// ==================================================================================================== -bool itmfifoCreate( struct itmfifosHandle *f ) - -/* Create each sub-process that will handle a port */ - -{ - int fd[2]; - - /* Make sure there's an initial timestamp to work with */ - f->lastHWExceptionTS = genericsTimestampuS(); - - /* Reset the handler before we start */ - OFLOWInit( &f->ot ); - ITMDecoderInit( &f->i, f->forceITMSync ); - - /* Cycle through channels and create a fifo for each one that is enabled */ - for ( int t = 0; t < ( NUM_CHANNELS + 1 ); t++ ) - { - if ( t < NUM_CHANNELS ) - { - if ( f->c[t].chanName ) - { - /* This is a live software channel fifo */ - if ( pipe( fd ) < 0 ) - { - return false; - } - - if ( !f->permafile ) - { - /* If this is not a permanent file then some data is allowed to get lost */ - fcntl( fd[1], F_SETFL, O_NONBLOCK ); - } - - f->c[t].handle = fd[1]; - f->c[t].ending = false; - - f->c[t].params.listenHandle = fd[0]; - f->c[t].params.portNo = t; - f->c[t].params.permafile = f->permafile; - f->c[t].params.c = &f->c[t]; - - f->c[t].fifoName = ( char * )calloc( strlen( f->c[t].chanName ) + 2 + ( f->chanPath ? strlen( f->chanPath ) : 0 ), 1 ); - - if ( f->chanPath ) - { - strcpy( f->c[t].fifoName, f->chanPath ); - strcat( f->c[t].fifoName, "/" ); - } - - strcat( f->c[t].fifoName, f->c[t].chanName ); - - if ( pthread_create( &( f->c[t].thread ), NULL, &_runFifo, &( f->c[t].params ) ) ) - { - return false; - } - } - } - else - { - /* This is the hardware fifo channel */ - if ( pipe( fd ) < 0 ) - { - return false; - } - - if ( !f->permafile ) - { - /* If this is not a permanent file then some data is allowed to get lost */ - fcntl( fd[1], F_SETFL, O_NONBLOCK ); - } - - f->c[t].handle = fd[1]; - - f->c[t].params.listenHandle = fd[0]; - f->c[t].params.portNo = t; - f->c[t].params.permafile = f->permafile; - f->c[t].params.c = &f->c[t]; - - f->c[t].fifoName = ( char * )calloc( strlen( HWFIFO_NAME ) + 2 + ( ( f->chanPath ) ? strlen( f->chanPath ) : 0 ), 1 ); - - if ( f->chanPath ) - { - strcpy( f->c[t].fifoName, f->chanPath ); - strcat( f->c[t].fifoName, "/" ); - } - - strcat( f->c[t].fifoName, HWFIFO_NAME ); - - if ( pthread_create( &( f->c[t].thread ), NULL, &_runHWFifo, &( f->c[t].params ) ) ) - { - return false; - } - } - } - - return true; -} -// ==================================================================================================== -void itmfifoShutdown( struct itmfifosHandle *f ) - -/* Destroy the per-port sub-processes. These will terminate when the fifos close */ - -{ - if ( f->amEnding ) - { - return; - } - - f->amEnding = true; - - /* Firstly go tell everything they're doomed */ - for ( int t = 0; t < NUM_CHANNELS + 1; t++ ) - { - f->c[t].ending = true; - - if ( f->c[t].handle > 0 ) - { - /* This will cause the read to end, thus terminating the pthread */ - close( f->c[t].handle ); - } - } - - /* ...now clean up */ - for ( int t = 0; t < NUM_CHANNELS + 1; t++ ) - { - if ( f->c[t].handle > 0 ) - { - pthread_join( f->c[t].thread, NULL ); - - if ( ! f->permafile ) - { - unlink( f->c[t].fifoName ); - } - } - - /* Remove the name string too */ - if ( f->c[t].presFormat ) - { - free( f->c[t].presFormat ); - } - } -} -// ==================================================================================================== - -void itmfifoFilewriter( struct itmfifosHandle *f, bool useFilewriter, char *workingPath ) - -{ - f->filewriter = useFilewriter; - - if ( f->filewriter ) - { - filewriterInit( workingPath ); - } -} - -// ==================================================================================================== -void itmfifoUsePermafiles( struct itmfifosHandle *f, bool usePermafilesSet ) - -{ - f->permafile = usePermafilesSet; -} -// ==================================================================================================== -struct itmfifosHandle *itmfifoInit( bool forceITMSyncSet, enum Prot p, int tag ) - -{ - struct itmfifosHandle *f = ( struct itmfifosHandle * )calloc( 1, sizeof( struct itmfifosHandle ) ); - - MEMCHECK( f, NULL ); - - f->chanPath = strdup( "" ); - f->protocol = p; - f->forceITMSync = forceITMSyncSet; - f->tag = tag; - return f; -} -// ==================================================================================================== diff --git a/Src/loadelf.c b/Src/loadelf.c index ea3295a1..e10652c0 100644 --- a/Src/loadelf.c +++ b/Src/loadelf.c @@ -369,15 +369,16 @@ 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 ); - 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; + } } + dwarf_highpc_b ( die, &h, 0, &formclass, 0 ); + dwarf_lowpc ( die, &l, 0 ); + if ( formclass == DW_FORM_CLASS_CONSTANT ) { h += l; @@ -1001,7 +1002,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; } @@ -1044,6 +1045,14 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol && strstr( insn->op_str, "pc" ) ) ) ? LE_IC_JUMP : 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( copy ); + /* Was it an exception return? */ *ic |= ( ( insn->id == ARM_INS_ERET ) ) ? LE_IC_JUMP | LE_IC_IRET : 0; @@ -1072,7 +1081,7 @@ char *symbolDisassembleLine( struct symbol *p, enum instructionClass *ic, symbol if ( newaddr ) { - *newaddr = detail->arm.operands[0].imm; + *newaddr = detail->arm.operands[n].imm; } break; diff --git a/Src/msgDecoder.c b/Src/msgDecoder.c index 1f982932..610b7092 100644 --- a/Src/msgDecoder.c +++ b/Src/msgDecoder.c @@ -36,7 +36,7 @@ static bool _handleDWTEvent( struct ITMPacket *packet, struct dwtMsg *decoded ) { decoded->msgtype = MSG_DWT_EVENT; - decoded->event = packet->d[1] & 0x2F; + decoded->event = packet->d[0] & 0x2F; return true; } // ==================================================================================================== @@ -207,17 +207,17 @@ static bool _handleTS( struct ITMPacket *packet, struct TSMsg *decoded ) if ( packet->len > 2 ) { - stamp |= ( packet->d[2] ) << 7; + stamp |= ( packet->d[2] & 0x7F ) << 7; + } - if ( packet->len > 3 ) - { - stamp |= ( packet->d[3] & 0x7F ) << 14; + if ( packet->len > 3 ) + { + stamp |= ( packet->d[3] & 0x7F ) << 14; + } - if ( packet->len > 4 ) - { - stamp |= ( packet->d[4] & 0x7f ) << 21; - } - } + if ( packet->len > 4 ) + { + stamp |= ( packet->d[4] & 0x7f ) << 21; } } diff --git a/Src/nwclient.c b/Src/nwclient.c index 085c7f21..7011374c 100644 --- a/Src/nwclient.c +++ b/Src/nwclient.c @@ -69,7 +69,7 @@ struct nwClient volatile struct nwClient *prevClient; /* Parameters used to run the client */ - int portNo; /* Port of connection */ + int fdNo; /* file descriptor of incoming connection */ }; // ==================================================================================================== @@ -105,7 +105,7 @@ static int _lock_with_timeout( pthread_mutex_t *mutex, const struct timespec *ts static void _clientRemoveNoLock( volatile struct nwClient *c ) { - close( c->portNo ); + close( c->fdNo ); if ( c->prevClient ) { @@ -154,14 +154,14 @@ static void *_listenTask( void *arg ) } inet_ntop( AF_INET, &cli_addr.sin_addr, s, 99 ); - genericsReport( V_INFO, "New connection from %s" EOL, s ); + genericsReport( V_INFO, "New connection from %s index %d" EOL, s, newsockfd ); /* We got a new connection - spawn a record to handle it */ client = ( struct nwClient * )calloc( 1, sizeof( struct nwClient ) ); MEMCHECK( client, NULL ); client->parent = h; - client->portNo = newsockfd; + client->fdNo = newsockfd; /* Make port non-blocking */ #ifdef WIN32 @@ -235,13 +235,14 @@ void nwclientSend( struct nwclientsHandle *h, uint32_t len, const uint8_t *ipbuf while ( t && ( sent >= 0 ) ) { - sent = send( n->portNo, p, t, MSG_NOSIGNAL ); + sent = send( n->fdNo, p, t, MSG_NOSIGNAL ); p += sent; t -= sent; } if ( t ) { + genericsReport( V_INFO, "Killed connection index %d" EOL, n->fdNo ); volatile struct nwClient *newn = n->nextClient; _clientRemoveNoLock( n ); n = newn; diff --git a/Src/orbcat.c b/Src/orbcat.c index 66951182..81ac7fc4 100644 --- a/Src/orbcat.c +++ b/Src/orbcat.c @@ -28,9 +28,8 @@ #include "oflow.h" #define NUM_CHANNELS 32 -#define HW_CHANNEL (NUM_CHANNELS) /* Make the hardware fifo on the end of the software ones */ -#define MAX_STRING_LENGTH (4096) /* Maximum length that will be output */ +#define MAX_STRING_LENGTH (4096*4) /* Maximum length that will be output */ #define DEFAULT_TS_TRIGGER '\n' /* Default trigger character for timestamp output */ #define MSG_REORDER_BUFLEN (10) /* Maximum number of samples to re-order for timekeeping */ @@ -46,7 +45,8 @@ #define ABS_FORMAT C_TSTAMP "%s.%03" PRIu64"|" C_RESET #define STAMP_FORMAT C_TSTAMP "%12" PRIu64 "|" C_RESET #define STAMP_FORMAT_MS C_TSTAMP "%8" PRIu64 ".%03" PRIu64 "_%03" PRIu64 "|" C_RESET -#define STAMP_FORMAT_MS_DELTA C_TSTAMP "%5" PRIu64 ".%03" PRIu64 "_%03" PRIu64 "|" C_RESET +//#define STAMP_FORMAT_MS_DELTA C_TSTAMP "%5" PRIu64 ".%03" PRIu64 "_%03" PRIu64 "|" C_RESET +#define STAMP_FORMAT_MS_DELTA C_TSTAMP "%5" PRIu64 ".%03" PRIu64 "_%03" PRIu64 "_%01" PRIu64 "|" C_RESET enum TSType { TSNone, TSAbsolute, TSRelative, TSDelta, TSStamp, TSStampDelta, TSNumTypes }; @@ -217,8 +217,9 @@ static void _printTimestamp( char *strstore ) if ( options.cps ) { - uint64_t tms = ( delta * 1000000 ) / options.cps; - sprintf( strstore, STAMP_FORMAT_MS_DELTA, tms / 1000000, ( tms / 1000 ) % 1000, tms % 1000 ); + /* Provide some rounding .. we're at the limits of what's sensible here */ + uint64_t tms = ( delta * 10000000 + options.cps / 2 ) / options.cps; + sprintf( strstore, STAMP_FORMAT_MS_DELTA, tms / 10000000, ( tms / 10000 ) % 10000, ( tms / 10 ) % 1000, tms % 10 ); } else { @@ -246,7 +247,7 @@ static void _outputText( char *p ) if ( !_r.inLine ) { _printTimestamp( opConstruct ); - genericsPrintf( "%s", opConstruct ); + genericsFPrintf( stdout, "%s", opConstruct ); _r.inLine = true; } @@ -256,21 +257,21 @@ static void _outputText( char *p ) if ( q ) { *q = 0; - genericsPrintf( "%s" EOL, p ); + genericsFPrintf( stdout, "%s" EOL, p ); /* Once we've output these data then we're not in a line any more */ _r.inLine = false; /* ...and if there were any DWT messages to print we'd better output those */ if ( _r.dwtText[0] ) { - genericsPrintf( "%s" EOL, _r.dwtText ); + genericsFPrintf( stdout, "%s" EOL, _r.dwtText ); _r.dwtText[0] = 0; } } else { /* Just output the whole of the data we've got, then we're done */ - genericsPrintf( "%s", p ); + genericsFPrintf( stdout, "%s", p ); break; } @@ -296,7 +297,7 @@ void _expex( const char *fmt, ... ) /* See if we exceeded max length...if so then output what we have and start a fresh buffer */ if ( MAX_STRING_LENGTH - strlen( _r.dwtText ) < 100 ) { - genericsPrintf( "%s", _r.dwtText ); + genericsFPrintf( stdout, "%s", _r.dwtText ); _r.dwtText[0] = 0; } @@ -310,7 +311,7 @@ void _expex( const char *fmt, ... ) if ( !_r.inLine ) { - genericsPrintf( "%s", _r.dwtText ); + genericsFPrintf( stdout, "%s", _r.dwtText ); _r.dwtText[0] = 0; } } @@ -549,30 +550,30 @@ static void _itmPumpProcess( char c ) static void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -c, --channel: , of channel to add into output stream (repeat per channel)" EOL ); - genericsPrintf( " -C, --cpufreq: (Scaled) speed of the CPU" EOL - " generally /1, /4, /16 or /64 of the real CPU speed," EOL ); - genericsPrintf( " -E, --eof: Terminate when the file/socket ends/is closed, or wait for more/reconnect" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -g, --trigger: to use to trigger timestamp (default is newline)" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: : Which orbflow tag to use (normally 1)" EOL ); - genericsPrintf( " -T, --timestamp: : Add absolute, relative (to session start)," EOL - " delta, system timestamp or system timestamp delta to output. Note" EOL - " the accuracy of a,r & d are host dependent." EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -x, --exceptions: Include exception information in output, in time order" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -c, --channel: , of channel to add into output stream (repeat per channel)" EOL ); + genericsFPrintf( stderr, " -C, --cpufreq: (Scaled) speed of the CPU" EOL + " generally /1, /4, /16 or /64 of the real CPU speed," EOL ); + genericsFPrintf( stderr, " -E, --eof: Terminate when the file/socket ends/is closed, or wait for more/reconnect" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -g, --trigger: to use to trigger timestamp (default is newline)" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: : Which orbflow tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -T, --timestamp: : Add absolute, relative (to session start)," EOL + " delta, system timestamp or system timestamp delta to output. Note" EOL + " the accuracy of a,r & d are host dependent." EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -x, --exceptions: Include exception information in output, in time order" EOL ); } // ==================================================================================================== static void _printVersion( void ) { - genericsPrintf( "orbcat version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orbcat version " GIT_DESCRIBE EOL ); } // ==================================================================================================== static struct option _longOptions[] = @@ -989,7 +990,7 @@ static void _feedStream( struct Stream *stream ) /* Check if an exception report timed out */ if ( ( _r.inLine ) && _r.dwtText[0] && ( _timestamp() - _r.dwtte > DWT_TO_US ) ) { - genericsPrintf( EOL "%s", _r.dwtText ); + genericsFPrintf( stderr, EOL "%s", _r.dwtText ); _r.dwtText[0] = 0; _r.inLine = false; } diff --git a/Src/orbdump.c b/Src/orbdump.c index a5116cc1..a6c59991 100644 --- a/Src/orbdump.c +++ b/Src/orbdump.c @@ -22,7 +22,7 @@ #include "nw.h" -#define MAX_STRING_LENGTH (256) /* Maximum length that will be output from a fifo for a single event */ +#define MAX_STRING_LENGTH (256) /* Maximum length that will be output for a single event */ #define DEFAULT_OUTFILE "/dev/stdout" #define DEFAULT_TIMELEN 10000 @@ -98,24 +98,24 @@ uint64_t _timestamp( void ) void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -l, --length: Length of time in ms to record from point of acheiving sync (defaults to %dmS)" EOL, options.timelen ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -o, --output-file: to be used for dump file (defaults to %s)" EOL, options.outfile ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: Which Orbflow tag to use (normally 1)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -w, --sync-write: Write synchronously to the output file after every packet" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -l, --length: Length of time in ms to record from point of acheiving sync (defaults to %dmS)" EOL, options.timelen ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -o, --output-file: to be used for dump file (defaults to %s)" EOL, options.outfile ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: Which Orbflow tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -w, --sync-write: Write synchronously to the output file after every packet" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbdump version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orbdump version " GIT_DESCRIBE EOL ); } // ==================================================================================================== static struct option _longOptions[] = diff --git a/Src/orbfifo.c b/Src/orbfifo.c deleted file mode 100644 index 78803583..00000000 --- a/Src/orbfifo.c +++ /dev/null @@ -1,549 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause */ - -/* - * ITM Splitter for Orbuculum - * ========================== - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "git_version_info.h" -#include "generics.h" -#include "fileWriter.h" -#include "stream.h" -#include "nw.h" - -#include "itmfifos.h" - -const char *protString[] = {"OFLOW", "ITM", NULL}; - -//#define DUMP_BLOCK - -/* Record for options, either defaults or from command line */ -struct -{ - /* Config information */ - bool filewriter; /* Supporting filewriter functionality */ - char *fwbasedir; /* Base directory for filewriter output */ - bool permafile; /* Use permanent files rather than fifos */ - - /* Source information */ - char *file; /* File host connection */ - bool fileTerminate; /* Terminate when file read isn't successful */ - bool mono; /* Supress colour in output */ - - int port; /* Source information */ - char *server; - -} options = -{ - .port = OFCLIENT_SERVER_PORT, - .server = "localhost" -}; - -struct -{ - struct itmfifosHandle *f; /* Link to the itmfifo subsystem */ - bool ending; /* Flag indicating app is terminating */ -} _r; - -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -// Private routines -// ==================================================================================================== -// ==================================================================================================== -// ==================================================================================================== -static void _printHelp( const char *const progName ) - -{ - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -b, --basedir: for channels" EOL ); - genericsPrintf( " -c, --channel: ,, of channel to populate (repeat per channel)" EOL ); - genericsPrintf( " -E, --eof: When reading from file, terminate at end of file" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -P, --permanent: Create permanent files rather than fifos" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: Which OFLOW tag to use (normally 1)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -W, --writer-path: Enable filewriter functionality using specified base path" EOL ); -} -// ==================================================================================================== -void _printVersion( void ) - -{ - genericsPrintf( "orbfifo version " GIT_DESCRIBE ); -} -// ==================================================================================================== -struct option _longOptions[] = -{ - {"basedir", required_argument, NULL, 'b'}, - {"channel", required_argument, NULL, 'c'}, - {"eof", no_argument, NULL, 'E'}, - {"input-file", required_argument, NULL, 'f'}, - {"help", no_argument, NULL, 'h'}, - {"no-colour", no_argument, NULL, 'M'}, - {"no-color", no_argument, NULL, 'M'}, - {"permanent", no_argument, NULL, 'P'}, - {"protocol", required_argument, NULL, 'p'}, - {"server", required_argument, NULL, 's'}, - {"tag", required_argument, NULL, 't'}, - {"verbose", required_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, - {"writer-path", required_argument, NULL, 'W'}, - {NULL, no_argument, NULL, 0} -}; -// ==================================================================================================== -static bool _processOptions( int argc, char *argv[] ) - -{ - int c, optionIndex = 0; -#define DELIMITER ',' - - char *chanConfig; - char *chanName; - uint chan; - char *chanIndex; - bool protExplicit = false; - bool serverExplicit = false; - bool portExplicit = false; - enum Prot p; - - while ( ( c = getopt_long ( argc, argv, "b:c:Ef:hVn:Pp:s:t:v:w:", _longOptions, &optionIndex ) ) != -1 ) - switch ( c ) - { - // ------------------------------------ - - case 'b': - itmfifoSetChanPath( _r.f, optarg ); - break; - - // ------------------------------------ - case 'E': - options.fileTerminate = true; - break; - - // ------------------------------------ - - case 'f': - options.file = optarg; - break; - - // ------------------------------------ - - case 'h': - _printHelp( argv[0] ); - return false; - - // ------------------------------------ - case 'V': - _printVersion(); - return false; - - // ------------------------------------ - case 'M': - options.mono = true; - break; - - // ------------------------------------ - case 'n': - itmfifoSetForceITMSync( _r.f, false ); - break; - - // ------------------------------------ - - case 'P': - options.permafile = true; - break; - - // ------------------------------------ - - case 'p': - p = PROT_UNKNOWN; - protExplicit = true; - - for ( int i = 0; protString[i]; i++ ) - { - if ( !strcmp( protString[i], optarg ) ) - { - p = i; - break; - } - } - - if ( PROT_UNKNOWN == p ) - { - genericsReport( V_ERROR, "Unrecognised protocol type" EOL ); - return false; - } - - itmfifoSetProtocol( _r.f, p ); - break; - - // ------------------------------------ - case 's': - options.server = optarg; - serverExplicit = true; - - // See if we have an optional port number too - char *a = optarg; - - while ( ( *a ) && ( *a != ':' ) ) - { - a++; - } - - if ( *a == ':' ) - { - *a = 0; - options.port = atoi( ++a ); - } - - if ( !options.port ) - { - options.port = NWCLIENT_SERVER_PORT; - } - else - { - portExplicit = true; - } - - break; - - // ------------------------------------ - - case 't': - itmfifoSettag( _r.f, atoi( optarg ) ); - break; - - // ------------------------------------ - - case 'v': - if ( !isdigit( *optarg ) ) - { - genericsReport( V_ERROR, "-v requires a numeric argument." EOL ); - return false; - } - - genericsSetReportLevel( atoi( optarg ) ); - break; - - // ------------------------------------ - - case 'W': - options.filewriter = true; - options.fwbasedir = optarg; - break; - - // ------------------------------------ - - /* Individual channel setup */ - case 'c': - chanIndex = chanConfig = strdup( optarg ); - - if ( NULL == chanConfig ) - { - genericsReport( V_ERROR, "Couldn't allocate memory at %s::%d" EOL, __FILE__, __LINE__ ); - return false; - } - - chan = atoi( optarg ); - - if ( chan >= NUM_CHANNELS ) - { - genericsReport( V_ERROR, "Channel index out of range" EOL ); - free( chanConfig ); - return false; - } - - /* Scan for start of filename */ - while ( ( *chanIndex ) && ( *chanIndex != DELIMITER ) ) - { - chanIndex++; - } - - if ( !*chanIndex ) - { - genericsReport( V_ERROR, "No filename for channel %d" EOL, chan ); - free( chanConfig ); - return false; - } - - chanName = ++chanIndex; - - /* Scan for format */ - while ( ( *chanIndex ) && ( *chanIndex != DELIMITER ) ) - { - chanIndex++; - } - - if ( !*chanIndex ) - { - genericsReport( V_WARN, "No output format for channel %d, output raw!" EOL, chan ); - itmfifoSetChannel( _r.f, chan, chanName, NULL ); - break; - } - - *chanIndex++ = 0; - itmfifoSetChannel( _r.f, chan, chanName, genericsUnescape( chanIndex ) ); - break; - - // ------------------------------------ - - case '?': - if ( optopt == 'b' ) - { - genericsReport( V_ERROR, "Option '%c' requires an argument." EOL, optopt ); - } - else if ( !isprint ( optopt ) ) - { - genericsReport( V_ERROR, "Unknown option character `\\x%x'." EOL, optopt ); - } - - return false; - - // ------------------------------------ - default: - genericsReport( V_ERROR, "Unrecognised option '%c'" EOL, c ); - return false; - // ------------------------------------ - } - - /* If we set an explicit server and port and didn't set a protocol chances are we want ITM, not OFLOW */ - if ( serverExplicit && !protExplicit ) - { - itmfifoSetProtocol( _r.f, PROT_ITM ); - } - - if ( ( itmfifoGetProtocol( _r.f ) == PROT_ITM ) && !portExplicit ) - { - options.port = NWCLIENT_SERVER_PORT; - } - - - /* ... and dump the config if we're being verbose */ - genericsReport( V_INFO, "orbfifo version " GIT_DESCRIBE EOL ); - genericsReport( V_INFO, "Server : %s:%d" EOL, options.server, options.port ); - - if ( options.file ) - { - genericsReport( V_INFO, "Input File : %s", options.file ); - - if ( options.fileTerminate ) - { - genericsReport( V_INFO, " (Terminate on exhaustion)" EOL ); - } - else - { - genericsReport( V_INFO, " (Ongoing read)" EOL ); - } - } - - - switch ( itmfifoGetProtocol( _r.f ) ) - { - case PROT_OFLOW: - genericsReport( V_INFO, "Decoding OFLOW (Orbuculum) with ITM in stream %d" EOL, itmfifoGettag( _r.f ) ); - break; - - case PROT_ITM: - genericsReport( V_INFO, "Decoding ITM" EOL ); - break; - - default: - genericsReport( V_INFO, "Decoding unknown" EOL ); - break; - } - - genericsReport( V_INFO, "Channels :" EOL ); - - for ( int g = 0; g < NUM_CHANNELS; g++ ) - { - if ( itmfifoGetChannelName( _r.f, g ) ) - { - genericsReport( V_INFO, " %02d [%s] [%s]" EOL, g, genericsEscape( itmfifoGetChannelFormat( _r.f, g ) ? : "RAW" ), itmfifoGetChannelName( _r.f, g ) ); - } - } - - genericsReport( V_INFO, " HW [Predefined] [" HWFIFO_NAME "]" EOL ); - - return true; -} -// ==================================================================================================== -static void _processBlock( int s, unsigned char *cbw ) - -/* Generic block processor for received data */ - -{ - genericsReport( V_DEBUG, "RXED Packet of %d bytes" EOL, s ); - - if ( s ) - { -#ifdef DUMP_BLOCK - uint8_t *c = cbw; - uint32_t y = s; - - fprintf( stderr, EOL ); - - while ( y-- ) - { - fprintf( stderr, "%02X ", *c++ ); - - if ( !( y % 16 ) ) - { - fprintf( stderr, EOL ); - } - } - -#endif - - itmfifoProtocolPump( _r.f, cbw, s ); - } - -} -// ==================================================================================================== -static void _doExit( void ) - -{ - _r.ending = true; - itmfifoShutdown( _r.f ); - /* Give them a bit of time, then we're leaving anyway */ - usleep( 200 ); -} - -// ==================================================================================================== -static void _intHandler( int sig ) - -{ - /* CTRL-C exit is not an error... */ - _doExit(); -} - -// ==================================================================================================== -int main( int argc, char *argv[] ) - -{ - uint8_t cbw[TRANSFER_SIZE]; - size_t t; - struct Stream *stream = NULL; - int64_t lastTime; - struct timeval tv; - uint64_t remainTime; - - /* Setup fifos with forced ITM sync, tag 1 */ - _r.f = itmfifoInit( true, false, 1 ); - assert( _r.f ); - - if ( !_processOptions( argc, argv ) ) - { - /* processOptions generates its own error messages */ - genericsExit( -1, "" EOL ); - } - - genericsScreenHandling( !options.mono ); - - itmfifoUsePermafiles( _r.f, options.permafile ); - - /* Make sure the fifos get removed at the end */ - atexit( _doExit ); - - /* Fill in a time to start from */ - lastTime = genericsTimestampmS(); - - /* This ensures the atexit gets called */ - if ( SIG_ERR == signal( SIGINT, _intHandler ) ) - { - genericsExit( -1, "Failed to establish Int handler" EOL ); - } - - /* Don't kill a sub-process when any reader or writer evaporates */ - if ( SIG_ERR == signal( SIGPIPE, SIG_IGN ) ) - { - genericsExit( -1, "Failed to ignore SIGPIPEs" EOL ); - } - - if ( ! ( itmfifoCreate( _r.f ) ) ) - { - genericsExit( -1, "Failed to make channel devices" EOL ); - } - - /* Start the filewriter */ - itmfifoFilewriter( _r.f, options.filewriter, options.fwbasedir ); - - while ( !_r.ending ) - { - if ( options.file != NULL ) - { - stream = streamCreateFile( options.file ); - } - else - { - while ( !_r.ending ) - { - stream = streamCreateSocket( options.server, options.port ); - - if ( stream ) - { - break; - } - - genericsReport( V_INFO, "Could not connect" EOL ); - usleep( 1000000 ); - } - } - - while ( !_r.ending ) - { - remainTime = ( ( lastTime + 1000000 - genericsTimestampuS() ) ); - - if ( remainTime > 0 ) - { - tv.tv_sec = remainTime / 1000000; - tv.tv_usec = remainTime % 1000000; - } - - enum ReceiveResult result = stream->receive( stream, cbw, TRANSFER_SIZE, &tv, ( size_t * )&t ); - - if ( ( result == RECEIVE_RESULT_EOF ) || ( result == RECEIVE_RESULT_ERROR ) ) - { - break; - } - - _processBlock( t, cbw ); - } - - - if ( stream ) - { - stream->close( stream ); - free( stream ); - stream = NULL; - } - - if ( options.fileTerminate ) - { - break; - } - } - - return -ESRCH; -} -// ==================================================================================================== diff --git a/Src/orblcd.c b/Src/orblcd.c index 0bb6856e..51495d3b 100644 --- a/Src/orblcd.c +++ b/Src/orblcd.c @@ -122,12 +122,20 @@ static void _paintPixels( struct swMsg *m, struct RunTime *r ) return; } - for ( int b = ORBLCD_PIXELS_PER_WORD( r->app->modeDescriptor ) - 1; b >= 0; b-- ) + for ( int b = m->len*8/ORBLCD_GET_DEPTH( r->app->modeDescriptor ) - 1; b >= 0; b-- ) + //for ( int b = ORBLCD_PIXELS_PER_WORD( r->app->modeDescriptor ) - 1; b >= 0; b-- ) { switch ( ORBLCD_DECODE_D( r->app->modeDescriptor ) ) { case ORBLCD_DEPTH_1: - y = ( d & ( 1 << ( b % 8 ) ) ) ? r->app->sbcolour : 0; + if ( ORBLCD_DECODE_L( r->app->modeDescriptor ) ) + { + y = ( d & ( 128 >> ( b % 8 ) ) ) ? r->app->sbcolour : 0; + } + else + { + y = ( d & ( 1 << ( b % 8 ) ) ) ? r->app->sbcolour : 0; + } if ( !( b % 8 ) ) { @@ -422,26 +430,26 @@ static bool _feedStream( struct Stream *stream, struct RunTime *r ) void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -c, --channel: of first channel in pair containing display data" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -S, --sbcolour: to be used for single bit renders, ignored for other bit depths" EOL ); - genericsPrintf( " -t, --tag: Which OFLOW tag to use (normally 1)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -w, --window: Set title for output window" EOL ); - genericsPrintf( " -z, --size: Set relative size of output window (normally 1.0)" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -c, --channel: of first channel in pair containing display data" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -S, --sbcolour: to be used for single bit renders, ignored for other bit depths" EOL ); + genericsFPrintf( stderr, " -t, --tag: Which OFLOW tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -w, --window: Set title for output window" EOL ); + genericsFPrintf( stderr, " -z, --size: Set relative size of output window (normally 1.0)" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orblcd version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orblcd version " GIT_DESCRIBE EOL ); } // ==================================================================================================== static struct option _longOptions[] = diff --git a/Src/orbmortem.c b/Src/orbmortem.c index 1d7442f4..495e2c76 100644 --- a/Src/orbmortem.c +++ b/Src/orbmortem.c @@ -167,41 +167,41 @@ static void _intHandler( int sig ) static void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -A, --alt-addr-enc: Do not use alternate address encoding" EOL ); - genericsPrintf( " -b, --buffer-len: Length of post-mortem buffer, in KBytes (Default %d KBytes)" EOL, DEFAULT_PM_BUFLEN_K ); - genericsPrintf( " -C, --editor-cmd: Command line for external editor (%%f = filename, %%l = line)" EOL ); - genericsPrintf( " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); - genericsPrintf( " -d, --del-prefix: Material to delete off the front of filenames" EOL ); - genericsPrintf( " -e, --elf-file: to use for symbols and source" EOL ); - genericsPrintf( " -E, --eof: When reading from file, terminate at end of file" EOL ); - genericsPrintf( " -f, --input-file: : Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -O, --objdump-opts: Options to pass directly to objdump" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ETM" EOL ); - genericsPrintf( " -P, --trace-proto: { " ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -A, --alt-addr-enc: Do not use alternate address encoding" EOL ); + genericsFPrintf( stderr, " -b, --buffer-len: Length of post-mortem buffer, in KBytes (Default %d KBytes)" EOL, DEFAULT_PM_BUFLEN_K ); + genericsFPrintf( stderr, " -C, --editor-cmd: Command line for external editor (%%f = filename, %%l = line)" EOL ); + genericsFPrintf( stderr, " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); + genericsFPrintf( stderr, " -d, --del-prefix: Material to delete off the front of filenames" EOL ); + genericsFPrintf( stderr, " -e, --elf-file: to use for symbols and source" EOL ); + genericsFPrintf( stderr, " -E, --eof: When reading from file, terminate at end of file" EOL ); + genericsFPrintf( stderr, " -f, --input-file: : Take input from specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -O, --objdump-opts: Options to pass directly to objdump" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ETM" EOL ); + genericsFPrintf( stderr, " -P, --trace-proto: { " ); for ( int i = TRACE_PROT_LIST_START; i < TRACE_PROT_NUM; i++ ) { - genericsPrintf( "%s ", TRACEDecodeGetProtocolName( i ) ); + genericsFPrintf( stderr, "%s ", TRACEDecodeGetProtocolName( i ) ); } - genericsPrintf( "} trace protocol to use, default is %s" EOL, TRACEDecodeGetProtocolName( TRACE_PROT_LIST_START ) ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: : Which OFLOW tag to use (normally 2)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( EOL "(Legacy protocol will connect one port higher than that set in -s)" EOL ); - genericsPrintf( "(This will automatically select the second output stream from orbuculum.)" EOL ); - genericsPrintf( EOL "Environment Variables;" EOL ); - genericsPrintf( " OBJDUMP: to use non-standard objdump binary" EOL ); + genericsFPrintf( stderr, "} trace protocol to use, default is %s" EOL, TRACEDecodeGetProtocolName( TRACE_PROT_LIST_START ) ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: : Which OFLOW tag to use (normally 2)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, EOL "(Legacy protocol will connect one port higher than that set in -s)" EOL ); + genericsFPrintf( stderr, "(This will automatically select the second output stream from orbuculum.)" EOL ); + genericsFPrintf( stderr, EOL "Environment Variables;" EOL ); + genericsFPrintf( stderr, " OBJDUMP: to use non-standard objdump binary" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbmortem version " GIT_DESCRIBE ); + genericsFPrintf( stderr, "orbmortem version " GIT_DESCRIBE ); } // ==================================================================================================== static struct option _longOptions[] = @@ -1329,7 +1329,7 @@ int main( int argc, char *argv[] ) genericsScreenHandling( !_r.options->mono ); - /* Make sure the fifos get removed at the end */ + /* Make sure any cleanup happens at the end */ atexit( _doExit ); if ( _r.options->file != NULL ) diff --git a/Src/orbprofile.c b/Src/orbprofile.c index 6bbfe68c..2841c177 100644 --- a/Src/orbprofile.c +++ b/Src/orbprofile.c @@ -457,33 +457,33 @@ static void _traceCB( void *d ) static void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -A, --alt-addr-enc: Switch off alternate address decoding (on by default)" EOL ); - genericsPrintf( " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); - genericsPrintf( " -d, --del-prefix: Material to delete off front of filenames" EOL ); - genericsPrintf( " -e, --elf-file: to use for symbols" EOL ); - genericsPrintf( " -E, --eof: When reading from file, terminate at EOF" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -I, --interval: Time between samples (in ms)" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -O, --objdump-opts: Options to pass directly to objdump" EOL ); - genericsPrintf( " -P, --trace-proto: {ETM35|MTB} trace protocol to use, default is ETM35" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise raw ETM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: : Which OFLOW tag to use (normally 2)" EOL ); - genericsPrintf( " -T, --all-truncate: truncate -d material off all references (i.e. make output relative)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -y, --graph-file: dotty filename for structured callgraph output" EOL ); - genericsPrintf( " -z, --cache-file: profile filename for kcachegrind output" EOL ); - genericsPrintf( EOL "(Will connect one port higher than that set in -s when Orbflow is not used)" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -A, --alt-addr-enc: Switch off alternate address decoding (on by default)" EOL ); + genericsFPrintf( stderr, " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); + genericsFPrintf( stderr, " -d, --del-prefix: Material to delete off front of filenames" EOL ); + genericsFPrintf( stderr, " -e, --elf-file: to use for symbols" EOL ); + genericsFPrintf( stderr, " -E, --eof: When reading from file, terminate at EOF" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -I, --interval: Time between samples (in ms)" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -O, --objdump-opts: Options to pass directly to objdump" EOL ); + genericsFPrintf( stderr, " -P, --trace-proto: {ETM35|MTB} trace protocol to use, default is ETM35" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise raw ETM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: : Which OFLOW tag to use (normally 2)" EOL ); + genericsFPrintf( stderr, " -T, --all-truncate: truncate -d material off all references (i.e. make output relative)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -y, --graph-file: dotty filename for structured callgraph output" EOL ); + genericsFPrintf( stderr, " -z, --cache-file: profile filename for kcachegrind output" EOL ); + genericsFPrintf( stderr, EOL "(Will connect one port higher than that set in -s when Orbflow is not used)" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbprofile version " GIT_DESCRIBE ); + genericsFPrintf( stderr, "orbprofile version " GIT_DESCRIBE ); } // ==================================================================================================== static struct option _longOptions[] = @@ -866,7 +866,7 @@ int main( int argc, char *argv[] ) genericsScreenHandling( !_r.options->mono ); - /* Make sure the fifos get removed at the end */ + /* Make sure any cleanup happens at the end */ atexit( _doExit ); /* This ensures the atexit gets called */ diff --git a/Src/orbstat.c b/Src/orbstat.c index 214129eb..9014a526 100644 --- a/Src/orbstat.c +++ b/Src/orbstat.c @@ -404,32 +404,32 @@ void _itmPumpProcess( struct RunTime *r, char c ) static void _printHelp( struct RunTime *r ) { - genericsPrintf( "Usage: %s [options]" EOL, r->progName ); - genericsPrintf( " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); - genericsPrintf( " -d, --del-prefix: Material to delete off front of filenames" EOL ); - genericsPrintf( " -e, --elf-file: to use for symbols" EOL ); - genericsPrintf( " -E, --eof: When reading from file, terminate at end of file" EOL ); - genericsPrintf( " -f, --input-file: : Take input from specified file" EOL ); - genericsPrintf( " -g, --trace-chn: ITM channel for trace (default %d)" EOL, r->options->traceChannel ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -I, --interval: : Time to sample (in mS)" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -O, --objdump-opts: Options to pass directly to objdump" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: : Which OFLOW tag to use (normally 1)" EOL ); - genericsPrintf( " -T, --all-truncate: truncate -d material off all references (i.e. make output relative)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -y, --graph-file: dotty filename for structured callgraph output" EOL ); - genericsPrintf( " -z, --cache-file: profile filename for kcachegrind output" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, r->progName ); + genericsFPrintf( stderr, " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); + genericsFPrintf( stderr, " -d, --del-prefix: Material to delete off front of filenames" EOL ); + genericsFPrintf( stderr, " -e, --elf-file: to use for symbols" EOL ); + genericsFPrintf( stderr, " -E, --eof: When reading from file, terminate at end of file" EOL ); + genericsFPrintf( stderr, " -f, --input-file: : Take input from specified file" EOL ); + genericsFPrintf( stderr, " -g, --trace-chn: ITM channel for trace (default %d)" EOL, r->options->traceChannel ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -I, --interval: : Time to sample (in mS)" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -O, --objdump-opts: Options to pass directly to objdump" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: : Which OFLOW tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -T, --all-truncate: truncate -d material off all references (i.e. make output relative)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -y, --graph-file: dotty filename for structured callgraph output" EOL ); + genericsFPrintf( stderr, " -z, --cache-file: profile filename for kcachegrind output" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbstat version " GIT_DESCRIBE ); + genericsFPrintf( stderr, "orbstat version " GIT_DESCRIBE ); } // ==================================================================================================== static struct option _longOptions[] = diff --git a/Src/orbtop.c b/Src/orbtop.c index f8cf205b..d7d79f80 100644 --- a/Src/orbtop.c +++ b/Src/orbtop.c @@ -36,6 +36,9 @@ #define MSG_REORDER_BUFLEN (10) /* Maximum number of samples to re-order for timekeeping */ +#define DWT_NUM_EVENTS 6 +const char *evName[DWT_NUM_EVENTS] = {"CPI", "Exc", "Slp", "LSU", "Fld", "Cyc"}; + struct visitedAddr /* Structure for Hashmap of visited/observed addresses */ { uint64_t visits; @@ -92,6 +95,7 @@ struct /* Record for options, either defau char *outfile; /* File to output current information */ char *logfile; /* File to output historic information */ bool mono; /* Supress colour in output */ + int paceDelay; /* Delay between blocks of data transmission in file readout */ uint32_t cutscreen; /* Cut screen output after specified number of lines */ uint32_t maxRoutines; /* Historic information to emit */ bool lineDisaggregation; /* Aggregate per line or per function? */ @@ -143,6 +147,7 @@ struct uint32_t SWPkt; /* Number of SW Packets received */ uint32_t TSPkt; /* Number of TS Packets received */ uint32_t HWPkt; /* Number of HW Packets received */ + uint32_t dwt_event_acc[DWT_NUM_EVENTS]; /* Accumulator for DWT events */ FILE *jsonfile; /* File where json output is being dumped */ uint32_t interrupts; @@ -343,10 +348,17 @@ void _handleException( struct excMsg *m, struct ITMDecoder *i ) }; } // ==================================================================================================== -void _handleDWTEvent( struct ITMDecoder *i, struct ITMPacket *p ) +// ==================================================================================================== +void _handleDWTEvent( struct dwtMsg *m, struct ITMPacket *p ) { - + for ( uint32_t i = 0; i < DWT_NUM_EVENTS; i++ ) + { + if ( m->event & ( 1 << i ) ) + { + _r.dwt_event_acc[i]++; + } + } } // ==================================================================================================== void _handleSW( struct ITMDecoder *i, struct ITMPacket *p ) @@ -422,13 +434,19 @@ uint32_t _consolodateReport( struct reportLine **returnReport, uint32_t *returnR } else { + a = ( struct visitedAddr * )calloc( 1, sizeof( struct visitedAddr ) ); + MEMCHECKV( a ); + a->visits = _r.sleeps; + n = ( struct nameEntry * )malloc( sizeof( struct nameEntry ) ); - } + n->fileindex = NO_FILE; + n->functionindex = FN_SLEEPING; + n->addr = FN_SLEEPING; + n->line = 0; - n->fileindex = NO_FILE; - n->functionindex = FN_SLEEPING; - n->addr = 0; - n->line = 0; + a->n = n; + HASH_ADD_INT( _r.addresses, n->addr, a ); + } report[reportLines].n = n; report[reportLines].count = _r.sleeps; @@ -442,6 +460,7 @@ uint32_t _consolodateReport( struct reportLine **returnReport, uint32_t *returnR *returnReport = report; *returnReportLines = reportLines; + return total; } // ==================================================================================================== @@ -618,7 +637,7 @@ static void _outputTop( uint32_t total, uint32_t reportLines, struct reportLine q = fopen( options.logfile, "a" ); } - genericsPrintf( CLEAR_SCREEN ); + genericsFPrintf( stdout, CLEAR_SCREEN ); if ( total ) { @@ -636,21 +655,21 @@ static void _outputTop( uint32_t total, uint32_t reportLines, struct reportLine dispSamples += report[n].count; totPercent += percentage; - genericsPrintf( C_DATA "%3d.%02d%% " C_SUPPORT " %7" PRIu64 " ", percentage / 100, percentage % 100, report[n].count ); + genericsFPrintf( stdout, C_DATA "%3d.%02d%% " C_SUPPORT " %7" PRIu64 " ", percentage / 100, percentage % 100, report[n].count ); if ( ( options.reportFilenames ) && ( report[n].n->fileindex != NO_FILE ) ) { - genericsPrintf( C_CONTEXT "%s" C_RESET "::", SymbolFilename( _r.s, report[n].n->fileindex ) ); + genericsFPrintf( stdout, C_CONTEXT "%s" C_RESET "::", SymbolFilename( _r.s, report[n].n->fileindex ) ); } if ( ( options.lineDisaggregation ) && ( report[n].n->line ) ) { - genericsPrintf( C_SUPPORT2 "%s" C_RESET "::" C_CONTEXT "%d" EOL, d ? d : SymbolFunction( _r.s, report[n].n->functionindex ), report[n].n->line ); + genericsFPrintf( stdout, C_SUPPORT2 "%s" C_RESET "::" C_CONTEXT "%d" EOL, d ? d : SymbolFunction( _r.s, report[n].n->functionindex ), report[n].n->line ); } else { - genericsPrintf( C_SUPPORT2 "%s" C_RESET EOL, d ? d : SymbolFunction( _r.s, report[n].n->functionindex ) ); + genericsFPrintf( stdout, C_SUPPORT2 "%s" C_RESET EOL, d ? d : SymbolFunction( _r.s, report[n].n->functionindex ) ); } printed++; @@ -690,9 +709,9 @@ static void _outputTop( uint32_t total, uint32_t reportLines, struct reportLine } } - genericsPrintf( C_RESET "-----------------" EOL ); + genericsFPrintf( stdout, C_RESET "-----------------" EOL ); - genericsPrintf( C_DATA "%3d.%02d%% " C_SUPPORT " %7" PRIu64 " " C_RESET "of "C_DATA" %" PRIu64 " "C_RESET" Samples" EOL, totPercent / 100, totPercent % 100, dispSamples, samples ); + genericsFPrintf( stdout, C_DATA "%3d.%02d%% " C_SUPPORT " %7" PRIu64 " " C_RESET "of "C_DATA" %" PRIu64 " "C_RESET" Samples" EOL, totPercent / 100, totPercent % 100, dispSamples, samples ); if ( p ) { @@ -705,17 +724,33 @@ static void _outputTop( uint32_t total, uint32_t reportLines, struct reportLine fclose( q ); } + bool havePrinted = false; + + /* DWT Event counters */ + for ( uint32_t i = 0; i < DWT_NUM_EVENTS; i++ ) + { + if ( _r.dwt_event_acc[i] ) + { + havePrinted = true; + genericsFPrintf( stdout, "%4s:" C_DATA "%7d " C_RESET, evName[i], _r.dwt_event_acc[i] ); + } + } + + if ( havePrinted ) + { + genericsFPrintf( stdout, EOL ); + } if ( options.outputExceptions ) { /* Tidy up screen output */ while ( printed++ <= options.cutscreen ) { - genericsPrintf( EOL ); + genericsFPrintf( stdout, EOL ); } - genericsPrintf( EOL " Exception | Count | MaxD | TotalTicks | %% | AveTicks | minTicks | maxTicks | maxWall " EOL ); - genericsPrintf( /**/"-------------------+----------+-------+-------------+-------+------------+------------+------------+----------" EOL ); + genericsFPrintf( stdout, EOL " Exception | Count | MaxD | TotalTicks | %% | AveTicks | minTicks | maxTicks | maxWall " EOL ); + genericsFPrintf( stdout, /**/"-------------------+----------+-------+-------------+-------+------------+------------+------------+----------" EOL ); for ( uint32_t e = 0; e < MAX_EXCEPTIONS; e++ ) { @@ -734,26 +769,26 @@ static void _outputTop( uint32_t total, uint32_t reportLines, struct reportLine } const float util_percent = ( float )_r.er[e].totalTime / ( _r.timeStamp - _r.lastReportTicks ) * 100.0f; - genericsPrintf( C_DATA "%3" PRId32 " %-14s" C_RESET " | " C_DATA "%8" PRIu64 C_RESET " |" C_DATA " %5" - PRIu32 C_RESET " | "C_DATA " %9" PRIu64 C_RESET " |" C_DATA "%6.1f" C_RESET " | " C_DATA "%9" PRIu64 C_RESET " | " C_DATA "%9" PRIu64 C_RESET " | " C_DATA" %9" PRIu64 C_RESET " | " C_DATA "%9" - PRIu64 C_RESET EOL, - e, exceptionName, _r.er[e].visits, _r.er[e].maxDepth, _r.er[e].totalTime, util_percent, _r.er[e].totalTime / _r.er[e].visits, _r.er[e].minTime, _r.er[e].maxTime, _r.er[e].maxWallTime ); + genericsFPrintf( stdout, C_DATA "%3" PRId32 " %-14s" C_RESET " | " C_DATA "%8" PRIu64 C_RESET " |" C_DATA " %5" + PRIu32 C_RESET " | "C_DATA " %9" PRIu64 C_RESET " |" C_DATA "%6.1f" C_RESET " | " C_DATA "%9" PRIu64 C_RESET " | " C_DATA "%9" PRIu64 C_RESET " | " C_DATA" %9" PRIu64 C_RESET " | " C_DATA "%9" + PRIu64 C_RESET EOL, + e, exceptionName, _r.er[e].visits, _r.er[e].maxDepth, _r.er[e].totalTime, util_percent, _r.er[e].totalTime / _r.er[e].visits, _r.er[e].minTime, _r.er[e].maxTime, _r.er[e].maxWallTime ); } } } - genericsPrintf( EOL C_RESET "[%s%s%s%s" C_RESET "] ", - ( _r.ITMoverflows != ITMDecoderGetStats( &_r.i )->overflow ) ? C_OVF_IND "V" : C_RESET "-", - ( _r.SWPkt != ITMDecoderGetStats( &_r.i )->SWPkt ) ? C_SOFT_IND "S" : C_RESET "-", - ( _r.TSPkt != ITMDecoderGetStats( &_r.i )->TSPkt ) ? C_TSTAMP_IND "T" : C_RESET "-", - ( _r.HWPkt != ITMDecoderGetStats( &_r.i )->HWPkt ) ? C_HW_IND "H" : C_RESET "-" ); + genericsFPrintf( stdout, EOL C_RESET "[%s%s%s%s" C_RESET "] ", + ( _r.ITMoverflows != ITMDecoderGetStats( &_r.i )->overflow ) ? C_OVF_IND "V" : C_RESET "-", + ( _r.SWPkt != ITMDecoderGetStats( &_r.i )->SWPkt ) ? C_SOFT_IND "S" : C_RESET "-", + ( _r.TSPkt != ITMDecoderGetStats( &_r.i )->TSPkt ) ? C_TSTAMP_IND "T" : C_RESET "-", + ( _r.HWPkt != ITMDecoderGetStats( &_r.i )->HWPkt ) ? C_HW_IND "H" : C_RESET "-" ); if ( ( _r.lastReportTicks ) && ( lastTime != _r.lastReportus ) ) - genericsPrintf( "Interval = " C_DATA "%" PRIu64 "ms " C_RESET "/ "C_DATA "%" PRIu64 C_RESET " (~" C_DATA "%" PRIu64 C_RESET " Ticks/ms)" EOL, - ( ( lastTime - _r.lastReportus ) ) / 1000, _r.timeStamp - _r.lastReportTicks, ( ( _r.timeStamp - _r.lastReportTicks ) * 1000 ) / ( lastTime - _r.lastReportus ) ); + genericsFPrintf( stdout, "Interval = " C_DATA "%" PRIu64 "ms " C_RESET "/ "C_DATA "%" PRIu64 C_RESET " (~" C_DATA "%" PRIu64 C_RESET " Ticks/ms)" EOL, + ( ( lastTime - _r.lastReportus ) ) / 1000, _r.timeStamp - _r.lastReportTicks, ( ( _r.timeStamp - _r.lastReportTicks ) * 1000 ) / ( lastTime - _r.lastReportus ) ); else { - genericsPrintf( C_RESET "Interval = " C_DATA "%" PRIu64 C_RESET "ms" EOL, ( ( lastTime - _r.lastReportus ) ) / 1000 ); + genericsFPrintf( stdout, C_RESET "Interval = " C_DATA "%" PRIu64 C_RESET "ms" EOL, ( ( lastTime - _r.lastReportus ) ) / 1000 ); } genericsReport( V_INFO, " Ovf=%3d ITMSync=%3d ITMErrors=%3d" EOL, @@ -808,16 +843,18 @@ void _handlePCSample( struct pcSampleMsg *m, struct ITMDecoder *i ) void _flushHash( void ) { - struct visitedAddr *a; - UT_hash_handle hh; + struct visitedAddr *a, *tmp; - for ( a = _r.addresses; a != NULL; a = hh.next ) + HASH_ITER( hh, _r.addresses, a, tmp ) { - hh = a->hh; + if ( a->n ) + { + free( a->n ); + } + + HASH_DEL( _r.addresses, a ); free( a ); } - - _r.addresses = NULL; } // ==================================================================================================== // Pump characters into the itm decoder @@ -840,7 +877,7 @@ void _itmPumpProcess( uint8_t c ) /* MSG_DATA_ACCESS_WP */ NULL, /* MSG_DATA_RWWP */ NULL, /* MSG_PC_SAMPLE */ ( handlers )_handlePCSample, - /* MSG_DWT_EVENT */ NULL, + /* MSG_DWT_EVENT */ ( handlers )_handleDWTEvent, /* MSG_EXCEPTION */ ( handlers )_handleException, /* MSG_TS */ ( handlers )_handleTS }; @@ -881,37 +918,38 @@ void _itmPumpProcess( uint8_t c ) void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -c, --cut-after: Cut screen output after number of lines" EOL ); - genericsPrintf( " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); - genericsPrintf( " -d, --del-prefix: to take off front of filenames" EOL ); - genericsPrintf( " -e, --elf-file: to use for symbols" EOL ); - genericsPrintf( " -E, --exceptions: Include exceptions in output report" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -g, --record-file: append historic records to specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -I, --interval: Display interval in milliseconds (defaults to %dms)" EOL, TOP_UPDATE_INTERVAL ); - genericsPrintf( " -j, --json-file: Output to file in JSON format (or screen if is '-')" EOL ); - genericsPrintf( " -l, --agg-lines: Aggregate per line rather than per function" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -o, --output-file: to be used for output live file" EOL ); - genericsPrintf( " -O, --objdump-opts: Options to pass directly to objdump" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -r, --routines: to record in live file (default %d routines)" EOL, options.maxRoutines ); - genericsPrintf( " -R, --report-files: Report filenames as part of function discriminator" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -t, --tag: Which OFLOW tag to use (normally 1)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( EOL "Environment Variables;" EOL ); - genericsPrintf( " OBJDUMP: to use non-standard obbdump binary" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -c, --cut-after: Cut screen output after number of lines" EOL ); + genericsFPrintf( stderr, " -D, --no-demangle: Switch off C++ symbol demangling" EOL ); + genericsFPrintf( stderr, " -d, --del-prefix: to take off front of filenames" EOL ); + genericsFPrintf( stderr, " -e, --elf-file: to use for symbols" EOL ); + genericsFPrintf( stderr, " -E, --exceptions: Include exceptions in output report" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -g, --record-file: append historic records to specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -I, --interval: Display interval in milliseconds (defaults to %dms)" EOL, TOP_UPDATE_INTERVAL ); + genericsFPrintf( stderr, " -j, --json-file: Output to file in JSON format (or screen if is '-')" EOL ); + genericsFPrintf( stderr, " -l, --agg-lines: Aggregate per line rather than per function" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -o, --output-file: to be used for output live file" EOL ); + genericsFPrintf( stderr, " -O, --objdump-opts: Options to pass directly to objdump" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -P, --pace: delay in block of data transmission to clients" EOL ); + genericsFPrintf( stderr, " -r, --routines: to record in live file (default %d routines)" EOL, options.maxRoutines ); + genericsFPrintf( stderr, " -R, --report-files: Report filenames as part of function discriminator" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -t, --tag: Which OFLOW tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, EOL "Environment Variables;" EOL ); + genericsFPrintf( stderr, " OBJDUMP: to use non-standard obbdump binary" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbtop version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orbtop version " GIT_DESCRIBE EOL ); } // ==================================================================================================== static struct option _longOptions[] = @@ -933,6 +971,7 @@ static struct option _longOptions[] = {"output-file", required_argument, NULL, 'o'}, {"objdump-opts", required_argument, NULL, 'O'}, {"protocol", required_argument, NULL, 'p'}, + {"pace", required_argument, NULL, 'P'}, {"routines", required_argument, NULL, 'r'}, {"report-files", no_argument, NULL, 'R'}, {"server", required_argument, NULL, 's'}, @@ -942,14 +981,14 @@ static struct option _longOptions[] = {NULL, no_argument, NULL, 0} }; // ==================================================================================================== -bool _processOptions( int argc, char *argv[] ) +errcode _processOptions( int argc, char *argv[] ) { int c, optionIndex = 0; bool protExplicit = false; bool serverExplicit = false; - while ( ( c = getopt_long ( argc, argv, "c:d:DEe:f:g:hVI:j:lMnO:o:p:r:Rs:t:v:", _longOptions, &optionIndex ) ) != -1 ) + while ( ( c = getopt_long ( argc, argv, "c:d:DEe:f:g:hVI:j:lMnO:o:p:P:r:Rs:t:v:", _longOptions, &optionIndex ) ) != -1 ) switch ( c ) { // ------------------------------------ @@ -1042,7 +1081,20 @@ bool _processOptions( int argc, char *argv[] ) if ( options.protocol == PROT_UNKNOWN ) { genericsReport( V_ERROR, "Unrecognised protocol type" EOL ); - return false; + return ERR; + } + + break; + + // ------------------------------------ + + case 'P': + options.paceDelay = atoi( optarg ); + + if ( options.paceDelay <= 0 ) + { + genericsReport( V_ERROR, "paceDelay is out of range" EOL ); + return ERR; } break; @@ -1058,7 +1110,7 @@ bool _processOptions( int argc, char *argv[] ) if ( !isdigit( *optarg ) ) { genericsReport( V_ERROR, "-v requires a numeric argument." EOL ); - return false; + return ERR; } genericsSetReportLevel( atoi( optarg ) ); @@ -1108,7 +1160,7 @@ bool _processOptions( int argc, char *argv[] ) // ------------------------------------ case 'V': _printVersion(); - return -EINVAL; + return ERR; // ------------------------------------ case '?': @@ -1121,31 +1173,33 @@ bool _processOptions( int argc, char *argv[] ) genericsReport( V_ERROR, "Unknown option character `\\x%x'." EOL, optopt ); } - return -EINVAL; + return ERR; // ------------------------------------ default: genericsReport( V_ERROR, "Unknown option %c" EOL, optopt ); - return -EINVAL; + return ERR; // ------------------------------------ } /* If we set an explicit server and port and didn't set a protocol chances are we want ITM, not OFLOW */ if ( serverExplicit && !protExplicit ) { - options.protocol = PROT_ITM; + genericsReport( V_ERROR, "Protocol must be explicit when server is explicit" EOL ); + return ERR; } if ( !options.elffile ) { genericsReport( V_ERROR, "Elf File not specified" EOL ); - exit( -EBADF ); + return ERR; } genericsReport( V_INFO, "orbtop version " GIT_DESCRIBE EOL ); if ( options.file ) { + genericsReport( V_INFO, "Pace Delay : %dus" EOL, options.paceDelay ); genericsReport( V_INFO, "Input File : %s", options.file ); } else @@ -1172,8 +1226,14 @@ bool _processOptions( int argc, char *argv[] ) break; default: - genericsReport( V_INFO, "Decoding unknown" EOL ); - break; + genericsReport( V_ERROR, "Decoding unknown" EOL ); + return ERR; + } + + if ( ( options.paceDelay ) && ( !options.file ) ) + { + genericsReport( V_ERROR, "Pace Delay only makes sense when input is from a file" EOL ); + return ERR; } return OK; @@ -1275,6 +1335,12 @@ int main( int argc, char *argv[] ) genericsReport( V_WARN, "Loaded %s" EOL, options.elffile ); + if ( _r.s ) + { + genericsReport( V_INFO, "Files: %d" EOL "Functions: %d" EOL "Source: %d" EOL, _r.s->fileCount, _r.s->functionCount, _r.s->sourceCount ); + } + + /* Reset the handlers before we start */ ITMDecoderInit( &_r.i, options.forceITMSync ); OFLOWInit( &_r.c ); @@ -1329,7 +1395,7 @@ int main( int argc, char *argv[] ) if ( ( !options.json ) || ( options.json[0] != '-' ) ) { - genericsPrintf( CLEAR_SCREEN "Connected..." EOL ); + genericsFPrintf( stderr, CLEAR_SCREEN "Connected..." EOL ); } /* ...just in case we have any readings from a previous incantation */ @@ -1399,6 +1465,11 @@ int main( int argc, char *argv[] ) } genericsReport( V_WARN, "Loaded %s" EOL, options.elffile ); + + if ( _r.s ) + { + genericsReport( V_INFO, "Files: %d" EOL "Functions: %d" EOL "Source: %d" EOL, _r.s->fileCount, _r.s->functionCount, _r.s->sourceCount ); + } } @@ -1449,6 +1520,13 @@ int main( int argc, char *argv[] ) _r.er[e].visits = _r.er[e].maxDepth = _r.er[e].totalTime = _r.er[e].minTime = _r.er[e].maxTime = _r.er[e].maxWallTime = 0; } + /* ... and the event counters */ + for ( uint32_t i = 0; i < DWT_NUM_EVENTS; i++ ) + { + _r.dwt_event_acc[i] = 0; + } + + /* It's safe to update these here because the ticks won't be updated until more * records arrive. */ if ( _r.ITMoverflows != ITMDecoderGetStats( &_r.i )->overflow ) @@ -1471,6 +1549,11 @@ int main( int argc, char *argv[] ) ITMDecoderGetStats( &_r.i )->tpiuSyncCount = 0; } } + + if ( options.paceDelay ) + { + usleep( options.paceDelay ); + } } stream->close( stream ); diff --git a/Src/orbtrace.c b/Src/orbtrace.c index c4b0e1b0..63e83909 100644 --- a/Src/orbtrace.c +++ b/Src/orbtrace.c @@ -137,36 +137,36 @@ static void _intHandler( int sig ) static void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -a, --serial-speed: to use (when SWO UART is selected)" EOL ); - genericsPrintf( " -e, --power: , Enable or Disable power. Ch is vtref, vtpwr or all" EOL ); - genericsPrintf( " -h, --help:: This help" EOL ); - genericsPrintf( " -l, --list: Show all OrbTrace devices attached to system" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -T, --trace-format: Trace format; 1,2 or 4 bit parallel with TPIU decode," EOL \ - " m for Manchester SWO, u=UART SWO," EOL \ - " M for Manchester SWO+TPIU, U=UART SWO+TPIU" EOL ); - genericsPrintf( " -n, --serial-number: any part of serial number to differentiate specific OrbTrace device" EOL ); - genericsPrintf( " -p, --voltage: , Set voltage in V, Ch is vtref or vtpwr" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - - // genericsPrintf( " *-b: Set default brightness of output leds" EOL ); - // genericsPrintf( " *-F: Force voltage setting" EOL ); - // genericsPrintf( " *-j: Format output in JSON" EOL ); - // genericsPrintf( " *-L: Lock device (prevent further changes)" EOL ); - // genericsPrintf( " *-N: Specify nickname for adaptor (8 chars max)" EOL ); - // genericsPrintf( " *-q: Query all data from connected device" EOL ); - // genericsPrintf( " *-Q: Query specified data from connected device (pPrR VPwr/IPwr/VRef/IRef)" EOL ); - // genericsPrintf( " *-U: Unlock device (allow changes, default state)" EOL ); - // genericsPrintf( " *-w: Write parameters specified on command line to NVRAM" EOL ); - // genericsPrintf( " *-W: Reset all NVRAM parameters to default values" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -a, --serial-speed: to use (when SWO UART is selected)" EOL ); + genericsFPrintf( stderr, " -e, --power: , Enable or Disable power. Ch is vtref, vtpwr or all" EOL ); + genericsFPrintf( stderr, " -h, --help:: This help" EOL ); + genericsFPrintf( stderr, " -l, --list: Show all OrbTrace devices attached to system" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -T, --trace-format: Trace format; 1,2 or 4 bit parallel with TPIU decode," EOL \ + " m for Manchester SWO, u=UART SWO," EOL \ + " M for Manchester SWO+TPIU, U=UART SWO+TPIU" EOL ); + genericsFPrintf( stderr, " -n, --serial-number: any part of serial number to differentiate specific OrbTrace device" EOL ); + genericsFPrintf( stderr, " -p, --voltage: , Set voltage in V, Ch is vtref or vtpwr" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + + // genericsFPrintf( stderr, " *-b: Set default brightness of output leds" EOL ); + // genericsFPrintf( stderr, " *-F: Force voltage setting" EOL ); + // genericsFPrintf( stderr, " *-j: Format output in JSON" EOL ); + // genericsFPrintf( stderr, " *-L: Lock device (prevent further changes)" EOL ); + // genericsFPrintf( stderr, " *-N: Specify nickname for adaptor (8 chars max)" EOL ); + // genericsFPrintf( stderr, " *-q: Query all data from connected device" EOL ); + // genericsFPrintf( stderr, " *-Q: Query specified data from connected device (pPrR VPwr/IPwr/VRef/IRef)" EOL ); + // genericsFPrintf( stderr, " *-U: Unlock device (allow changes, default state)" EOL ); + // genericsFPrintf( stderr, " *-w: Write parameters specified on command line to NVRAM" EOL ); + // genericsFPrintf( stderr, " *-W: Reset all NVRAM parameters to default values" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "Orbtrace version " GIT_DESCRIBE ); + genericsFPrintf( stderr, "Orbtrace version " GIT_DESCRIBE ); } // ==================================================================================================== static struct option _longOptions[] = @@ -416,7 +416,7 @@ static int _processOptions( struct RunTime *r, int argc, char *argv[] ) case 'V': /* Print the version of this utility, and schedule to get the version of the probes */ _printVersion(); - genericsPrintf( EOL "Attached Probe(s);" EOL ); + genericsFPrintf( stderr, EOL "Attached Probe(s);" EOL ); _set_action( r, ACTION_LIST_DEVICES ); break; diff --git a/Src/orbtraceIf.c b/Src/orbtraceIf.c index 602e4d80..226b0120 100644 --- a/Src/orbtraceIf.c +++ b/Src/orbtraceIf.c @@ -402,14 +402,14 @@ void OrbtraceIfListDevices( struct OrbtraceIf *o ) char printConstruct[SCRATCH_STRINGLEN]; /* Get longest line */ - genericsPrintf( C_RESET " Id | Description | Serial | Version" EOL ); - genericsPrintf( " ---+---------------------------------------------------+------------------+----------------------------" EOL ); + genericsFPrintf( stderr, C_RESET " Id | Description | Serial | Version" EOL ); + genericsFPrintf( stderr, " ---+---------------------------------------------------+------------------+----------------------------" EOL ); for ( int i = 0; i < o->numDevices; i++ ) { snprintf( printConstruct, MAX_DESC_FIELDLEN, "%s %s", OrbtraceIfGetManufacturer( o, i ), OrbtraceIfGetProduct( o, i ) ) ; - genericsPrintf( C_SEL " %2d " C_RESET "|"C_ELEMENT" %-49s "C_RESET"|"C_ELEMENT" %16s "C_RESET"|"C_ELEMENT" %s" C_RESET EOL, - i + 1, printConstruct, OrbtraceIfGetSN( o, i ), OrbtraceIfGetVersion( o, i ) ); + genericsFPrintf( stderr, C_SEL " %2d " C_RESET "|"C_ELEMENT" %-49s "C_RESET"|"C_ELEMENT" %16s "C_RESET"|"C_ELEMENT" %s" C_RESET EOL, + i + 1, printConstruct, OrbtraceIfGetSN( o, i ), OrbtraceIfGetVersion( o, i ) ); } } @@ -427,7 +427,7 @@ int OrbtraceIfSelectDevice( struct OrbtraceIf *o ) while ( ( selection < 1 ) || ( selection > o->numDevices ) ) { - genericsPrintf( EOL C_SEL "Selection>" C_RESET ); + genericsFPrintf( stderr, EOL C_SEL "Selection>" C_RESET ); scanf( "%d", &selection ); } } diff --git a/Src/orbuculum.c b/Src/orbuculum.c index 8dd7ded4..316ab22e 100644 --- a/Src/orbuculum.c +++ b/Src/orbuculum.c @@ -351,41 +351,41 @@ static void _intHandler( int sig ) void _printHelp( const char *const progName, struct RunTime *r ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -a, --serial-speed: to use" EOL ); - genericsPrintf( " -E, --eof: When reading from file, terminate at end of file" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -l, --listen-port: Listen port for incoming ORBFLOW connections (defaults to %d)" EOL, r->options->listenPort ); - genericsPrintf( " -m, --monitor: Output monitor information about the link at ms, min 500ms" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -n, --serial-number: any part of serial number to differentiate specific device" EOL ); - genericsPrintf( " -o, --output-file: to be used for dump file" EOL ); - genericsPrintf( " -O, --orbtrace: \"\" run orbtrace with specified options on device connect" EOL ); - genericsPrintf( " -p, --serial-port: to use" EOL ); - genericsPrintf( " -P, --pace: delay in block of data transmission to clients" EOL ); - genericsPrintf( " -s, --server: : to use" EOL ); - genericsPrintf( " -T, --tpiu: Strip TPIU framing from input flows (mostly not relevant)" EOL ); - genericsPrintf( " -t, --tag: Legacy TPIU streams to decode and route (Default %s)" EOL, r->options->channelList ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version, connected usb devices, and exit" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -a, --serial-speed: to use" EOL ); + genericsFPrintf( stderr, " -E, --eof: When reading from file, terminate at end of file" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -l, --listen-port: Listen port for incoming ORBFLOW connections (defaults to %d)" EOL, r->options->listenPort ); + genericsFPrintf( stderr, " -m, --monitor: Output monitor information about the link at ms, min 500ms" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -n, --serial-number: any part of serial number to differentiate specific device" EOL ); + genericsFPrintf( stderr, " -o, --output-file: to be used for dump file" EOL ); + genericsFPrintf( stderr, " -O, --orbtrace: \"\" run orbtrace with specified options on device connect" EOL ); + genericsFPrintf( stderr, " -p, --serial-port: to use" EOL ); + genericsFPrintf( stderr, " -P, --pace: delay in block of data transmission to clients" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use" EOL ); + genericsFPrintf( stderr, " -T, --tpiu: Strip TPIU framing from input flows (mostly not relevant)" EOL ); + genericsFPrintf( stderr, " -t, --tag: Legacy TPIU streams to decode and route (Default %s)" EOL, r->options->channelList ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version, connected usb devices, and exit" EOL ); } // ==================================================================================================== void _printVersion( struct RunTime *r ) { - genericsPrintf( "orbuculum version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orbuculum version " GIT_DESCRIBE EOL ); r->o = OrbtraceIfCreateContext(); int ndevices = OrbtraceIfGetDeviceList( r->o, NULL, DEVTYPE( DEVICE_ORBTRACE_MINI ) | DEVTYPE( DEVICE_BMP ) ); if ( !ndevices ) { - genericsPrintf( "No devices found" EOL ); + genericsFPrintf( stderr, "No devices found" EOL ); } else { - genericsPrintf( "Device%s Found;" EOL, ( ndevices > 1 ) ? "s" : "" ); + genericsFPrintf( stderr, "Device%s Found;" EOL, ( ndevices > 1 ) ? "s" : "" ); OrbtraceIfListDevices( r->o ); } @@ -544,6 +544,7 @@ bool _processOptions( int argc, char *argv[], struct RunTime *r ) if ( *a == ':' ) { + *a = 0; r->options->nwserverPort = atoi( ++a ); } @@ -721,19 +722,19 @@ void _checkInterval( void *params ) if ( r->conn ) { - genericsPrintf( C_PREV_LN C_DATA ); + genericsFPrintf( stdout, C_PREV_LN C_DATA ); if ( snapInterval / 1000000 ) { - genericsPrintf( "%4d.%d " C_RESET "MBits/sec ", snapInterval / 1000000, ( snapInterval * 1 / 100000 ) % 10 ); + genericsFPrintf( stdout, "%4d.%d " C_RESET "MBits/sec ", snapInterval / 1000000, ( snapInterval * 1 / 100000 ) % 10 ); } else if ( snapInterval / 1000 ) { - genericsPrintf( "%4d.%d " C_RESET "KBits/sec ", snapInterval / 1000, ( snapInterval / 100 ) % 10 ); + genericsFPrintf( stdout, "%4d.%d " C_RESET "KBits/sec ", snapInterval / 1000, ( snapInterval / 100 ) % 10 ); } else { - genericsPrintf( " %4d " C_RESET " Bits/sec ", snapInterval ); + genericsFPrintf( stdout, " %4d " C_RESET " Bits/sec ", snapInterval ); } uint64_t totalPct = 0; @@ -755,11 +756,11 @@ void _checkInterval( void *params ) { if ( ( !r->tagCount[i].hasHandler ) && r->options->useTPIU ) { - genericsPrintf( C_NOCHAN" [%d:" "%3d%%] " C_RESET, i, w / 10 ); + genericsFPrintf( stdout, C_NOCHAN" [%d:" "%3d%%] " C_RESET, i, w / 10 ); } else { - genericsPrintf( " %d:" C_DATA"%3d%% " C_RESET, i, w / 10 ); + genericsFPrintf( stdout, " %d:" C_DATA"%3d%% " C_RESET, i, w / 10 ); } } @@ -767,18 +768,18 @@ void _checkInterval( void *params ) } w = ( totalPct < 1000 ) ? 1000 - totalPct : 0; - genericsPrintf( " Waste:" C_DATA "%2d.%01d%% " C_RESET, w / 10, w % 10 ); + genericsFPrintf( stdout, " Waste:" C_DATA "%2d.%01d%% " C_RESET, w / 10, w % 10 ); } if ( r->options->dataSpeed > 100 ) { /* Conversion to percentage done as a division to avoid overflow */ uint32_t fullPercent = ( snapInterval * 100 ) / r->options->dataSpeed; - genericsPrintf( "(" C_DATA " %3d%% " C_RESET "full)", ( fullPercent > 100 ) ? 100 : fullPercent ); + genericsFPrintf( stdout, "(" C_DATA " %3d%% " C_RESET "full)", ( fullPercent > 100 ) ? 100 : fullPercent ); } genericsReport( V_INFO, "Ce=%d Oe=%d", OFLOWGetCOBSErrors( &_r.oflow ), OFLOWGetErrors( &_r.oflow ) ); - genericsPrintf( " " C_RESET C_CLR_LN EOL ); + genericsFPrintf( stdout, " " C_RESET C_CLR_LN EOL ); } r->intervalRawBytes = 0; @@ -1009,11 +1010,8 @@ static void _handleBlock( struct RunTime *r, ssize_t fillLevel, uint8_t *buffer if ( r->usingOFLOW ) { - if ( r->options->intervalReportTime ) - { - /* We need to decode this so we can get the stats out of it .. we don't bother if we don't need stats */ - OFLOWPump( &r->oflow, buffer, fillLevel, _OFLOWpacketRxed, r ); - } + /* We need to decode this so we can get the stats out of it, and to reflect it out */ + OFLOWPump( &r->oflow, buffer, fillLevel, _OFLOWpacketRxed, r ); /* ...and reflect this packet to the outgoing OFLOW channels, if we don't need to reconstruct them */ if ( !r->options->useTPIU ) @@ -1615,7 +1613,7 @@ int main( int argc, char *argv[] ) } /* Blank line for tidyness' sake */ - genericsPrintf( EOL ); + genericsFPrintf( stdout, EOL ); if ( ( _r.options->nwserverPort ) || ( _r.options->port ) || ( _r.options->file ) ) { diff --git a/Src/orbzmq.c b/Src/orbzmq.c index a83030ae..a18e6b99 100644 --- a/Src/orbzmq.c +++ b/Src/orbzmq.c @@ -414,32 +414,32 @@ void _itmPumpProcess( char c ) void _printHelp( const char *const progName ) { - genericsPrintf( "Usage: %s [options]" EOL, progName ); - genericsPrintf( " -c, --channel: ,, of channel to populate (repeat per channel)" EOL ); - genericsPrintf( " -e, --hwevent: Comma-separated list of published hwevents" EOL ); - genericsPrintf( " -E, --eof: Terminate when the file/socket ends/is closed, otherwise wait to reconnect" EOL ); - genericsPrintf( " -f, --input-file: Take input from specified file" EOL ); - genericsPrintf( " -h, --help: This help" EOL ); - genericsPrintf( " -M, --no-colour: Supress colour in output" EOL ); - genericsPrintf( " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); - genericsPrintf( " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); - genericsPrintf( " -s, --server: : to use, default %s:%d" EOL, options.server, options.port ); - genericsPrintf( " -t, --tag: : Which Orbflow tag to use (normally 1)" EOL ); - genericsPrintf( " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); - genericsPrintf( " -V, --version: Print version and exit" EOL ); - genericsPrintf( " -z, --zbind: : ZeroMQ bind URL, default %s" EOL, options.bindUrl ); - genericsPrintf( EOL ); - genericsPrintf( "Available HW events: " EOL ); - genericsPrintf( " all - All hwevents TS - Timestamp" EOL ); - genericsPrintf( " EXCP - Exception entry/exit PC - PC sampling" EOL ); - genericsPrintf( " DWT - DWT event RWWT - Read/write watchpoint" EOL ); - genericsPrintf( " AWP - Access watchpoint OFS - Data offset" EOL ); + genericsFPrintf( stderr, "Usage: %s [options]" EOL, progName ); + genericsFPrintf( stderr, " -c, --channel: ,, of channel to populate (repeat per channel)" EOL ); + genericsFPrintf( stderr, " -e, --hwevent: Comma-separated list of published hwevents" EOL ); + genericsFPrintf( stderr, " -E, --eof: Terminate when the file/socket ends/is closed, otherwise wait to reconnect" EOL ); + genericsFPrintf( stderr, " -f, --input-file: Take input from specified file" EOL ); + genericsFPrintf( stderr, " -h, --help: This help" EOL ); + genericsFPrintf( stderr, " -M, --no-colour: Supress colour in output" EOL ); + genericsFPrintf( stderr, " -n, --itm-sync: Enforce sync requirement for ITM (i.e. ITM needs to issue syncs)" EOL ); + genericsFPrintf( stderr, " -p, --protocol: Protocol to communicate. Defaults to OFLOW if -s is not set, otherwise ITM" EOL ); + genericsFPrintf( stderr, " -s, --server: : to use, default %s:%d" EOL, options.server, options.port ); + genericsFPrintf( stderr, " -t, --tag: : Which Orbflow tag to use (normally 1)" EOL ); + genericsFPrintf( stderr, " -v, --verbose: Verbose mode 0(errors)..3(debug)" EOL ); + genericsFPrintf( stderr, " -V, --version: Print version and exit" EOL ); + genericsFPrintf( stderr, " -z, --zbind: : ZeroMQ bind URL, default %s" EOL, options.bindUrl ); + genericsFPrintf( stderr, EOL ); + genericsFPrintf( stderr, "Available HW events: " EOL ); + genericsFPrintf( stderr, " all - All hwevents TS - Timestamp" EOL ); + genericsFPrintf( stderr, " EXCP - Exception entry/exit PC - PC sampling" EOL ); + genericsFPrintf( stderr, " DWT - DWT event RWWT - Read/write watchpoint" EOL ); + genericsFPrintf( stderr, " AWP - Access watchpoint OFS - Data offset" EOL ); } // ==================================================================================================== void _printVersion( void ) { - genericsPrintf( "orbcat version " GIT_DESCRIBE EOL ); + genericsFPrintf( stderr, "orbcat version " GIT_DESCRIBE EOL ); } static int32_t _parseHWEventsArg( char *s ) diff --git a/Src/symbols.c b/Src/symbols.c index 2158ef16..13bd93cb 100644 --- a/Src/symbols.c +++ b/Src/symbols.c @@ -30,7 +30,7 @@ #define NO_FILE_TXT "No Source" //#define GPTI_DEBUG 1 /* Define this for objdump data collection state machine trace */ - +//#define _DUMP_SYMBOLS /* Define this to dump all symbols at start of run */ #ifdef GPTI_DEBUG #define GTPIP(...) { fprintf(stderr, __VA_ARGS__); } #else @@ -261,6 +261,11 @@ static enum LineType _getLineType( char *sourceLine, char *p1, char *p2, char *p /* If it has something with in it, it's a proc label (function) */ if ( 2 == sscanf( sourceLine, "%[0-9a-fA-F] <%[^>]>", p1, p2 ) ) { + /* Demangled C++ names may have multiple ">" characters. Expand until last one. */ + const char *const beg = strchr( sourceLine, '<' ) + 1; + const char *const end = strrchr( beg, '>' ); + ( void )memcpy( p2, beg, end - beg ); + p2[end - beg] = '\0'; return LT_PROC_LABEL; } @@ -849,6 +854,26 @@ static enum symbolErr _getTargetProgramInfo( struct SymbolSet *s ) #endif _sortLines( s ); + +#ifdef _DUMP_SYMBOLS + uint32_t sline = 0; + uint32_t functionindex = s->sources[0].functionIdx; + uint32_t firstaddr = s->sources[0].startAddr; + + while ( sline < s->sourceCount - 1 ) + { + if ( s->sources[sline + 1].functionIdx != functionindex ) + { + printf( "%08x-%08x %s" EOL, firstaddr, s->sources[sline].endAddr, s->functions[functionindex].name ); + functionindex = s->sources[sline + 1].functionIdx; + firstaddr = s->sources[sline + 1].startAddr; + } + + sline++; + } + +#endif + return SYMBOL_OK; } // ==================================================================================================== @@ -925,7 +950,6 @@ bool SymbolLookup( struct SymbolSet *s, uint32_t addr, struct nameEntry *n ) return true; } - n->fileindex = n->functionindex = n->line = 0; n->source = ""; n->assy = NULL; diff --git a/Src/traceDecoder_etm4.c b/Src/traceDecoder_etm4.c index d90c7f8a..99811f81 100644 --- a/Src/traceDecoder_etm4.c +++ b/Src/traceDecoder_etm4.c @@ -185,6 +185,12 @@ static bool _pumpAction( struct TRACEDecoderEngine *e, struct TRACECPUState *cpu } 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 ) @@ -336,7 +342,7 @@ 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 ) + 4; cpu->instCount = cpu->eatoms; cpu->disposition = ( 1 << ( cpu->eatoms ) ) - 1; @@ -404,6 +410,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 */ @@ -685,7 +693,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 ) ); diff --git a/Support/60-orbcode.rules b/Support/60-orbcode.rules index 1501072c..a32ba006 100644 --- a/Support/60-orbcode.rules +++ b/Support/60-orbcode.rules @@ -4,9 +4,9 @@ ACTION!="add|change|bind", GOTO="orb_rules_end" SUBSYSTEM!="usb|tty|hidraw", GOTO="orb_rules_end" -# Orbrace mini in bootloader mode -ATTRS{idVendor}=="1209" ATTRS{idProduct}=="3442", GROUP="plugdev", TAG+="uaccess" -# Orbrace mini -ATTRS{idVendor}=="1209" ATTRS{idProduct}=="3443", GROUP="plugdev", TAG+="uaccess" +# Orbtrace mini in bootloader mode +ATTRS{idVendor}=="1209", ATTRS{idProduct}=="3442", GROUP="plugdev", TAG+="uaccess" +# Orbtrace mini +ATTRS{idVendor}=="1209", ATTRS{idProduct}=="3443", GROUP="plugdev", TAG+="uaccess" LABEL="orb_rules_end" diff --git a/Support/gdbtrace.init b/Support/gdbtrace.init index 00d5b728..fc0c8513 100644 --- a/Support/gdbtrace.init +++ b/Support/gdbtrace.init @@ -9,7 +9,7 @@ GDB SWO Trace Configuration Helpers Setup Device ------------ STM32; - enableSTM32SWO : Enable SWO on STM32 pins (for F4 or F7 if 4/7 is passed as first argument) + enableSTM32SWO : Enable SWO on STM32 pins enableSTM32TRACE: Start TRACE on STM32 pins IMXRT; @@ -81,8 +81,8 @@ end # Definitions for the CPU types we currently support set $CPU_IMXRT102X=1 -set $CPU_STM32=2 set $CPU_IMXRT106X=1 +set $CPU_STM32F1F4F7=2 set $CPU_NRF=3 set $CPU_EFR32=4 set $CPU_TM4C=5 @@ -90,6 +90,8 @@ set $CPU_S32K344=6 set $CPU_IMXRT117X=7 set $CPU_KINETIS=8 set $CPU_SAMD5x=9 +set $CPU_STM32M33=10 +set $CPU_STM32H7=11 # ==================================================================== set $CDBBASE=0xE000EDF0 @@ -97,11 +99,63 @@ set $DWTBASE=0xE0001000 set $ITMBASE=0xE0000000 set $TPIUBASE=0xE0040000 set $ETMBASE=0xE0041000 +set $CTIBASE=0xE0042000 + +define setTRCENA + set *($CDBBASE+0xC)|=(1<<24) +end +document setTRCENA +setTRCENA Enables trace peripherals (DWT,ITM,ETM) in DEMCR. +end + +define unlockComponent + set *($arg0 + 0xfb0) = 0xc5acce55 +end define _setAddressesSTM32 # Locations in the memory map for interesting things on STM32 - set $RCCBASE = 0x40023800 - set $GPIOBASE = 0x40020000 + + set $dev = $arg0 + + if ! $dev + # Device type not specified, detect from DBGMCU ID register. + if (*0x5C001000 & 0x7ff) == 0x450 + set $CPU = $CPU_STM32H7 + else + set $CPU = $CPU_STM32F1F4F7 + end + else + if $dev == 33 + set $CPU = $CPU_STM32M33 + end + if ($dev == 1) || ($dev == 4) || ($dev == 7) + set $CPU = $CPU_STM32F1F4F7 + end + end + + if $CPU == $CPU_STM32M33 + set $GPIOBASE = 0x42020000 + set $RCCGPIO = 0x46020c8c + set $DBGMCU_CR = 0xE0044004 + end + + if $CPU == $CPU_STM32H7 + set $GPIOBASE = 0x58020000 + set $RCCGPIO = 0x580244E0 + set $DBGMCU_CR = 0x5C001004 + set $SWOBASE = 0x5C003000 + set $SWTFBASE = 0x5C004000 + set $CSTFBASE = 0x5C013000 + set $ETFBASE = 0x5C014000 + set $TPIUBASE = 0x5C015000 + end + + if $CPU == $CPU_STM32F1F4F7 + set $GPIOBASE = 0x40020000 + set $RCCGPIO = 0x40023830 + set $DBGMCU_CR = 0xE0042004 + set $RRCGPIO = 0x40023830 + end end define _setAddressesIMXRT @@ -264,12 +318,12 @@ define _setupTraceBusS32K344 end # Enable access to the funnels and ETFs. - set *($FUNNEL_0_BASE + 0xfb0) = 0xc5acce55 - set *($FUNNEL_1_BASE + 0xfb0) = 0xc5acce55 - set *($FUNNEL_2_BASE + 0xfb0) = 0xc5acce55 - set *($ETF_CM7_CLUSTER_ETMI_BASE + 0xfb0) = 0xc5acce55 - set *($ETF_CM7_CLUSTER_ETMD_BASE + 0xfb0) = 0xc5acce55 - set *($ETF_SHARED_SYSTEM_BASE + 0xfb0) = 0xc5acce55 + unlockComponent $FUNNEL_0_BASE + unlockComponent $FUNNEL_1_BASE + unlockComponent $FUNNEL_2_BASE + unlockComponent $ETF_CM7_CLUSTER_ETMI_BASE + unlockComponent $ETF_CM7_CLUSTER_ETMD_BASE + unlockComponent $ETF_SHARED_SYSTEM_BASE # Enable all inputs of all funnels to ensure that all trace sources # can pass. Enabling all inputs is probably not optimal, so this @@ -353,7 +407,7 @@ end define _startETMv35 # Allow access to device - set *($ETMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ETMBASE # Enter configuration mode (write twice to be sure we reached it) set *($ETMBASE) = (1<<10) @@ -583,34 +637,43 @@ define prepareSWO end # Make sure we can get to everything - set *($ITMBASE+0xfb0) = 0xc5acce55 - set *($ETMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE + unlockComponent $DWTBASE - set *($CDBBASE+0xC)|=(1<<24) + set $_formatterPresent=1 + set $_protocolBase=$TPIUBASE + if $CPU == $CPU_STM32H7 + set $_formatterPresent=0 + set $_protocolBase=$SWOBASE + unlockComponent $SWOBASE + end + + setTRCENA if ($useMan==0) # Use Async mode pin protocol (TPIU_SPPR) - set *($TPIUBASE+0xF0) = 2 + set *($_protocolBase+0xF0) = 2 else # Use Manchester mode pin protocol (TPIU_SPPR) - set *($TPIUBASE+0xF0) = 1 + set *($_protocolBase+0xF0) = 1 # There are two edges in a bit, so double the clock set $speed = $speed*2 end # Output bits at speed dependent on system clock - set *($TPIUBASE+0x10) = ((($clockspeed+$speed-1)/$speed)-1) + set *($_protocolBase+0x10) = ((($clockspeed+$speed-1)/$speed)-1) - if ($useTPIU==1) - # Use TPIU formatter and flush - set *($TPIUBASE+0x304) = 0x102 - else - set *($TPIUBASE+0x304) = 0x100 + if $_formatterPresent==1 + if $useTPIU==1 + # Use TPIU formatter and flush + set *($TPIUBASE+0x304) = 0x102 + else + set *($TPIUBASE+0x304) = 0x100 + end end # Flush all initial configuration - set *($CDBBASE+0xC)|=(1<<24) set *($DWTBASE) = 0 set *($ITMBASE+0xe80) = 0 @@ -838,10 +901,10 @@ define enableIMXRT117XSWO _setAddressesIMXRT117X # Configure trace funnels/ATB. - set *($FUNNEL_CSSYS_BASE + 0xfb0) = 0xc5acce55 + unlockComponent $FUNNEL_CSSYS_BASE set *($FUNNEL_CSSYS_BASE) |= 0xff - set *($FUNNEL_M7_BASE + 0xfb0) = 0xc5acce55 + unlockComponent $FUNNEL_M7_BASE set *($FUNNEL_M7_BASE) |= 0xff # TODO: configure trace subsystem clocks. @@ -851,7 +914,7 @@ define enableIMXRT117XSWO set *(0x40c0806c) = 0x2 # Allow access to SWO TPIU registers. - set *($TPIU_SWO_BASE + 0xfb0) = 0xc5acce55 + unlockComponent $TPIU_SWO_BASE # Set $TPIUBASE for use by other commands in this file. set $TPIUBASE = $TPIU_SWO_BASE @@ -859,8 +922,6 @@ define enableIMXRT117XSWO #set language auto end -# ==================================================================== - define enableKinetisSWO _setAddressesKinetis set language c @@ -878,35 +939,52 @@ define enableKinetisSWO set language auto end +# ==================================================================== + define enableSTM32SWO #set language c - set $tgt=1 + set $dev=0 if $argc >= 1 - set $tgt = $arg0 + set $dev = $arg0 + end + _setAddressesSTM32 $dev + + if $CPU == $CPU_STM32H7 + # Set D1DBGCKEN, D3DBGCKEN + set *$DBGMCU_CR |= 7 | (6 << 20) + # Unlock SWO trace funnel. + unlockComponent $SWTFBASE + # Enable port S0 in SWO trace funnel. + set *($SWTFBASE + 0x000) = 0x00000301 + # SWO on PB3 + enableSTM32Pin 1 3 3 end - set $CPU=$CPU_STM32 - _setAddressesSTM32 + if ($CPU == $CPU_STM32F1F4F7) + if (($dev==4) || ($dev==7)) + # STM32F4/7 variant: SWO on PB3. + enableSTM32Pin 1 3 3 + else + # STM32F1 variant. + # RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; + set *0x40021018 |= 1 + # AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO + set *0x40010004 |= 0x2000000 + end + end - if (($tgt==4) || ($tgt==7)) - # STM32F4/7 variant: SWO on PB3. - enableSTM32Pin 1 3 3 - else - # STM32F1 variant. - # RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; - set *0x40021018 |= 1 - # AFIO->MAPR |= (2 << 24); // Disable JTAG to release TRACESWO - set *0x40010004 |= 0x2000000 + if $CPU != $CPU_STM32H7 + # Common initialisation. + # DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; + set *$DBGMCU_CR |= 0x20 end - # Common initialisation. - # DBGMCU->CR |= DBGMCU_CR_TRACE_IOEN; - set *0xE0042004 |= 0x20 #set language auto end document enableSTM32SWO -enableSTM32SWO Configure output pin on STM32 for SWO use. +enableSTM32SWO Configure output pin on STM32 for SWO use. + : Type of STM32 Device 1=f1, 4=f4, 7=f7, 33=M33 end # ==================================================================== define enableSAMD5XSWD @@ -993,9 +1071,7 @@ end define _doTRACE # Must be called with $bits containing number of bits to set trace for - set *($ITMBASE+0xfb0) = 0xc5acce55 - set *($ETMBASE+0xfb0) = 0xc5acce55 - set *($TPIUBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE # Set port size (TPIU_CSPSR) set *($TPIUBASE+4) = (1<<$bits) @@ -1009,11 +1085,11 @@ end # ==================================================================== define enableSTM32Pin #set language c - _setAddressesSTM32 + set $_GPIOPORT = $GPIOBASE + 0x400 * $arg0 # Enable GPIO port in RCC - set *($RCCBASE + 0x30) |= (0x1<<$arg0) + set *($RCCGPIO) |= (0x1<<$arg0) # MODER: Alternate Function set *($_GPIOPORT+0x00) &= ~(0x3<<2*$arg1) @@ -1057,6 +1133,7 @@ define enableSTM32TRACE set $bits=4 set $drive=1 + set $dev=1 if $argc >= 1 set $bits = $arg0 @@ -1069,21 +1146,46 @@ define enableSTM32TRACE set $drive = $arg1 end + if $argc >= 3 + set $dev = $arg2 + end + if ($drive > 3) help enableSTM32TRACE end set $bits = $bits-1 - set $CPU=$CPU_STM32 - _setAddressesSTM32 + _setAddressesSTM32 $dev # Enable Trace TRCENA (DCB DEMCR) needed for clocks - set *($CDBBASE+0xC)=(1<<24) + setTRCENA + + + if ($CPU == $CPU_STM32H7) + # Enable TRACECKEN, D1DBGCKEN + set *$DBGMCU_CR |= 7 | (3 << 20) - # Enable compensation cell - set *0x40023844 |= (1<<14) - set *0x40013820 |=1 + unlockComponent $ETFBASE + unlockComponent $CSTFBASE + unlockComponent $TPIUBASE + + # Hardware FIFO mode + set *($ETFBASE + 0x028) = 2 + # Formatter and flush control + set *($ETFBASE + 0x304) |= 1 + # Enable ETF trace capture + set *($ETFBASE + 0x020) = 1 + + # Enable both ETM and ITM in trace funnel. bit0=ETM, bit1=ITM + set *($CSTFBASE + 0x000) |= 3 + else + if $CPU != $CPU_STM32M33 + # Enable compensation cell + set *($RRCGPIO+0x14) |= (1<<14) + set *0x40013820 |=1 + end + end # Setup PE2 & PE3 enableSTM32Pin 4 2 $drive @@ -1100,27 +1202,37 @@ define enableSTM32TRACE enableSTM32Pin 4 6 $drive end - # Set number of bits in DBGMCU_CR - set *0xE0042004 &= ~(3<<6) + if $CPU != $CPU_STM32H7 + # Set number of bits in DBGMCU_CR + set *$DBGMCU_CR &= ~(3<<6) - if ($bits<3) - set *0xE0042004 |= ((($bits+1)<<6) | (1<<5)) - else - set *0xE0042004 |= ((3<<6) | (1<<5)) + if ($bits<3) + set *$DBGMCU_CR |= ((($bits+1)<<6) | (1<<5)) + else + set *$DBGMCU_CR |= ((3<<6) | (1<<5)) + end end - # Enable Trace TRCENA (DCB DEMCR) - set *($CDBBASE+0xC)=(1<<24) - # Finally start the trace output - _doTRACE + + # Set port size (TPIU_CURPSIZE) + set *($TPIUBASE+4) = (1<<$bits) + + if $CPU != $CPU_STM32H7 + # Set pin protocol to Sync Trace Port (TPIU_SPPR) + set *($TPIUBASE+0xF0)=0 + end + + # TPIU formatter and flush control register (TPIU_FFCR) + set *($TPIUBASE+0x304) = 0x102 #set language auto end document enableSTM32TRACE enableSTM32TRACE : Enable TRACE on STM32 pins - : Number of bits wide (1,2 or 4 only) - : Drive strength (0=lowest, 3=highest) + : Number of bits wide (1,2 or 4 only, default=4) + : Drive strength (0=lowest, 3=highest, default=1) + : Device type, 33=special for CORTEX-M33, otherwise default end # ==================================================================== define enableNRF52TRACE @@ -1158,7 +1270,7 @@ define enableNRF52TRACE # from modules/nrfx/mdk/system_nrf52.c # CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - set *($CDBBASE+0xC) |= (1<<24) + setTRCENA # NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos; set *($NRF_CLOCK+0x0000055C) &= ~(3 << 16) @@ -1266,7 +1378,7 @@ define enableNRF53TRACE set *($NRF_TAD_S+0x518) = $cspeed # Enable Trace TRCENA (DCB DEMCR) - set *($CDBBASE+0xC)=(1<<24) + setTRCENA # Finally start the trace output _doTRACE @@ -1358,7 +1470,7 @@ define enableTM4C123TRACE end # Enable Trace TRCENA (DCB DEMCR) - set *($CDBBASE+0xC)=(1<<24) + setTRCENA # Finally start the trace output _doTRACE @@ -1480,7 +1592,7 @@ define enableLPC176xTRACE set *0x4002C028 = (1 << 3) # Enable Trace TRCENA (DCB DEMCR) - set *($CDBBASE+0xC)=(1<<24) + setTRCENA # Start tracing set $bits = $bits-1 @@ -1550,17 +1662,8 @@ define enableSAMD5XTRACE set *(unsigned char *)(0x41008000+0x80*2+0x40+24) = (($drive) << 6) | 1 end - # Set number of bits in DBGMCU_CR - set *0xE0042004 &= ~(3<<6) - - if ($bits<3) - set *0xE0042004 |= ((($bits+1)<<6) | (1<<5)) - else - set *0xE0042004 |= ((3<<6) | (1<<5)) - end - # Enable Trace TRCENA (DCB DEMCR) - set *($CDBBASE+0xC)=(1<<24) + setTRCENA # Finally start the trace output _doTRACE @@ -1579,7 +1682,7 @@ define dwtPOSTCNT if ($argc!=1) help dwtPOSTCNT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<22) else @@ -1599,7 +1702,7 @@ define dwtFOLDEVT if ($argc!=1) help dwtFOLDEVT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<21) else @@ -1619,7 +1722,7 @@ define dwtLSUEVT if ($argc!=1) help dwtLSUEVT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<20) else @@ -1639,7 +1742,7 @@ define dwtSLEEPEVT if ($argc!=1) help dwtSLEEPEVT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<19) else @@ -1659,7 +1762,7 @@ define dwtDEVEVT if ($argc!=1) help dwtDEVEVT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<18) else @@ -1670,7 +1773,7 @@ define dwtDEVEVT #set language auto end document dwtDEVEVT -dwtDEVEVT <0|1> Enable Exception counter overflow event packet generation +dwtDEVEVT <0|1> Enable Exception overhead counter overflow event packet generation end # ==================================================================== define dwtCPIEVT @@ -1679,7 +1782,7 @@ define dwtCPIEVT if ($argc!=1) help dwtCPIEVT else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<17) else @@ -1699,7 +1802,7 @@ define dwtTraceException if ($argc!=1) help dwtTraceException else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<16) else @@ -1719,7 +1822,7 @@ define dwtSamplePC if ($argc!=1) help dwtSamplePC else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<12) else @@ -1739,7 +1842,7 @@ define dwtSyncTap if (($argc!=1) || ($arg0<0) || ($arg0>3)) help dwtSyncTap else - set *($CDBBASE|0xC) |= 0x1000000 + setTRCENA set *($DWTBASE) &= ~(0x03<<10) set *($DWTBASE) |= (($arg0&0x03)<<10) end @@ -1756,7 +1859,7 @@ define dwtPostTap if (($argc!=1) || ($arg0<0) || ($arg0>1)) help dwtPostTap else - set *($CDBBASE|0xC) |= 0x1000000 + setTRCENA if ($arg0==0) set *($DWTBASE) &= ~(1<<9) else @@ -1776,7 +1879,7 @@ define dwtPostInit if (($argc!=1) || ($arg0<0) || ($arg0>15)) help dwtPostInit else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA set *($DWTBASE) &= ~(0x0f<<5) set *($DWTBASE) |= (($arg0&0x0f)<<5) end @@ -1793,7 +1896,7 @@ define dwtPostReset if (($argc!=1) || ($arg0<0) || ($arg0>15)) help dwtPostReset else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA set *($DWTBASE) &= ~(0x0f<<1) set *($DWTBASE) |= (($arg0&0x0f)<<1) end @@ -1812,7 +1915,7 @@ define dwtCycEna if ($argc!=1) help dwtCycEna else - set *($CDBBASE+0xC) |= 0x1000000 + setTRCENA if ($arg0==1) set *($DWTBASE) |= (1<<0) else @@ -1833,7 +1936,7 @@ define ITMId if (($argc!=1) || ($arg0<0) || ($arg0>127)) help ITMId else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE set *($ITMBASE+0xe80) &= ~(0x7F<<16) set *($ITMBASE+0xe80) |= (($arg0&0x7f)<<16) end @@ -1850,7 +1953,7 @@ define ITMGTSFreq if (($argc!=1) || ($arg0<0) || ($arg0>3)) help ITMGTSFreq else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE set *($ITMBASE+0xe80) &= ~(0x3<<10) set *($ITMBASE+0xe80) |= (($arg0&3)<<10) end @@ -1869,7 +1972,7 @@ define ITMTSPrescale if (($argc!=1) || ($arg0<0) || ($arg0>3)) help ITMTSPrescale else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE set *($ITMBASE+0xe80) &= ~(0x3<<8) set *($ITMBASE+0xe80) |= (($arg0&3)<<8) end @@ -1886,7 +1989,7 @@ define ITMSWOEna if (($argc!=1) || ($arg0<0) || ($arg0>1)) help ITMSWOEna else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE if ($arg0==0) set *($ITMBASE+0xe80) &= ~(0x1<<4) else @@ -1907,7 +2010,7 @@ define ITMTXEna if (($argc!=1) || ($arg0<0) || ($arg0>1)) help ITMTXEna else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE if ($arg0==0) set *($ITMBASE+0xe80) &= ~(0x1<<3) else @@ -1928,7 +2031,7 @@ define ITMSYNCEna if (($argc!=1) || ($arg0<0) || ($arg0>1)) help ITMSYNCEna else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE if ($arg0==0) set *($ITMBASE+0xe80) &= ~(0x1<<2) else @@ -1949,7 +2052,7 @@ define ITMTSEna if (($argc!=1) || ($arg0<0) || ($arg0>1)) help ITMTSEna else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE if ($arg0==0) set *($ITMBASE+0xe80) &= ~(0x1<<1) else @@ -1969,7 +2072,7 @@ define ITMEna if (($argc!=1) || ($arg0<0) || ($arg0>1)) help ITMEna else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE if ($arg0==0) set *($ITMBASE+0xe80) &= ~(0x1<<0) else @@ -1989,7 +2092,7 @@ define ITMTER if (($argc!=2) || ($arg0<0) || ($arg0>7)) help ITMTER else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE set *($ITMBASE+0xe00+4*$arg0) = $arg1 end @@ -2005,7 +2108,7 @@ define ITMTPR if ($argc!=1) help ITMTPR else - set *($ITMBASE+0xfb0) = 0xc5acce55 + unlockComponent $ITMBASE set *($ITMBASE+0xe40) = $arg0 end @@ -2021,7 +2124,7 @@ define tracetest if ($argc!=1) help tracetest else - set *($TPIUBASE+0xfb0) = 0xc5acce55 + unlockComponent $TPIUBASE if ($arg0 == 0) set *($TPIUBASE+0x204) = 0 else diff --git a/meson.build b/meson.build index 8b8f6b10..338af476 100644 --- a/meson.build +++ b/meson.build @@ -115,21 +115,6 @@ executable('orbuculum', install: true, ) -if host_machine.system() != 'windows' - executable('orbfifo', - sources: [ - 'Src/orbfifo.c', - 'Src/filewriter.c', - 'Src/itmfifos.c', - git_version_info_h, - ], - include_directories: incdirs, - dependencies: dependencies, - link_with: liborb, - install: true, - ) -endif - executable('orbcat', sources: [ 'Src/orbcat.c',