Search code examples
armctagscortex-mexuberant-ctags

Understanding the ctags file format


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


Solution

  • 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).