Understanding the ctags file format
Asked Answered
T

2

5

I used "Exhuberant ctags" to index all the tags from my c-project. The c-project is embedded software for a Cortex-M7 microcontroller. The result is a tags-file. I'm trying to read this file and understand what is written down.
Based on the documentation I find for ctags and Exhuberant ctags, I can grasp the meanings of most lines. For example:

ADC3    .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   1525;"  d

This line means:

  • A tag has been found with name ADC3.
  • The tag is found in file .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h.
  • The tag is at line 1525 in that file.
  • The tag is type d - which is a "macro definition".

So far, so good. But there are lots of lines in the tags-file that I cannot wrap my head around. For example:

A0  .\Drivers\CMSIS\Include\arm_math.h  /^    q15_t A0;           \/**< The derived gain, A0 = Kp + Ki + Kd . *\/$/;"   m   struct:__anon68

And this one:

ABFSR   .\Drivers\CMSIS\Include\core_cm7.h  /^  __IOM uint32_t ABFSR;                  \/*!< Offset: 0x2A8 (R\/W)  Auxiliary Bus Fault Status Register *\/$/;"  m   struct:__anon187

And this one:

ABR .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^  __IO uint32_t ABR;      \/*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C *\/$/;"  m   struct:__anon39

And this one:

ADC_Common_TypeDef  .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^} ADC_Common_TypeDef;$/;" t   typeref:struct:__anon3

And this one:

ADC_IRQn    .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^  ADC_IRQn                    = 18,     \/*!< ADC1, ADC2 and ADC3 global Interrupts                             *\/$/;"   e   enum:__anon1

And this one:

C   .\Drivers\CMSIS\Include\core_cm7.h  /^    uint32_t C:1;                        \/*!< bit:     29  Carry condition code flag *\/$/;" m   struct:__anon182::__anon183

And I can geep going...

Can you help me to understand them? Perhaps working out one or two examples, while giving some general rules on how to interpret these lines? That would be really helpful.

EDIT: For the newest .exe file of "universal ctags", refer to this question: Universal ctags on Windows

Taliesin answered 30/1, 2017 at 10:39 Comment(1)
I would try asking directly to the developers of the program which generated those tags, and/or the developers of the programs which consume those tags.Trinitrobenzene
B
2

In general, looking at CTags files manually isn't going to be very productive (though I understand you probably just want to understand what's going on). With that said, here's my explanation of what the various entries you've posted are.

I suspect most of what you'll see will fall into one of these broad categories, but when in doubt looking directly in the code will really help you figure out what's going on.

Struct Members

Data structs

A0  .\Drivers\CMSIS\Include\arm_math.h  /^    q15_t A0;           \/**< The derived gain, A0 = Kp + Ki + Kd . *\/$/;"   m   struct:__anon68

A0 is a member of a struct (m struct:__anon68) which is used to pass data to/from mathematics acceleration functions.

Hardware Registers

ST declares their hardware registers in a particular way. I'll use an example here from core_m7.h, which declares register blocks common to all Cortex-M7 CPUs irrespective of vendor:

typedef struct
{
  __IO uint32_t ISER[8];                 /*!< Offset: 0x000 (R/W)  Interrupt Set Enable Register           */
       uint32_t RESERVED0[24];
  __IO uint32_t ICER[8];                 /*!< Offset: 0x080 (R/W)  Interrupt Clear Enable Register         */
       uint32_t RSERVED1[24];
  __IO uint32_t ISPR[8];                 /*!< Offset: 0x100 (R/W)  Interrupt Set Pending Register          */
       uint32_t RESERVED2[24];
  __IO uint32_t ICPR[8];                 /*!< Offset: 0x180 (R/W)  Interrupt Clear Pending Register        */
       uint32_t RESERVED3[24];
  __IO uint32_t IABR[8];                 /*!< Offset: 0x200 (R/W)  Interrupt Active bit Register           */
       uint32_t RESERVED4[56];
  __IO uint8_t  IP[240];                 /*!< Offset: 0x300 (R/W)  Interrupt Priority Register (8Bit wide) */
       uint32_t RESERVED5[644];
  __O  uint32_t STIR;                    /*!< Offset: 0xE00 ( /W)  Software Trigger Interrupt Register     */
}  NVIC_Type;

/* ... */

#define SCS_BASE            (0xE000E000UL)                            /*!< System Control Space Base Address  */
#define NVIC_BASE           (SCS_BASE +  0x0100UL)                    /*!< NVIC Base Address                  */

/* ... */

#define NVIC                ((NVIC_Type      *)     NVIC_BASE     )   /*!< NVIC configuration struct          */

