QTools  7.3.0
Collection of Host-Based Tools
No Matches
QSPY Dictionaries

QSPY Screen OutputQSPY UDP Interface

About QSPY Dictionaries

By the time you compile and load your application image to the Target, the symbolic names of various objects, function names, and event signal names are stripped from the code. Therefore, if you want to have the symbolic information available to the QSPY host-resident component, you need to supply it somehow to the software tracing system.

The QS Target-resident component provides special dictionary trace records designed expressly for providing the symbolic information about the target code in the trace itself. These "dictionary records" are very much like the symbolic information embedded in the object files for the traditional single-step debugger. QS can supply four types of dictionary trace records:

  • object dictionary — for identifying objects (HSMs, AOs, Time events, etc.)
  • function dictionary — for identifying functions (state-handlers)
  • signal dictionary — for identifying event signals
  • user dictionary — for identifying application-specific (user) records
QSPY does not absolutely require the presence of dictionary trace records to generate the human-readable output, in the same way that the symbolic information in the object files is not absolutely required to be able to debug code. However, in both cases, the availability of the symbolic information greatly improves the readability of the disassembly code shown in the debugger.

For instance, the following listing shows an example of the QSPY text output when the "dictionaries" are not available. (NOTE: dictionaries might not be available because (1) the Target does not produce dictionary trace records for all relevant objects or (2) the Target does produce all dictionaries, but QSPY has never seen them, because it was attached to the Target after the dictionaries have been transmitted):

. . . . . .
0009692721 Disp===> Obj=0x2000133C,Sig=00000010,Obj=0x2000133C,State=0x000010C5
0009693389 USER+000 4 hungry
0009695383 USER+000 4 eating
0009695932 =>Intern Obj=0x2000133C,Sig=00000010,Obj=0x2000133C,State=0x000010C5
===RTC===> St-Entry Obj=0x200012F8,State=0x00000D49
0009697188 ===>Tran Obj=0x200012F8,Sig=00000011,Obj=0x200012F8,State=0x00000DD5->0x00000D49
0009698052 Disp===> Obj=0x200012F8,Sig=00000004,Obj=0x200012F8,State=0x00000D49
===RTC===> St-Entry Obj=0x200012F8,State=0x00000CA9
0009699697 ===>Tran Obj=0x200012F8,Sig=00000004,Obj=0x200012F8,State=0x00000D49->0x00000CA9
0009700602 Disp===> Obj=0x200012B8,Sig=00000004,Obj=0x200012B8,State=0x00000DD5
0009701247 =>Intern Obj=0x200012B8,Sig=00000004,Obj=0x200012B8,State=0x00000DD5
0009702038 Disp===> Obj=0x20001278,Sig=00000004,Obj=0x20001278,State=0x00000DD5
0009702677 =>Intern Obj=0x20001278,Sig=00000004,Obj=0x20001278,State=0x00000DD5
0009703468 Disp===> Obj=0x20001238,Sig=00000004,Obj=0x20001238,State=0x00000DD5
0009704107 =>Intern Obj=0x20001238,Sig=00000004,Obj=0x20001238,State=0x00000DD5
0009704899 Disp===> Obj=0x200011F8,Sig=00000004,Obj=0x200011F8,State=0x00000DD5
0009705538 =>Intern Obj=0x200011F8,Sig=00000004,Obj=0x200011F8,State=0x00000DD5
0015961105 Disp===> Obj=0x200011F8,Sig=00000011,Obj=0x200011F8,State=0x00000DD5
===RTC===> St-Exit  Obj=0x200011F8,State=0x00000DD5
0015962823 Disp===> Obj=0x2000133C,Sig=00000010,Obj=0x2000133C,State=0x000010C5
0015963491 USER+000 0 hungry
. . . . . .

And here is the exact same trace data when the "dictionaries" are available:

