Pretty-printing C structures - Page 1
Forum section: electronics / general

author: westfw
author_rank: Super Contributor
timestamp: August 20, 2023, 11:31:09 pm
content: In the vein of "Surely this has been done before, probably many times!"Does anyone happen to have a utility that will generate the printf()s needed to pretty-print a C structure, given the definitions from the .h file?In other words, given:Code:typedef struct{__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */} SysTick_Type;I would like to get something like:Code:#define uint32_t_format "0x%08x"printf("SysTick\n");printf(" CTRL = " uint32_t_format "!< Offset: 0x000 (R/W) SysTick Control and Status Register\n", p->CTRL);printf(" LOAD = " uint32_t_format "!< Offset: 0x004 (R/W) SysTick Reload Value Register\n", p->LOAD);printf(" VAL = " uint32_t_format "!< Offset: 0x008 (R/W) SysTick Current Value Register\n", p->VAL);printf(" CALIB = " uint32_t_format "!< Offset: 0x00C (R/ ) SysTick Calibration Register \n", p->CALIB);I'm don't much care about the language the tool is written in, and it need not be all-powerful and inclusive.(Yeah, it should work from .h files rather than from .svd or similar, since the latter can be hard to find.)

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 20, 2023, 11:34:07 pm
content: (For a nice collection of SVDs:https://github.com/posborne/cmsis-svd/tree/master/data)

author: westfw
author_rank: Super Contributor
timestamp: August 21, 2023, 02:12:28 am
content: QuoteI was aware of that.I cannot find an SVD for the Renesas ra4m1 used on the new Arduino, though. (Part of the whole "Renesas docs for this chip really suck" status.)(Web search shows some complaints about the SVD for RA chips failing verification, but apparently the "solution" to this was to remove the files entirely. :-( )

author: djacobow
author_rank: Super Contributor
timestamp: August 21, 2023, 02:27:39 am
content: Parsing C header files can be hairier than it seems. To do it right without compromises really means implementing most of the front end of a compiler, including the preprocessor.As a result, you're going to find mostly janky homemade tools that work correctly only if the header you want parsed is written a certain way, and doesn't use certain c features (bit fields, anyone?)This is what I do instead: I write python that defines the structs I want and the same code emits the c header with the struct definitions, routines for pretty printing, and something I want but which you don't mention: routines for accessing the same structures through Python. I use the latter to make it much easier to implement tests that access binary data from my code under test.This is actually not all that difficult to write yourself, especially if all you want is a stringifier.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: August 21, 2023, 02:58:53 am
content: To the extent GDB and friends are able to interpret data structures -- would it be possible/feasible to use debug info to create this?Would be a two-pass process of course, either running code generation after compiling the project and just compiling twice when changes occur, or, as a pre-build step, building a toy module that uses the headers of interest, and obtaining debug info from that.(I know nothing about the structure / ease of use of the data so encoded, I'm no help implementing this; just putting the thought out there.)Tm

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2023, 03:23:54 am
content: Quote from: westfw on August 21, 2023, 02:12:28 amAll their devices are grouped into a single pack -https://www.keil.arm.com/vendors/renesas/packs/It is stupid, just like literally everything about those devices.Quote from: westfw on August 21, 2023, 02:12:28 amAlmost all SVD files out there are failing verification. I doubt vendors even verify them at all, and there is no real spec for SVD files. You kind of just have to do your best guess based on the schema file.Parsers in the tools have to be very accepting of random stuff and gracefully ignore stuff they don't understand. Most of them are fine with practical files..

author: djacobow
author_rank: Super Contributor
timestamp: August 21, 2023, 04:06:45 am
content: Quote from: T3sl4co1l on August 21, 2023, 02:58:53 amIt is indeed possible. All the info you need is in the debug info that the compiler generates. It's not easy to learn how that all works, but at least if you're using GCC, it's open source.Another option is that compilers like clang / LLVM make some of the intermediate format steps available to other tools during compilation, and I bet that could be used to make pretty-printers. You just need to learn how that all works. :-)

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2023, 04:11:05 am
content: The debug info stored in the DWARF format, but it is not trivial by any means. There are libraries for parsing it too, but it is more trouble than it is worth for this use, IMO. You also won't get the comments.For somewhat robust generic version, parsing SVD is the easiest.For a quick hack for well-formatted header files (as headers often are), a simple Python script would work too.A bigger issue would be what to do with non-trivial types. What if that struct includes another struct? Print it recursively? Ignore it?

author: westfw
author_rank: Super Contributor
timestamp: August 21, 2023, 04:52:24 am
content: Quote from: djacobow onTodayat 07:27:39 pmQuoteI'm fine with something that does 85% of the work for "written in a certain way" files. I'll get rid of bitfields manually, unless I think they're really important. And I care most about the more-or-less CMSIS-compliant header files, so that simplifies things.It would be great if someone already had a hack that used DWARF info and spit out code that would print every structure referenced in a .elf file, but a lot less would still be useful. My normal strategy would be to create a save some EMACS keyboard macros.QuoteNot applicable, since what I want is to print out contents of structs that someone else has defined.Are there SVDs for the ARM cores themselves? (ie covering my sysTick example; usually not in a vendor SVD file.)

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2023, 04:59:58 am
content: Quote from: westfw on August 21, 2023, 04:52:24 amYes, they are a part of the ARM CMSIS SVD pack. Or just get them from the source -https://github.com/ARM-software/CMSIS_5/tree/develop/Device/ARM/SVDWait, those files don't seem to contain anything useful. Yes, I remember now running into that some time ago. And I don't think I could find real SVD files for that, which was puzzling.Many vendor files contain those peripherals, probably for that reason. I had to specifically filter them out in my SVD to H converter because they conflicted with the ARM header files.

author: 5U4GB
author_rank: Super Contributor
timestamp: August 21, 2023, 10:47:40 am
content: Quote from: westfw on August 20, 2023, 11:31:09 pmYup, google clang's "__builtin_dump_struct", it's done by the compiler so it sorts out any parsing issues for you. From themanpage:Code:Examples:struct S {int x, y;float f;struct T {int i;} t;};void func(struct S *s) {__builtin_dump_struct(s, printf);}Example output:struct S {int x = 100int y = 42float f = 3.141593struct T t = {int i = 1997}}

author: djacobow
author_rank: Super Contributor
timestamp: August 21, 2023, 03:57:56 pm
content: Oh, that's great about the clang builtin!

author: SiliconWizard
author_rank: Super Contributor
timestamp: August 21, 2023, 08:03:31 pm
content: Have you looked at doxygen?

author: westfw
author_rank: Super Contributor
timestamp: August 26, 2023, 07:14:40 am
content: So I ended up using this EMACS keyboard macro, which helps a lot...It's not fully optimized; I don't think I fully understand the ways that keyboard macros can be edited...Code:;; Keyboard Macro Editor. Press C-c C-c to finish; press C-x k RET to cancel.;; Original keys: ESC d ESC d ESC d sprintf ( spbuffer , "%6s=%0x08lx SPC ( %s ) " , " SPC C-f ESC \ ESC C-s ; C-b C-w C-d C-y " , SPC p-> C-y , SPC " M-\ C-e " ) ; C-n C-a mySerial.print ( spbuffer ) ; RETCommand: last-kbd-macroKey: noneMacro:ESC d ;; kill-word -get rid of "__IOM uint32_t"ESC d ;; kill-wordESC d ;; kill-wordsprintf ;; self-insert-command * 7( ;; c-electric-parenspbuffer ;; self-insert-command * 8, ;; c-electric-semi&comma"%6s=%0x08lx ;; self-insert-command "sprintf(spbuf, "%6s=0x%08lx%s","SPC ;; self-insert-command( ;; c-electric-paren%s ;; self-insert-command * 2) ;; c-electric-paren" ;; self-insert-command, ;; c-electric-semi&comma" ;; self-insert-commandSPC ;; self-insert-commandC-f ;; forward-char skip the spacesESC \ ;; delete-horizontal-spaceESC C-s ;; isearch-forward-regexp copy structure member name; ;; c-electric-semi&comma into the kill bufferC-b ;; backward-char ...C-w ;; kill-regionC-d ;; c-electric-delete-forwardC-y ;; yank into the quoted string" ;; self-insert-command, ;; c-electric-semi&commaSPC ;; self-insert-commandp-> ;; self-insert-command * 3C-y ;; yank and again as a variable p->member, ;; c-electric-semi&commaSPC ;; self-insert-command" ;; self-insert-commandM-\ ;; delete-horizontal-space and clean up the description from the commentC-e ;; move-end-of-line" ;; self-insert-command) ;; c-electric-paren; ;; c-electric-semi&commaC-n ;; next-lineC-a ;; move-beginning-of-linemySerial.print ;; self-insert-command * 14 and print the constructed string( ;; c-electric-parenspbuffer ;; self-insert-command * 8) ;; c-electric-paren; ;; c-electric-semi&commaRET ;; newline

author: Alti
author_rank: Frequent Contributor
timestamp: August 26, 2023, 10:13:46 am
content: Quote from: westfw on August 26, 2023, 07:14:40 amYou do not print structs but volatile structs.Those structs might be write only and/or undefined behavior on read. Some values might change content or status of some fifo on read, also some are integers but some are bitfields so interpretation is the key to prettyfying it.I would go svd way. It contains more data.