The struct determines the location in memory of various configuration and control registers, in this case for the NVIC (Nested Vectored Interrupt Controller) block, which manages the system's exception handling.

As far as CTags is concerned, this is identical to A0 above. The (very significant) difference lies in how the structs are instantiated -- for hardware blocks, the struct declarations mapped to specific memory addresses that have to be treated specially.

Many of your ctags lines will refer to these kinds of declaration, including:

ABFSR   .\Drivers\CMSIS\Include\core_cm7.h  /^  __IOM uint32_t ABFSR;                  \/*!< Offset: 0x2A8 (R\/W)  Auxiliary Bus Fault Status Register *\/$/;"  m   struct:__anon187

ABR .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^  __IO uint32_t ABR;      \/*!< QUADSPI Alternate Bytes register,                   Address offset: 0x1C *\/$/;"  m   struct:__anon39

Both of these are struct members. In your code, you'll likely see something like SCB->ABFSR = ....

C   .\Drivers\CMSIS\Include\core_cm7.h  /^    uint32_t C:1;                        \/*!< bit:     29  Carry condition code flag *\/$/;" m   struct:__anon182::__anon183

Deserves special treatment, since it's a bitfield declaration. It's more complicated since it's a struct member inside a union (m struct:__anon182::__anon183), but effectively it's the same sort of thing. Depending on what you're looking, these anonymous nestings can get pretty deep -- keeping track of this stuff is where CTags and similar tools really start to prove their worth.

Type definitions

ADC_Common_TypeDef  .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^} ADC_Common_TypeDef;$/;" t   typeref:struct:__anon3

This is how CTags keeps track of all those anonymous structs. It says "ADC_Common_TypeDef is the same thing as struct:__anon3"

Constants (enums)

ADC_IRQn    .\Drivers\CMSIS\Device\ST\STM32F7xx\Include\stm32f767xx.h   /^  ADC_IRQn                    = 18,     \/*!< ADC1, ADC2 and ADC3 global Interrupts                             *\/$/;"   e   enum:__anon1

This is a constant (the interrupt vector number for the ADC interrupt). It's declared as part of an anonymous enum (e enum:__anon1).

Braxton answered 6/2, 2017 at 17:54 Comment(0)
S
2

The tags file format is described in a fair amount of detail in the tags(5) manual page.

The most important thing to understand about the format is that it consists of tab-separated fields, which means you need to distinguish between tabs and other whitespace when reading it. (One easy way to do this in most editors that have search highlighting, such as with :set hlsearch in Vim, is simply to search for a tab character.)

Here is first example you give of a line you don't understand (I've removed the four leading space characters you added):

A0  .\Drivers\CMSIS\Include\arm_math.h  /^    q15_t A0;           \/**< The derived gain, A0 = Kp + Ki + Kd . *\/$/;"   m   struct:__anon68

When we split this on the tab characters, we get five fields as follows:

  1. A0
  2. .\Drivers\CMSIS\Include\arm_math.h
  3. /^ q15_t A0; \/**< The derived gain, A0 = Kp + Ki + Kd . *\/$/;"
  4. m
  5. struct:__anon68

Field 1 is the tag name and field 2 is the file containing the tag, as you've already determined.

Field 3 is the address, which is a command to find the tag location in the target file. This can be just a line number, but in this case, since it starts with /, it's a search pattern, but you'll note that this particular one contains lots of whitespace, which is probably what was confusing you. (It's worth nothing that the only special characters in search patterns in tag files are ^ and $; characters such as * are treated literally, not as regular expression special characters.)

All fields following the third one are tagfields which are an extension supported by Vim, Exuberant Ctags and various other programs. These are in name:value format where name consists of letters only (case sensitive) and value can be any string that does not contain tabs. (\t, \r, \n, and \\ escapes are understood.)

The tagfield names depend on the particular programs reading and writing, but the suggestions in the tags(5) manpage include arity, class, enum, file, function, kind, struct, and union. See the manual page for details on these, but the kind tagfield values are probably worth reproducing here:

c  class name
d  define (from #define XXX)
e  enumerator
f  function or method name
F  file name
g  enumeration name
m  member (of structure or class data)
p  function prototype
s  structure name
t  typedef
u  union name
v  variable

There's one special case for tagfield names, which is that the kind: need not be present for "kind" tagfields (i.e., just m will be interpreted as kind:m); this works because the tagfield value for kind never has a colon in it. This can save considerable space in a large tagfile.

Savadove answered 7/5, 2023 at 5:25 Comment(1)
I assumed you use Universal Ctags. You can list kinds supported in its C parser with ctags --list-kinds-full=C. You can list supported fields with ctags --list-fields.Jotting

© 2022 - 2024 — McMap. All rights reserved.