QSPY  5.8.0
QSPY Dictionaries

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, function dictionary, signal dictionary, and user dictionary.

The dictionary trace records are not absolutely required to generate the human-readable output, in the same way as the symbolic information in the object files is not absolutely required to debug code. However, in both cases, the availability of the symbolic information greatly improves the productivity in working with the software trace or the debugger. For example, the following listing shows an example of the QSPY text output when the "dictionaries" are not available:

********** Data discontinuity: seq=1 -> seq=73
0148066147 Disp==>: Obj=20000E14 Sig=0000000B,Obj=20000E14 Active=00000D01
           ENTRY: Obj=20000E14 State=00000C99
0148067681 ==>Tran: Obj=20000E14 Sig=0000000B,Obj=20000E14 Source=00000D01 New=00000C99
0148068651 Disp==>: Obj=20000E90 Sig=0000000A,Obj=20000E90 Active=00001145
0148069357 User70: 3 hungry
0148069955 Intern : Obj=20000E90 Sig=0000000A,Obj=20000E90 Source=00001145
0181066185 Disp==>: Obj=20000D60 Sig=0000000B,Obj=20000D60 Active=00000D01
           ENTRY: Obj=20000D60 State=00000C99
0181067719 ==>Tran: Obj=20000D60 Sig=0000000B,Obj=20000D60 Source=00000D01 New=00000C99
0181068689 Disp==>: Obj=20000E90 Sig=0000000A,Obj=20000E90 Active=00001145
0181069395 User70: 0 hungry
0181069999 Intern : Obj=20000E90 Sig=0000000A,Obj=20000E90 Source=00001145
0185066099 Disp==>: Obj=20000E50 Sig=0000000B,Obj=20000E50 Active=00000C45
           EXIT : Obj=20000E50 State=00000C45
           ENTRY: Obj=20000E50 State=00000D01
0185068413 ==>Tran: Obj=20000E50 Sig=0000000B,Obj=20000E50 Source=00000C45 New=00000D01
. . . . . .

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

********** Data discontinuity: seq=1 -> seq=73
0148066147 Disp==>: Obj=l_philo[3] Sig=TIMEOUT_SIG Active=Philo_thinking
           ENTRY: Obj=l_philo[3] State=Philo_hungry
0148067681 ==>Tran: Obj=l_philo[3] Sig=TIMEOUT_SIG Source=Philo_thinking New=Philo_hungry
0148068651 Disp==>: Obj=l_table Sig=HUNGRY_SIG Active=Table_serving
0148069357 PHILO_STAT: 3 hungry
0148069955 Intern : Obj=l_table Sig=HUNGRY_SIG Source=Table_serving
0181066185 Disp==>: Obj=l_philo[0] Sig=TIMEOUT_SIG Active=Philo_thinking
           ENTRY: Obj=l_philo[0] State=Philo_hungry
0181067719 ==>Tran: Obj=l_philo[0] Sig=TIMEOUT_SIG Source=Philo_thinking New=Philo_hungry
0181068689 Disp==>: Obj=l_table Sig=HUNGRY_SIG Active=Table_serving
0181069395 PHILO_STAT: 0 hungry
0181069999 Intern : Obj=l_table Sig=HUNGRY_SIG Source=Table_serving
0185066099 Disp==>: Obj=l_philo[4] Sig=TIMEOUT_SIG Active=Philo_eating
           EXIT : Obj=l_philo[4] State=Philo_eating
           ENTRY: Obj=l_philo[4] State=Philo_thinking
0185068413 ==>Tran: Obj=l_philo[4] Sig=TIMEOUT_SIG Source=Philo_eating New=Philo_thinking
. . . . . .

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 objects 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 the EK-TM4C123GXL board:

C:\qp\qtools\qspy\doxygen>qspy -u -cCOM4
QSPY host application 5.5.0
Copyright (c) Quantum Leaps, state-machine.com
Time Stamp: 150918_113919