. . . . . .
0009692721 Disp===> Obj=l_table,Sig=HUNGRY_SIG,State=Table_serving
0009693389 PHILO_STAT 4 hungry
0009695383 PHILO_STAT 4 eating
0009695932 =>Intern Obj=l_table,Sig=HUNGRY_SIG,State=Table_serving
===RTC===> St-Entry Obj=l_philo[4],State=Philo_hungry
0009697188 ===>Tran Obj=l_philo[4],Sig=TIMEOUT_SIG,State=Philo_thinking->Philo_hungry
0009698052 Disp===> Obj=l_philo[4],Sig=EAT_SIG,State=Philo_hungry
===RTC===> St-Entry Obj=l_philo[4],State=Philo_eating
0009699697 ===>Tran Obj=l_philo[4],Sig=EAT_SIG,State=Philo_hungry->Philo_eating
0009700602 Disp===> Obj=l_philo[3],Sig=EAT_SIG,State=Philo_thinking
0009701247 =>Intern Obj=l_philo[3],Sig=EAT_SIG,State=Philo_thinking
0009702038 Disp===> Obj=l_philo[2],Sig=EAT_SIG,State=Philo_thinking
0009702677 =>Intern Obj=l_philo[2],Sig=EAT_SIG,State=Philo_thinking
0009703468 Disp===> Obj=l_philo[1],Sig=EAT_SIG,State=Philo_thinking
0009704107 =>Intern Obj=l_philo[1],Sig=EAT_SIG,State=Philo_thinking
0009704899 Disp===> Obj=l_philo[0],Sig=EAT_SIG,State=Philo_thinking
0009705538 =>Intern Obj=l_philo[0],Sig=EAT_SIG,State=Philo_thinking
0015961105 Disp===> Obj=l_philo[0],Sig=TIMEOUT_SIG,State=Philo_thinking
===RTC===> St-Exit  Obj=l_philo[0],State=Philo_thinking
0015962823 Disp===> Obj=l_table,Sig=HUNGRY_SIG,State=Table_serving
0015963491 PHILO_STAT 0 hungry
. . . . . .

As you can see, the difference in readability is quite dramatic.

Acquiring Dictionaries

The QS Target-resident component generates the dictionary trace records during the initialization of active object components in the Target code, that is, typically right after the reset. Consequently, the best way to acquire the dictionaries is to capture the trace when the Target performs the reset. This can be done in a couple of ways:

  • Start QSPY before the Target resets
  • Manually reset the Target while QSPY is running (e.g., press a Reset button on the Target board)
  • Send the RESET command to the Target from QSPY while it is running

Either way, the dictionary records should be produced and acquired by the Target. The following listing shows the dictionary records sent by the DPP example application running on a STM32 NUCLEO board:

C:\qp\qpc\examples\arm-cm\dpp_nucleo-l152re\qk\gnu>qspy -cCOM7
QQSPY 6.9.0 Copyright (c) 2005-2020 Quantum Leaps
Documentation: https://www.state-machine.com/qtools/qspy.html
Current timestamp: 200827_093625
-c COM7
-u 7701
-v 620
-T 4
-O 4
-F 4
-S 2
-E 2
-Q 1
-P 2
-B 2
-C 2

########## Trg-RST  QP-Ver=690,Build=200824_123230
           Obj-Dict 0x20001048->QS_RX
           Obj-Dict 0x08004009->l_SysTick_Handler
           Usr-Dict 00000100->PHILO_STAT
           Obj-Dict 0x20000EE0->AO_Table
           Obj-Dict 0x20000DDC->AO_Philo[0]
           Obj-Dict 0x20000E10->AO_Philo[1]
           Obj-Dict 0x20000E44->AO_Philo[2]
           Obj-Dict 0x20000E78->AO_Philo[3]
           Obj-Dict 0x20000EAC->AO_Philo[4]
           Obj-Dict 0x20000F94->EvtPool1
           Obj-Dict 0x20000DDC->Philo_inst[0]
           Obj-Dict 0x20000E00->Philo_inst[0].timeEvt
           Obj-Dict 0x20000E10->Philo_inst[1]
           Obj-Dict 0x20000E34->Philo_inst[1].timeEvt
           Obj-Dict 0x20000E44->Philo_inst[2]
           Obj-Dict 0x20000E68->Philo_inst[2].timeEvt
           Obj-Dict 0x20000E78->Philo_inst[3]
           Obj-Dict 0x20000E9C->Philo_inst[3].timeEvt
           Obj-Dict 0x20000EAC->Philo_inst[4]
           Obj-Dict 0x20000ED0->Philo_inst[4].timeEvt
           Fun-Dict 0x080006A9->Philo_initial
           Fun-Dict 0x08000915->Philo_thinking
           Fun-Dict 0x08000871->Philo_hungry
           Fun-Dict 0x080007C5->Philo_eating
           Sig-Dict 00000010,Obj=0x20000DDC->HUNGRY_SIG
           Sig-Dict 00000011,Obj=0x20000DDC->TIMEOUT_SIG
