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:
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.
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:
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 QF_RUN
Once QSPY acquires the dictionaries, it keeps them in memory and applies them to display the data in symbolic form rather than hex addresses.
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.
-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 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:
-v690 -T4 -O4 -F4 -S2 -E2 -Q1 -P2 -B2 -C2 -t200824_123230 Obj-Dic: 4 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 *** Fun-Dic: 4 0x080006A9 Philo_initial 0x080007C5 Philo_eating 0x08000871 Philo_hungry 0x08000915 Philo_thinking 0x08000AD1 Table_paused 0x08000BB5 Table_active 0x08000BDD Table_serving *** Usr-Dic: 1 0x00000064 PHILO_STAT 0x0000007C QUTEST_ON_POST *** Sig-Dic: 4 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 ***
The dictionary file saved in previous QSPY sessions can be used in two ways:
-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.-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.