********** TARGET: QP-Ver: 550, build tstamp:150831_144229
           Obj-Dic: 0000000000004018->QS_RX
           Obj-Dic: 0000000000003B18->l_SysTick_Handler
           Obj-Dic: 0000000000003B19->l_GPIOPortA_IRQHandler
           Usr-Dic: 00000046        ->PHILO_STAT
           Usr-Dic: 00000047        ->COMMAND_STAT
           Obj-Dic: 0000000020000D10->smlPoolSto
           Obj-Dic: 0000000020000CFC->tableQueueSto
           Obj-Dic: 0000000020000C74->philoQueueSto[0]
           Obj-Dic: 0000000020000C88->philoQueueSto[1]
           Obj-Dic: 0000000020000C9C->philoQueueSto[2]
           Obj-Dic: 0000000020000CB0->philoQueueSto[3]
           Obj-Dic: 0000000020000CC4->philoQueueSto[4]
           Obj-Dic: 0000000020000D60->l_philo[0]
           Obj-Dic: 0000000020000D8C->l_philo[0].timeEvt
           Obj-Dic: 0000000020000D9C->l_philo[1]
           Obj-Dic: 0000000020000DC8->l_philo[1].timeEvt
           Obj-Dic: 0000000020000DD8->l_philo[2]
           Obj-Dic: 0000000020000E04->l_philo[2].timeEvt
           Obj-Dic: 0000000020000E14->l_philo[3]
           Obj-Dic: 0000000020000E40->l_philo[3].timeEvt
           Obj-Dic: 0000000020000E50->l_philo[4]
           Obj-Dic: 0000000020000E7C->l_philo[4].timeEvt
           Fun-Dic: 0000000000000A79->Philo_initial
           Fun-Dic: 0000000000000D01->Philo_thinking
           Fun-Dic: 0000000000000C99->Philo_hungry
           Fun-Dic: 0000000000000C45->Philo_eating
           Sig-Dic: 0000000A,Obj=0000000020000D60->HUNGRY_SIG
           Sig-Dic: 0000000B,Obj=0000000020000D60->TIMEOUT_SIG
           INIT : Obj=l_philo[0] Source=NULL Target=Philo_thinking
           ENTRY: Obj=l_philo[0] State=Philo_thinking
0000500000 ==>Init: Obj=l_philo[0] New=Philo_thinking
           Sig-Dic: 0000000A,Obj=0000000020000D9C->HUNGRY_SIG
           Sig-Dic: 0000000B,Obj=0000000020000D9C->TIMEOUT_SIG
           INIT : Obj=l_philo[1] Source=NULL Target=Philo_thinking
           ENTRY: Obj=l_philo[1] State=Philo_thinking
0000500000 ==>Init: Obj=l_philo[1] New=Philo_thinking
           Sig-Dic: 0000000A,Obj=0000000020000DD8->HUNGRY_SIG
           Sig-Dic: 0000000B,Obj=0000000020000DD8->TIMEOUT_SIG
           INIT : Obj=l_philo[2] Source=NULL Target=Philo_thinking
           ENTRY: Obj=l_philo[2] State=Philo_thinking
0000500000 ==>Init: Obj=l_philo[2] New=Philo_thinking
           Sig-Dic: 0000000A,Obj=0000000020000E14->HUNGRY_SIG
           Sig-Dic: 0000000B,Obj=0000000020000E14->TIMEOUT_SIG
           INIT : Obj=l_philo[3] Source=NULL Target=Philo_thinking
           ENTRY: Obj=l_philo[3] State=Philo_thinking
0000500000 ==>Init: Obj=l_philo[3] New=Philo_thinking
           Sig-Dic: 0000000A,Obj=0000000020000E50->HUNGRY_SIG
           Sig-Dic: 0000000B,Obj=0000000020000E50->TIMEOUT_SIG
           INIT : Obj=l_philo[4] Source=NULL Target=Philo_thinking
           ENTRY: Obj=l_philo[4] State=Philo_thinking