0000000000 AO-Subsc Obj=Philo_inst[0],Sig=00000004,Obj=0x20000DDC
0000000000 AO-Subsc Obj=Philo_inst[0],Sig=00000008,Obj=0x20000DDC
===RTC===> St-Init  Obj=Philo_inst[0],State=0x08001099->Philo_thinking
0000000000 TE0-Arm  Obj=Philo_inst[0].timeEvt,AO=Philo_inst[0],Tim=84,Int=0
===RTC===> St-Entry Obj=Philo_inst[0],State=Philo_thinking
0000000000 Init===> Obj=Philo_inst[0],State=Philo_thinking
           Sig-Dict 00000010,Obj=0x20000E10->HUNGRY_SIG
           Sig-Dict 00000011,Obj=0x20000E10->TIMEOUT_SIG
0000000000 AO-Subsc Obj=Philo_inst[1],Sig=00000004,Obj=0x20000E10
0000000000 AO-Subsc Obj=Philo_inst[1],Sig=00000008,Obj=0x20000E10
===RTC===> St-Init  Obj=Philo_inst[1],State=0x08001099->Philo_thinking
0000000000 TE0-Arm  Obj=Philo_inst[1].timeEvt,AO=Philo_inst[1],Tim=107,Int=0
===RTC===> St-Entry Obj=Philo_inst[1],State=Philo_thinking
0000000000 Init===> Obj=Philo_inst[1],State=Philo_thinking
           Sig-Dict 00000010,Obj=0x20000E44->HUNGRY_SIG
           Sig-Dict 00000011,Obj=0x20000E44->TIMEOUT_SIG
0000000000 AO-Subsc Obj=Philo_inst[2],Sig=00000004,Obj=0x20000E44
0000000000 AO-Subsc Obj=Philo_inst[2],Sig=00000008,Obj=0x20000E44
===RTC===> St-Init  Obj=Philo_inst[2],State=0x08001099->Philo_thinking
0000000000 TE0-Arm  Obj=Philo_inst[2].timeEvt,AO=Philo_inst[2],Tim=102,Int=0
===RTC===> St-Entry Obj=Philo_inst[2],State=Philo_thinking
0000000000 Init===> Obj=Philo_inst[2],State=Philo_thinking
           Sig-Dict 00000010,Obj=0x20000E78->HUNGRY_SIG
           Sig-Dict 00000011,Obj=0x20000E78->TIMEOUT_SIG
0000000000 AO-Subsc Obj=Philo_inst[3],Sig=00000004,Obj=0x20000E78
0000000000 AO-Subsc Obj=Philo_inst[3],Sig=00000008,Obj=0x20000E78
===RTC===> St-Init  Obj=Philo_inst[3],State=0x08001099->Philo_thinking
0000000000 TE0-Arm  Obj=Philo_inst[3].timeEvt,AO=Philo_inst[3],Tim=148,Int=0
===RTC===> St-Entry Obj=Philo_inst[3],State=Philo_thinking
0000000000 Init===> Obj=Philo_inst[3],State=Philo_thinking
           Sig-Dict 00000010,Obj=0x20000EAC->HUNGRY_SIG
           Sig-Dict 00000011,Obj=0x20000EAC->TIMEOUT_SIG
0000000000 AO-Subsc Obj=Philo_inst[4],Sig=00000004,Obj=0x20000EAC
0000000000 AO-Subsc Obj=Philo_inst[4],Sig=00000008,Obj=0x20000EAC
===RTC===> St-Init  Obj=Philo_inst[4],State=0x08001099->Philo_thinking
0000000000 TE0-Arm  Obj=Philo_inst[4].timeEvt,AO=Philo_inst[4],Tim=51,Int=0
===RTC===> St-Entry Obj=Philo_inst[4],State=Philo_thinking
0000000000 Init===> Obj=Philo_inst[4],State=Philo_thinking
           Obj-Dict 0x20000EE0->Table_inst
           Sig-Dict 00000005,Obj=0x00000000->DONE_SIG
           Sig-Dict 00000004,Obj=0x00000000->EAT_SIG
           Sig-Dict 00000006,Obj=0x00000000->PAUSE_SIG
           Sig-Dict 00000007,Obj=0x00000000->SERVE_SIG
           Sig-Dict 00000008,Obj=0x00000000->TEST_SIG
           Sig-Dict 00000010,Obj=0x20000EE0->HUNGRY_SIG
0000000000 AO-Subsc Obj=Table_inst,Sig=DONE_SIG
0000000000 AO-Subsc Obj=Table_inst,Sig=PAUSE_SIG
0000000000 AO-Subsc Obj=Table_inst,Sig=SERVE_SIG
0000000000 AO-Subsc Obj=Table_inst,Sig=TEST_SIG
0000000000 PHILO_STAT 0 thinking
0000000000 PHILO_STAT 1 thinking
0000000000 PHILO_STAT 2 thinking
0000000000 PHILO_STAT 3 thinking
0000000000 PHILO_STAT 4 thinking
           Fun-Dict 0x08000BB5->Table_active
           Fun-Dict 0x08000BDD->Table_serving
           Fun-Dict 0x08000AD1->Table_paused
