spevnev / uprintf

Single-header library for printing anything in C (on Linux)
MIT License
31 stars 2 forks source link
c debug debugging dwarf library single-header-lib single-header-library

Universal printf

uprintf is a single-header library that allows to print anything in C, intended for debugging and prototyping.

What is a single header library?

The idea behind single-header libraries is that they're easy to distribute since it's trivial to add them to any project.

By default the header file acts as any header would, i.e. contains declarations (without definitions). \ However, by defining a macro the header start to act as a .c file, i.e. contains definitions.

Examples

Source files as well as their outputs can be found in examples. \ You can also build them yourself using make examples, but note that sqlite takes long to build.

In addition, there are also tests with their outputs in the baselines.

Example outputs

avl ```c AVL tree: { avl_tree_node_t *root = 0x50400003ffd0 ({ avl_tree_node_t *left = 0x50400001ffd0 ({ avl_tree_node_t *left = 0x50400000ffd0 ({ avl_tree_node_t *left = 0x504000007fd0 ({ avl_tree_node_t *left = 0x504000003fd0 ({...}) avl_tree_node_t *right = 0x50400000bfd0 ({...}) int depth = 10 void *key = 0x1ff void *data = 0x1ff }) avl_tree_node_t *right = 0x504000017fd0 ({ avl_tree_node_t *left = 0x504000013fd0 ({...}) avl_tree_node_t *right = 0x50400001bfd0 ({...}) int depth = 10 void *key = 0x5ff void *data = 0x5ff }) int depth = 11 void *key = 0x3ff void *data = 0x3ff }) avl_tree_node_t *right = 0x50400002ffd0 ({ avl_tree_node_t *left = 0x504000027fd0 ({ avl_tree_node_t *left = 0x504000023fd0 ({...}) avl_tree_node_t *right = 0x50400002bfd0 ({...}) int depth = 10 void *key = 0x9ff void *data = 0x9ff }) avl_tree_node_t *right = 0x504000037fd0 ({ avl_tree_node_t *left = 0x504000033fd0 ({...}) avl_tree_node_t *right = 0x50400003bfd0 ({...}) int depth = 10 void *key = 0xdff void *data = 0xdff }) int depth = 11 void *key = 0xbff void *data = 0xbff }) int depth = 12 void *key = 0x7ff void *data = 0x7ff }) avl_tree_node_t *right = 0x50400005ffd0 ({ avl_tree_node_t *left = 0x50400004ffd0 ({ avl_tree_node_t *left = 0x504000047fd0 ({ avl_tree_node_t *left = 0x504000043fd0 ({...}) avl_tree_node_t *right = 0x50400004bfd0 ({...}) int depth = 10 void *key = 0x11ff void *data = 0x11ff }) avl_tree_node_t *right = 0x504000057fd0 ({ avl_tree_node_t *left = 0x504000053fd0 ({...}) avl_tree_node_t *right = 0x50400005bfd0 ({...}) int depth = 10 void *key = 0x15ff void *data = 0x15ff }) int depth = 11 void *key = 0x13ff void *data = 0x13ff }) avl_tree_node_t *right = 0x50400007ffd0 ({ avl_tree_node_t *left = 0x50400006ffd0 ({ avl_tree_node_t *left = 0x504000067fd0 ({...}) avl_tree_node_t *right = 0x504000077fd0 ({...}) int depth = 11 void *key = 0x1bff void *data = 0x1bff }) avl_tree_node_t *right = 0x50400008ffd0 ({ avl_tree_node_t *left = 0x504000087fd0 ({...}) avl_tree_node_t *right = 0x504000097fd0 ({...}) int depth = 11 void *key = 0x23ff void *data = 0x23ff }) int depth = 12 void *key = 0x1fff void *data = 0x1fff }) int depth = 13 void *key = 0x17ff void *data = 0x17ff }) int depth = 14 void *key = 0xfff void *data = 0xfff }) int(void *, void *) comparator = 0x5f69682a31c0 void(void *) destructor = NULL } ```
sqlite ```c Sqlite's database: <#0> { sqlite3_vfs *pVfs = 0x5c9eb29172a0 (<#1> { int iVersion = 3 int szOsFile = 120 int mxPathname = 512 sqlite3_vfs *pNext = 0x5c9eb29195a0 ({ int iVersion = 2 int szOsFile = 120 int mxPathname = 1024 sqlite3_vfs *pNext = 0x5c9eb2917498 ({ int iVersion = 3 int szOsFile = 120 int mxPathname = 512 sqlite3_vfs *pNext = 0x5c9eb29173f0 ({ int iVersion = 3 int szOsFile = 120 int mxPathname = 512 sqlite3_vfs *pNext = 0x5c9eb2917348 ({ int iVersion = 3 int szOsFile = 120 int mxPathname = 512 sqlite3_vfs *pNext = NULL const char *zName = 0x5c9eb2553ea0 ("unix-none") void *pAppData = 0x5c9eb258ba40 int(sqlite3_vfs *, const char *, sqlite3_file *, int, int *) xOpen = 0x5c9eb222bbe0 int(sqlite3_vfs *, const char *, int) xDelete = 0x5c9eb20f2720 int(sqlite3_vfs *, const char *, int, int *) xAccess = 0x5c9eb1fc98a0 int(sqlite3_vfs *, const char *, int, char *) xFullPathname = 0x5c9eb20f45a0 void *(sqlite3_vfs *, const char *) xDlOpen = 0x5c9eb1f61ff0 void(sqlite3_vfs *, int, char *) xDlError = 0x5c9eb20ce410 void()(sqlite3_vfs *, void *, const char *) xDlSym = 0x5c9eb1f61fe0 void(sqlite3_vfs *, void *) xDlClose = 0x5c9eb1fb4dc0 int(sqlite3_vfs *, int, char *) xRandomness = 0x5c9eb20f0bc0 int(sqlite3_vfs *, int) xSleep = 0x5c9eb1f61e90 int(sqlite3_vfs *, double *) xCurrentTime = 0x5c9eb1fe83b0 int(sqlite3_vfs *, int, char *) xGetLastError = 0x5c9eb1f9b230 int(sqlite3_vfs *, sqlite3_int64 *) xCurrentTimeInt64 = 0x5c9eb1fab1d0 int(sqlite3_vfs *, const char *, void()) xSetSystemCall = 0x5c9eb1fb0a50 void()(sqlite3_vfs *, const char *) xGetSystemCall = 0x5c9eb1fb0890 const char *(sqlite3_vfs *, const char *) xNextSystemCall = 0x5c9eb1fb05f0 }) const char *zName = 0x5c9eb2553ee0 ("unix-dotfile") void *pAppData = 0x5c9eb258b940 int(sqlite3_vfs *, const char *, sqlite3_file *, int, int *) xOpen = 0x5c9eb222bbe0 int(sqlite3_vfs *, const char *, int) xDelete = 0x5c9eb20f2720 int(sqlite3_vfs *, const char *, int, int *) xAccess = 0x5c9eb1fc98a0 int(sqlite3_vfs *, const char *, int, char *) xFullPathname = 0x5c9eb20f45a0 void *(sqlite3_vfs *, const char *) xDlOpen = 0x5c9eb1f61ff0 void(sqlite3_vfs *, int, char *) xDlError = 0x5c9eb20ce410 void()(sqlite3_vfs *, void *, const char *) xDlSym = 0x5c9eb1f61fe0 void(sqlite3_vfs *, void *) xDlClose = 0x5c9eb1fb4dc0 int(sqlite3_vfs *, int, char *) xRandomness = 0x5c9eb20f0bc0 int(sqlite3_vfs *, int) xSleep = 0x5c9eb1f61e90 int(sqlite3_vfs *, double *) xCurrentTime = 0x5c9eb1fe83b0 int(sqlite3_vfs *, int, char *) xGetLastError = 0x5c9eb1f9b230 int(sqlite3_vfs *, sqlite3_int64 *) xCurrentTimeInt64 = 0x5c9eb1fab1d0 int(sqlite3_vfs *, const char *, void()) xSetSystemCall = 0x5c9eb1fb0a50 void()(sqlite3_vfs *, const char *) xGetSystemCall = 0x5c9eb1fb0890 const char *(sqlite3_vfs *, const char *) xNextSystemCall = 0x5c9eb1fb05f0 }) const char *zName = 0x5c9eb25435c0 ("unix-excl") void *pAppData = 0x5c9eb258bb40 int(sqlite3_vfs *, const char *, sqlite3_file *, int, int *) xOpen = 0x5c9eb222bbe0 int(sqlite3_vfs *, const char *, int) xDelete = 0x5c9eb20f2720 int(sqlite3_vfs *, const char *, int, int *) xAccess = 0x5c9eb1fc98a0 int(sqlite3_vfs *, const char *, int, char *) xFullPathname = 0x5c9eb20f45a0 void *(sqlite3_vfs *, const char *) xDlOpen = 0x5c9eb1f61ff0 void(sqlite3_vfs *, int, char *) xDlError = 0x5c9eb20ce410 void()(sqlite3_vfs *, void *, const char *) xDlSym = 0x5c9eb1f61fe0 void(sqlite3_vfs *, void *) xDlClose = 0x5c9eb1fb4dc0 int(sqlite3_vfs *, int, char *) xRandomness = 0x5c9eb20f0bc0 int(sqlite3_vfs *, int) xSleep = 0x5c9eb1f61e90 int(sqlite3_vfs *, double *) xCurrentTime = 0x5c9eb1fe83b0 int(sqlite3_vfs *, int, char *) xGetLastError = 0x5c9eb1f9b230 int(sqlite3_vfs *, sqlite3_int64 *) xCurrentTimeInt64 = 0x5c9eb1fab1d0 int(sqlite3_vfs *, const char *, void()) xSetSystemCall = 0x5c9eb1fb0a50 void()(sqlite3_vfs *, const char *) xGetSystemCall = 0x5c9eb1fb0890 const char *(sqlite3_vfs *, const char *) xNextSystemCall = 0x5c9eb1fb05f0 }) const char *zName = 0x5c9eb254b160 ("memdb") void *pAppData = 0x5c9eb29172a0 int(sqlite3_vfs *, const char *, sqlite3_file *, int, int *) xOpen = 0x5c9eb222f1c0 int(sqlite3_vfs *, const char *, int) xDelete = NULL int(sqlite3_vfs *, const char *, int, int *) xAccess = 0x5c9eb1f6d320 int(sqlite3_vfs *, const char *, int, char *) xFullPathname = 0x5c9eb20cd960 void *(sqlite3_vfs *, const char *) xDlOpen = 0x5c9eb1f6d380 void(sqlite3_vfs *, int, char *) xDlError = 0x5c9eb1f6d490 void()(sqlite3_vfs *, void *, const char *) xDlSym = 0x5c9eb1f6d5b0 void(sqlite3_vfs *, void *) xDlClose = 0x5c9eb1f6d6d0 int(sqlite3_vfs *, int, char *) xRandomness = 0x5c9eb1f6d7e0 int(sqlite3_vfs *, int) xSleep = 0x5c9eb1f6d900 int(sqlite3_vfs *, double *) xCurrentTime = NULL int(sqlite3_vfs *, int, char *) xGetLastError = 0x5c9eb1f6da10 int(sqlite3_vfs *, sqlite3_int64 *) xCurrentTimeInt64 = 0x5c9eb1f6db40 int(sqlite3_vfs *, const char *, void()) xSetSystemCall = NULL void()(sqlite3_vfs *, const char *) xGetSystemCall = NULL const char *(sqlite3_vfs *, const char *) xNextSystemCall = NULL }) const char *zName = 0x5c9eb2553e60 ("unix") void *pAppData = 0x5c9eb258bb40 int(sqlite3_vfs *, const char *, sqlite3_file *, int, int *) xOpen = 0x5c9eb222bbe0 int(sqlite3_vfs *, const char *, int) xDelete = 0x5c9eb20f2720 int(sqlite3_vfs *, const char *, int, int *) xAccess = 0x5c9eb1fc98a0 int(sqlite3_vfs *, const char *, int, char *) xFullPathname = 0x5c9eb20f45a0 void *(sqlite3_vfs *, const char *) xDlOpen = 0x5c9eb1f61ff0 void(sqlite3_vfs *, int, char *) xDlError = 0x5c9eb20ce410 void()(sqlite3_vfs *, void *, const char *) xDlSym = 0x5c9eb1f61fe0 void(sqlite3_vfs *, void *) xDlClose = 0x5c9eb1fb4dc0 int(sqlite3_vfs *, int, char *) xRandomness = 0x5c9eb20f0bc0 int(sqlite3_vfs *, int) xSleep = 0x5c9eb1f61e90 int(sqlite3_vfs *, double *) xCurrentTime = 0x5c9eb1fe83b0 int(sqlite3_vfs *, int, char *) xGetLastError = 0x5c9eb1f9b230 int(sqlite3_vfs *, sqlite3_int64 *) xCurrentTimeInt64 = 0x5c9eb1fab1d0 int(sqlite3_vfs *, const char *, void()) xSetSystemCall = 0x5c9eb1fb0a50 void()(sqlite3_vfs *, const char *) xGetSystemCall = 0x5c9eb1fb0890 const char *(sqlite3_vfs *, const char *) xNextSystemCall = 0x5c9eb1fb05f0 }) Vdbe *pVdbe = NULL CollSeq *pDfltColl = 0x50d000000048 ({ char *zName = 0x50d0000000c0 ("BINARY") u8 enc = 1 void *pUser = NULL int(void *, int, const void *, int, const void *) xCmp = 0x5c9eb1fb4de0 void(void *) xDel = NULL }) sqlite3_mutex *mutex = 0x504000000058 ({ pthread_mutex_t mutex = { __pthread_mutex_s __data = { int __lock = 0 unsigned int __count = 0 int __owner = 0 unsigned int __nusers = 0 int __kind = 1 short int __spins = 0 short int __elision = 0 __pthread_list_t __list = { __pthread_internal_list *__prev = NULL __pthread_internal_list *__next = NULL } } char[] __size = [0 , 1, 0 ] long int __align = 0 } }) Db *aDb = 0x518000000320 ({ char *zDbSName = 0x5c9eb2537ac0 ("main") Btree *pBt = 0x507000000028 (<#2> { sqlite3 *db = 0x518000000088 () BtShared *pBt = 0x50e000000048 ({ Pager *pPager = 0x518000000488 ({ sqlite3_vfs *pVfs = 0x5c9eb29172a0 () u8 exclusiveMode = 0 u8 journalMode = 0 u8 useJournal = 1 u8 noSync = 0 u8 fullSync = 1 u8 extraSync = 0 u8 syncFlags = 2 u8 walSyncFlags = 10 u8 tempFile = 0 u8 noLock = 0 u8 readOnly = 0 u8 memDb = 0 u8 memVfs = 0 u8 eState = 0 u8 eLock = 0 u8 changeCountDone = 0 u8 setSuper = 0 u8 doNotSpill = 0 u8 subjInMemory = 0 u8 bUseFetch = 0 u8 hasHeldSharedLock = 0 Pgno dbSize = 0 Pgno dbOrigSize = 0 Pgno dbFileSize = 0 Pgno dbHintSize = 0 int errCode = 0 int nRec = 0 u32 cksumInit = 0 u32 nSubRec = 0 Bitvec *pInJournal = NULL sqlite3_file *fd = 0x518000000610 ({ const sqlite3_io_methods *pMethods = 0x5c9eb258bb80 ({ int iVersion = 3 int(sqlite3_file *) xClose = 0x5c9eb20efc30 int(sqlite3_file *, void *, int, sqlite3_int64) xRead = 0x5c9eb1fb29b0 int(sqlite3_file *, const void *, int, sqlite3_int64) xWrite = 0x5c9eb1fe5440 int(sqlite3_file *, sqlite3_int64) xTruncate = 0x5c9eb20f0f70 int(sqlite3_file *, int) xSync = 0x5c9eb20f13f0 int(sqlite3_file *, sqlite3_int64 *) xFileSize = 0x5c9eb1f9aea0 int(sqlite3_file *, int) xLock = 0x5c9eb2020d40 int(sqlite3_file *, int) xUnlock = 0x5c9eb20eea50 int(sqlite3_file *, int *) xCheckReservedLock = 0x5c9eb1f9b290 int(sqlite3_file *, int, void *) xFileControl = 0x5c9eb2225490 int(sqlite3_file *) xSectorSize = 0x5c9eb1f6c860 int(sqlite3_file *) xDeviceCharacteristics = 0x5c9eb1f6c8d0 int(sqlite3_file *, int, int, int, volatile void **) xShmMap = 0x5c9eb222fd30 int(sqlite3_file *, int, int, int) xShmLock = 0x5c9eb1fb3280 void(sqlite3_file *) xShmBarrier = 0x5c9eb1fee470 int(sqlite3_file *, int) xShmUnmap = 0x5c9eb20ef450 int(sqlite3_file *, sqlite3_int64, int, void **) xFetch = 0x5c9eb20f2360 int(sqlite3_file *, sqlite3_int64, void *) xUnfetch = 0x5c9eb1f6cf70 }) }) sqlite3_file *jfd = 0x518000000700 ({ const sqlite3_io_methods *pMethods = NULL }) sqlite3_file *sjfd = 0x518000000688 ({ const sqlite3_io_methods *pMethods = NULL }) i64 journalOff = 0 i64 journalHdr = 0 sqlite3_backup *pBackup = NULL PagerSavepoint *aSavepoint = NULL int nSavepoint = 0 u32 iDataVersion = 1 char[] dbFileVers = [0 ] int nMmapOut = 0 sqlite3_int64 szMmap = 0 PgHdr *pMmapFreelist = NULL u16 nExtra = 136 i16 nReserve = 0 u32 vfsFlags = 262 u32 sectorSize = 512 Pgno mxPgno = 4294967294 Pgno lckPgno = 262145 i64 pageSize = 4096 i64 journalSizeLimit = -1 char *zFilename = 0x518000000784 ("/home/tx/projects/uprintf/test.db") char *zJournal = 0x5180000007a7 ("/home/tx/projects/uprintf/test.db-journal") int(void *) xBusyHandler = 0x5c9eb1f91310 void *pBusyHandlerArg = 0x50e000000048 u32[] aStat = [0 ] void(DbPage *) xReiniter = 0x5c9eb20e3d30 int(Pager *, Pgno, DbPage **, int) xGet = 0x5c9eb21c6150 char *pTmpSpace = 0x521000000108 ("") PCache *pPCache = 0x5180000005c0 ({ PgHdr *pDirty = NULL PgHdr *pDirtyTail = NULL PgHdr *pSynced = NULL i64 nRefSum = 0 int szCache = -2000 int szSpill = 1 int szPage = 4096 int szExtra = 136 u8 bPurgeable = 1 u8 eCreate = 2 int(void *, PgHdr *) xStress = 0x5c9eb22463a0 void *pStress = 0x518000000488 sqlite3_pcache *pCache = 0x50f000000048 ({}) }) Wal *pWal = NULL char *zWal = 0x5180000007d1 ("/home/tx/projects/uprintf/test.db-wal") }) sqlite3 *db = 0x518000000088 () BtCursor *pCursor = NULL MemPage *pPage1 = NULL u8 openFlags = 0 u8 autoVacuum = 0 u8 incrVacuum = 0 u8 bDoTruncate = 0 u8 inTransaction = 0 u8 max1bytePayload = 0 u8 nReserveWanted = 0 u16 btsFlags = 0 u16 maxLocal = 0 u16 minLocal = 0 u16 maxLeaf = 0 u16 minLeaf = 0 u32 pageSize = 4096 u32 usableSize = 4096 int nTransaction = 0 u32 nPage = 0 void *pSchema = 0x50c000000108 void(void *) xFreeSchema = 0x5c9eb2000070 sqlite3_mutex *mutex = NULL Bitvec *pHasContent = NULL int nRef = 1 BtShared *pNext = NULL BtLock *pLock = NULL Btree *pWriter = NULL u8 *pTmpSpace = NULL int nPreformatSize = 0 }) u8 inTrans = 0 u8 sharable = 0 u8 locked = 0 u8 hasIncrblobCur = 0 int wantToLock = 0 int nBackup = 0 u32 iBDataVersion = 0 Btree *pNext = NULL Btree *pPrev = NULL BtLock lock = { Btree *pBtree = 0x507000000028 () Pgno iTable = 1 u8 eLock = 0 BtLock *pNext = NULL } }) u8 safety_level = 3 u8 bSyncSet = 0 Schema *pSchema = 0x50c000000108 ({ int schema_cookie = 0 int iGeneration = 0 Hash tblHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash idxHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash trigHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash fkeyHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Table *pSeqTab = NULL u8 file_format = 0 u8 enc = 1 u16 schemaFlags = 0 int cache_size = 0 }) }) int nDb = 2 u32 mDbFlags = 0 u64 flags = 3758391520 i64 lastRowid = 0 i64 szMmap = 0 u32 nSchemaLock = 0 unsigned int openFlags = 6 int errCode = 0 int errByteOffset = -1 int errMask = 255 int iSysErrno = 0 u32 dbOptFlags = 0 u8 enc = 1 u8 autoCommit = 1 u8 temp_store = 0 u8 mallocFailed = 0 u8 bBenignMalloc = 0 u8 dfltLockMode = 0 signed char nextAutovac = -1 u8 suppressErr = 0 u8 vtabOnConflict = 0 u8 isTransactionSavepoint = 0 u8 mTrace = 0 u8 noSharedCache = 0 u8 nSqlExec = 0 u8 eOpenState = 118 ('v') int nextPagesize = 0 i64 nChange = 0 i64 nTotalChange = 0 int[] aLimit = [1000000000, 1000000000, 2000, 1000, 500, 250000000, 127, 10, 50000, 32766, 1000, 0] int nMaxSorterMmap = 0 sqlite3InitInfo init = { Pgno newTnum = 0 u8 iDb = 0 u8 busy = 0 unsigned int orphanTrigger = 0 <1 bit> unsigned int imposterTable = 0 <1 bit> unsigned int reopenMemdb = 0 <1 bit> const char **azInit = 0x5c9eb29199a0 } int nVdbeActive = 0 int nVdbeRead = 0 int nVdbeWrite = 0 int nVdbeExec = 0 int nVDestroy = 0 int nExtension = 0 void **aExtension = NULL union trace = { void(void *, const char *) xLegacy = NULL int(u32, void *, void *, void *) xV2 = NULL } void *pTraceArg = NULL void(void *, const char *, u64) xProfile = NULL void *pProfileArg = NULL void *pCommitArg = NULL int(void *) xCommitCallback = NULL void *pRollbackArg = NULL void(void *) xRollbackCallback = NULL void *pUpdateArg = NULL void(void *, int, const char *, const char *, sqlite_int64) xUpdateCallback = NULL void *pAutovacPagesArg = NULL void(void *) xAutovacDestr = NULL unsigned int(void *, const char *, u32, u32, u32) xAutovacPages = NULL Parse *pParse = NULL int(void *, sqlite3 *, const char *, int) xWalCallback = 0x5c9eb2423eb0 void *pWalArg = 0x3e8 void(void *, sqlite3 *, int, const char *) xCollNeeded = NULL void(void *, sqlite3 *, int, const void *) xCollNeeded16 = NULL void *pCollNeededArg = NULL sqlite3_value *pErr = NULL union u1 = { volatile int isInterrupted = 0 double notUsed1 = 0.000000 } Lookaside lookaside = { u32 bDisable = 0 u16 sz = 1200 u16 szTrue = 1200 u8 bMalloced = 1 u32 nSlot = 123 u32[] anStat = [0, 0, 0] LookasideSlot *pInit = 0x52e000008bf8 ({ LookasideSlot *pNext = 0x52e000008748 ({ LookasideSlot *pNext = 0x52e000008298 ({ LookasideSlot *pNext = 0x52e000007de8 ({ LookasideSlot *pNext = 0x52e000007938 ({ LookasideSlot *pNext = 0x52e000007488 ({ LookasideSlot *pNext = 0x52e000006fd8 ({ LookasideSlot *pNext = 0x52e000006b28 ({ LookasideSlot *pNext = 0x52e000006678 ({...}) }) }) }) }) }) }) }) }) LookasideSlot *pFree = NULL LookasideSlot *pSmallInit = 0x52e00000bea8 ({ LookasideSlot *pNext = 0x52e00000be28 ({ LookasideSlot *pNext = 0x52e00000bda8 ({ LookasideSlot *pNext = 0x52e00000bd28 ({ LookasideSlot *pNext = 0x52e00000bca8 ({ LookasideSlot *pNext = 0x52e00000bc28 ({ LookasideSlot *pNext = 0x52e00000bba8 ({ LookasideSlot *pNext = 0x52e00000bb28 ({ LookasideSlot *pNext = 0x52e00000baa8 ({...}) }) }) }) }) }) }) }) }) LookasideSlot *pSmallFree = NULL void *pMiddle = 0x52e0000090a8 void *pStart = 0x52e000000408 void *pEnd = 0x52e00000bf28 void *pTrueEnd = 0x52e00000bf28 } int(void *, int, const char *, const char *, const char *, const char *) xAuth = NULL void *pAuthArg = NULL int(void *) xProgress = NULL void *pProgressArg = NULL unsigned int nProgressOps = 0 int nVTrans = 0 Hash aModule = { unsigned int htsize = 0 unsigned int count = 2 HashElem *first = 0x504000000218 (<#3> { HashElem *next = 0x5040000001d8 ({ HashElem *next = NULL HashElem *prev = 0x504000000218 () void *data = 0x507000000098 const char *pKey = 0x5070000000c8 ("json_each") }) HashElem *prev = NULL void *data = 0x507000000108 const char *pKey = 0x507000000138 ("json_tree") }) _ht *ht = NULL } VtabCtx *pVtabCtx = NULL VTable **aVTrans = NULL VTable *pDisconnect = NULL Hash aFunc = { unsigned int htsize = 0 unsigned int count = 1 HashElem *first = 0x504000000198 ({ HashElem *next = NULL HashElem *prev = NULL void *data = 0x5080000000a8 const char *pKey = 0x5080000000f0 ("match") }) _ht *ht = NULL } Hash aCollSeq = { unsigned int htsize = 0 unsigned int count = 3 HashElem *first = 0x504000000118 (<#4> { HashElem *next = 0x5040000000d8 (<#5> { HashElem *next = 0x504000000098 ({ HashElem *next = NULL HashElem *prev = 0x5040000000d8 () void *data = 0x50d000000048 const char *pKey = 0x50d0000000c0 ("BINARY") }) HashElem *prev = 0x504000000118 () void *data = 0x50d000000118 const char *pKey = 0x50d000000190 ("NOCASE") }) HashElem *prev = NULL void *data = 0x50d0000001e8 const char *pKey = 0x50d000000260 ("RTRIM") }) _ht *ht = NULL } BusyHandler busyHandler = { int(void *, int) xBusyHandler = NULL void *pBusyArg = NULL int nBusy = 0 } Db[] aDbStatic = [ { char *zDbSName = 0x5c9eb2537ac0 ("main") Btree *pBt = 0x507000000028 () u8 safety_level = 3 u8 bSyncSet = 0 Schema *pSchema = 0x50c000000108 ({ int schema_cookie = 0 int iGeneration = 0 Hash tblHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash idxHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash trigHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash fkeyHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Table *pSeqTab = NULL u8 file_format = 0 u8 enc = 1 u16 schemaFlags = 0 int cache_size = 0 }) }, { char *zDbSName = 0x5c9eb2538d80 ("temp") Btree *pBt = NULL u8 safety_level = 1 u8 bSyncSet = 0 Schema *pSchema = 0x50c0000001c8 ({ int schema_cookie = 0 int iGeneration = 0 Hash tblHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash idxHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash trigHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Hash fkeyHash = { unsigned int htsize = 0 unsigned int count = 0 HashElem *first = NULL _ht *ht = NULL } Table *pSeqTab = NULL u8 file_format = 0 u8 enc = 1 u16 schemaFlags = 0 int cache_size = 0 }) } ] Savepoint *pSavepoint = NULL int nAnalysisLimit = 0 int busyTimeout = 0 int nSavepoint = 0 int nStatement = 0 i64 nDeferredCons = 0 i64 nDeferredImmCons = 0 int *pnBytesFreed = NULL DbClientData *pDbData = NULL } ```
vorbis ```c Vorbis data: { unsigned int sample_rate = 44100 int channels = 2 unsigned int setup_memory_required = 193864 unsigned int temp_memory_required = 4096 unsigned int setup_temp_memory_required = 7209 char *vendor = 0x504000000010 ("Xiph.Org libVorbis I 20120203 (Omnipresent)") int comment_list_length = 3 char **comment_list = 0x503000000100 FILE *f = 0x515000000080 () uint32 f_start = 0 int close_on_free = 1 uint8 *stream = NULL uint8 *stream_start = NULL uint8 *stream_end = NULL uint32 stream_len = 1032948 uint8 push_mode = 0 uint32 first_audio_page_offset = 4465 ProbedPage p_first = { uint32 page_start = 4465 uint32 page_end = 8913 uint32 last_decoded_sample = 22080 } ProbedPage p_last = { uint32 page_start = 0 uint32 page_end = 0 uint32 last_decoded_sample = 0 } stb_vorbis_alloc alloc = { char *alloc_buffer = NULL int alloc_buffer_length_in_bytes = 0 } int setup_offset = 0 int temp_offset = 0 int eof = 0 STBVorbisError error = VORBIS__no_error (0) int[] blocksize = [256, 2048] int blocksize_0 = 256 int blocksize_1 = 2048 int codebook_count = 42 Codebook *codebooks = 0x532000000800 ({ int dimensions = 1 int entries = 8 uint8 *codeword_lengths = 0x502000000030 ("") float minimum_value = 0.000000 float delta_value = 0.000000 uint8 value_bits = 0 uint8 lookup_type = 0 uint8 sequence_p = 0 uint8 sparse = 0 uint32 lookup_values = 0 codetype *multiplicands = NULL uint32 *codewords = 0x503000000190 (0) int16[] fast_huffman = [0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 3, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 7, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0, 4, 0, 2, 0, 4, 0, 1, 0, 4, 0, 5, 0, 4] uint32 *sorted_codewords = NULL int *sorted_values = NULL int sorted_entries = 0 }) int floor_count = 2 uint16[] floor_types = [1, 1, 0 ] Floor *floor_config = 0x51f000000080 ( { Floor0 floor0 = { uint8 order = 6 uint16 rate = 257 uint16 bark_map_size = 770 uint8 amplitude_bits = 3 uint8 amplitude_offset = 190 uint8 number_of_books = 190 uint8[] book_list = [190 ] } Floor1 floor1 = { uint8 partitions = 6 uint8[] partition_class_list = [0, 1, 1, 2, 3, 3, 190 ] uint8[] class_dimensions = [2, 3, 3, 3, 190 ] uint8[] class_subclasses = [0, 1, 2, 2, 190 ] uint8[] class_masterbooks = [190, 0, 1, 2, 190 ] int16[][] subclass_books = [ [3, -16706 ], [4, 5, -16706 ], [-1, 6, 7, 8, -16706 ], [-1, 9, 10, 11, -16706 ], [-16706 ] ] uint16[] Xlist = [0, 128, 12, 46, 4, 8, 16, 23, 33, 70, 2, 6, 10, 14, 19, 28, 39, 58, 90, 48830 ] uint8[] sorted_order = [0, 10, 4, 11, 5, 12, 2, 13, 6, 14, 7, 15, 8, 16, 3, 17, 9, 18, 1, 190 ] uint8[][] neighbors = [ [190, 190], [190, 190], [0, 1], [2, 1], [0, 2], [4, 2], [2, 3], [6, 3], [7, 3], [3, 1], [0, 4], [4, 5], [5, 2], [2, 6], [6, 7], [7, 8], [8, 3], [3, 9], [9, 1], [190, 190] ] uint8 floor1_multiplier = 2 uint8 rangebits = 7 int values = 19 } }) int residue_count = 2 uint16[] residue_types = [2, 2, 0 ] Residue *residue_config = 0x5060000005c0 ({ uint32 begin = 0 uint32 end = 240 uint32 part_size = 16 uint8 classifications = 10 uint8 classbook = 27 uint8 **classdata = 0x518000001080 int16[] *residue_books = 0x50e0000003c0 ([-1 ]) }) int mapping_count = 2 Mapping *mapping = 0x5080000004a0 ({ uint16 coupling_steps = 1 MappingChannel *chan = 0x502000001ab0 ({ uint8 magnitude = 0 uint8 angle = 1 uint8 mux = 0 }) uint8 submaps = 1 uint8[] submap_floor = [0 ] uint8[] submap_residue = [0 ] }) int mode_count = 2 Mode[] mode_config = [ { uint8 blockflag = 0 uint8 mapping = 0 uint16 windowtype = 0 uint16 transformtype = 0 }, { uint8 blockflag = 1 uint8 mapping = 1 uint16 windowtype = 0 uint16 transformtype = 0 }, { uint8 blockflag = 0 uint8 mapping = 0 uint16 windowtype = 0 uint16 transformtype = 0 } ] uint32 total_samples = 0 float[] channel_buffers = [0x525000000100 (-0.000001), 0x525000002900 (0.000001), NULL ] float[] outputs = [NULL ] float[] previous_window = [0x521000001500 (0.000001), 0x521000002900 (-0.000000), NULL ] int previous_length = 128 int16[] finalY = [0x506000000620 (26), 0x506000000680 (26), NULL ] uint32 current_loc = 0 int current_loc_valid = 1 float[] A = [0x515000001c00 (1.000000), 0x521000003d00 (1.000000)] float[] B = [0x515000001e80 (0.499991), 0x521000005100 (0.500000)] float[] C = [0x5110000020c0 (0.999699), 0x51d000001480 (0.999995)] float[] window = [0x515000002100 (0.000059), 0x521000006500 (0.000001)] uint16[] bit_reverse = [0x5060000006e0 (0), 0x515000002380 (0)] uint32 serial = 0 int last_page = 2 int segment_count = 35 uint8[] segments = [22, 255, 25, 127, 72 ('H'), 93 (']'), 233, 255, 101 ('e'), 71 ('G'), 65 ('A'), 115 ('s'), 82 ('R'), 103 ('g'), 245, 255, 107 ('k'), 72 ('H'), 63 ('?'), 62 ('>'), 62 ('>'), 113 ('q'), 79 ('O'), 94 ('^'), 234, 255, 107 ('k'), 71 ('G'), 64 ('@'), 118 ('v'), 87 ('W'), 93 (']'), 218, 255, 113 ('q'), 0 ] uint8 page_flag = 0 uint8 bytes_in_seg = 0 uint8 first_decode = 0 int next_seg = 1 int last_seg = 1 int last_seg_which = 0 uint32 acc = 0 int valid_bits = 3 int packet_bytes = 22 int end_seg_with_known_loc = 34 uint32 known_loc_for_packet = 22080 int discard_samples_deferred = 0 uint32 samples_output = 0 int page_crc_tests = -1 CRCscan[] scan = [ { uint32 goal_crc = 0 int bytes_left = 0 uint32 crc_so_far = 0 int bytes_done = 0 uint32 sample_loc = 0 } ] int channel_buffer_start = 0 int channel_buffer_end = 0 } ```