0000500000 ==>Init: Obj=l_philo[4] New=Philo_thinking
           Obj-Dic: 0000000020000E90->l_table
           Fun-Dic: 00000000000017A5->QHsm_top
           Fun-Dic: 0000000000000E6D->Table_initial
           Fun-Dic: 0000000000001355->Table_active
           Fun-Dic: 0000000000001145->Table_serving
           Fun-Dic: 0000000000000FFD->Table_paused
           Sig-Dic: 00000005,Obj=0000000000000000->DONE_SIG
           Sig-Dic: 00000004,Obj=0000000000000000->EAT_SIG
           Sig-Dic: 00000006,Obj=0000000000000000->PAUSE_SIG
           Sig-Dic: 00000007,Obj=0000000000000000->SERVE_SIG
           Sig-Dic: 00000008,Obj=0000000000000000->TERMINATE_SIG
           Sig-Dic: 0000000A,Obj=0000000020000E90->HUNGRY_SIG

Once QSPY acquires the dictionaries, it keeps them in the 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 must be triggered by the user (by means of the d keyboard command or from QSpyView menu "File->Save Dictionaries"), because QSPY does not "know" when the dictionaries are "complete", therefore it cannot know when to save them automatically.

On the other hand, QSPY generates automatically the file name for saving dictionaries. This file name has always 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 by 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 the EK-TM4C123GXL board:

21 4
0000000000003B18 l_SysTick_Handler
0000000000003B19 l_GPIOPortA_IRQHandler
0000000000004018 QS_RX
0000000020000C74 philoQueueSto[0]
0000000020000C88 philoQueueSto[1]
0000000020000C9C philoQueueSto[2]
0000000020000CB0 philoQueueSto[3]
0000000020000CC4 philoQueueSto[4]
0000000020000CFC tableQueueSto
0000000020000D10 smlPoolSto
0000000020000D60 l_philo[0]
0000000020000D8C l_philo[0].timeEvt
0000000020000D9C l_philo[1]
0000000020000DC8 l_philo[1].timeEvt
0000000020000DD8 l_philo[2]
0000000020000E04 l_philo[2].timeEvt
0000000020000E14 l_philo[3]
0000000020000E40 l_philo[3].timeEvt
0000000020000E50 l_philo[4]
0000000020000E7C l_philo[4].timeEvt
0000000020000E90 l_table
9 4
0000000000000A79 Philo_initial
0000000000000C45 Philo_eating
0000000000000C99 Philo_hungry
0000000000000D01 Philo_thinking
0000000000000E6D Table_initial
0000000000000FFD Table_paused
0000000000001145 Table_serving
0000000000001355 Table_active
00000000000017A5 QHsm_top
2 1
0000000000000046 PHILO_STAT
0000000000000047 COMMAND_STAT
16 4
00000004 0000000000000000 EAT_SIG
00000005 0000000000000000 DONE_SIG
00000006 0000000000000000 PAUSE_SIG
00000007 0000000000000000 SERVE_SIG
00000008 0000000000000000 TERMINATE_SIG
0000000A 0000000020000DD8 HUNGRY_SIG
0000000A 0000000020000E50 HUNGRY_SIG
0000000A 0000000020000E14 HUNGRY_SIG
0000000A 0000000020000D60 HUNGRY_SIG
0000000A 0000000020000D9C HUNGRY_SIG
0000000A 0000000020000E90 HUNGRY_SIG
0000000B 0000000020000E14 TIMEOUT_SIG
0000000B 0000000020000E50 TIMEOUT_SIG
0000000B 0000000020000DD8 TIMEOUT_SIG
0000000B 0000000020000D60 TIMEOUT_SIG
0000000B 0000000020000D9C TIMEOUT_SIG
0 4

Using 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 command-line option to QSPY. In this case QSPY reads the dictionaries 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: command line: qspy -dqspy150831_144229.dic will attempt to read the dictionaries from the specified file.
  • you can query the Target information (by means of the i keyboard command or from QSpyView 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. (NOTE: this option requires that the Target implements the QS receive channel, QS-RX, so that it can receive commands from QSPY).

Next: QSPY MATLAB Support