===RTC===> St-Init  Obj=Table_inst,State=0x08001099->Table_serving
===RTC===> St-Entry Obj=Table_inst,State=Table_serving
0000000000 Init===> Obj=Table_inst,State=Table_serving

Once QSPY acquires the dictionaries, it keeps them in memory and applies them to display the data in symbolic form rather than hex addresses.

The dictionaries do not need to be complete to be useful. QSPY simply applies the symbolic information whenever it can find a match in the dictionaries acquired so far. When a dictionary entry is not available, QSPY displays only hex addresses.

Saving Dictionaries to a File

QSPY can save the dictionaries acquired thus far into a file. This is triggered by the QS_QF_RUN trace record from the Target, but it can also be triggered by the user (by means of the d keyboard command or from QView menu File->Save Dictionaries), because QSPY does not "know" when the dictionaries are "complete", therefore it cannot know when to save them automatically.

In order for dictionaries to be saved to a file, the QSPY host application must be launched with the -d command-line option, with or without the optional [file] parameter.

On the other hand, QSPY automatically generates the file name for saving dictionaries. This file name always has the form qspy<target-time-stamp>.dic, where <target-time-stamp> unambiguously identifies the Target build date and time. For example, the Target code last built on August 31, 2015 at 14:42:29 will have the name qspy150831_144229.dic.

The internal addresses of objects can change with every code re-build, so dictionaries are applicable only to the specific Target build and must be freshly re-acquired after every new Target code build.

The dictionaries are saved to a file in ASCII format. The following listing shows the dictionaries from the DPP example application running on a STM32 NUCLEO board:


0x08004009 l_SysTick_Handler
0x20000DDC Philo_inst[0]
0x20000E00 Philo_inst[0].timeEvt
0x20000E10 Philo_inst[1]
0x20000E34 Philo_inst[1].timeEvt
0x20000E44 Philo_inst[2]
0x20000E68 Philo_inst[2].timeEvt
0x20000E78 Philo_inst[3]
0x20000E9C Philo_inst[3].timeEvt
0x20000EAC Philo_inst[4]
0x20000ED0 Philo_inst[4].timeEvt
0x20000EE0 Table_inst
0x20000F94 EvtPool1
0x20001048 QS_RX
0x080006A9 Philo_initial
0x080007C5 Philo_eating
0x08000871 Philo_hungry
0x08000915 Philo_thinking
0x08000AD1 Table_paused
0x08000BB5 Table_active
0x08000BDD Table_serving
0x00000064 PHILO_STAT
00000004 0x00000000 EAT_SIG
00000005 0x00000000 DONE_SIG
00000006 0x00000000 PAUSE_SIG
00000007 0x00000000 SERVE_SIG
00000008 0x00000000 TEST_SIG
00000010 0x20000E44 HUNGRY_SIG
00000010 0x20000EAC HUNGRY_SIG
00000010 0x20000E78 HUNGRY_SIG
00000010 0x20000DDC HUNGRY_SIG
00000010 0x20000E10 HUNGRY_SIG
00000010 0x20000EE0 HUNGRY_SIG
00000011 0x20000E78 TIMEOUT_SIG
00000011 0x20000EAC TIMEOUT_SIG
00000011 0x20000E44 TIMEOUT_SIG
00000011 0x20000DDC TIMEOUT_SIG
00000011 0x20000E10 TIMEOUT_SIG

Using the Dictionary File

The dictionary file saved in previous QSPY sessions can be used in two ways:

  • you can specify the dictionary file in the -d <dictionary_file> command-line option to QSPY. In this case QSPY reads the dictionaries from the provided <dictionary_file> before processing any trace records from the Target. (NOTE: in this case you don't need to provide any of the upper-case command-line options, because they are read from the dictionary file.) For example: the command line qspy -d qspy180117_155932.dic will attempt to read the dictionaries from the specified file.
  • you can specify the dictionary option without the dictionary file -d command-line option to QSPY. Subsequently, once you run QSPY, you can query the Target information (by means of the i or r keyboard command or from QView menu Commands->Query Target Info). When the Target replies and provides its build-time-stamp, QSPY looks for the corresponding dictionary file in the current directory, and if such a file is found, QSPY reads the dictionaries from it.
That last option requires that the Target implements the QS receive channel, QS-RX so that it can receive commands from QSPY.

QSPY Screen OutputQSPY UDP Interface