Installation

Installing a single header library is as simple as downloading uprintf.h.

If you have cloned the repository, it can be installed to /usr/local/include by running make install. \ This way you should be able to include it without copying the header to every project (since it is a default include path).

Requirements

Tested on:

Architectures: \ x86_64, amd64

Compilers: \ gcc-14.2, gcc-13.3, gcc-12.4 \ clang-18, clang-17, clang-14

Usage

  1. Copy or install the library, ensure it is in the include path

  2. Pick a single file and define UPRINTF_IMPLEMENTATION before the include:

    #define UPRINTF_IMPLEMENTATION
    #include "uprintf.h"

    This will copy library's implementation to be built as a part of this file, so you should choose rarely modified file in order to avoid unnecessary rebuilding. \ You can also define options here, see below.

  3. Add include in other files where you intend to use it:

    #include "uprintf.h"
  4. Call function.

    uprintf(fmt, ...);

    fmt - a format string with placeholders(% followed by a letter). Unlike in printf, you can use anything, e.g. I use %S. Use %% to print %. \ For each format specifier there must be a pointer to whatever should be printed in its place (except void*).

Options

Behavior of the library can be changed by setting options before implementation:

#define OPTION_NAME VALUE
#define UPRINTF_IMPLEMENTATION
#include "uprintf.h"

The list of options:

macro description default
UPRINTF_INDENTATION_WIDTH The number of spaces to use for indentation 4
UPRINTF_MAX_DEPTH How deep can nested structures be. Use a negative value to have no limit 10
UPRINTF_IGNORE_STDIO_FILE Should stdio.h's FILE be ignored true
UPRINTF_ARRAY_COMPRESSION_THRESHOLD The minimum number of consecutive array values that get compressed(VALUE <repeats X times>). Use a non-positive value to disable it 4
UPRINTF_MAX_STRING_LENGTH The max string length after which it will be truncated. Use a non-positive value to have no limit 200

How does it work?

TL;DR: It works by inspecting debugging information of the executable in a debugger-like manner, which allows it to interpret and format passed pointers.

  1. Read current binary.
  2. Parse ELF and DWARF.
  3. Get info about scopes and types.
  4. Locate scopes from which current call is invoked based on the PC.
  5. Parse provided arguments.
  6. Infer types from the parsed arguments.
  7. Print data using type definition as reference.

Tests

Tests take long to complete, so it is highly recommended to set -j NUMBER_OF_CORES.

If you use compiler other than gcc and clang (e.g. clang-18) make sure to specify COMPILERS or edit Makefile.

$ make tests
$ make tests -jNUMBER_OF_CORES
$ make tests COMPILERS=COMPILER_NAME