{"id":19795616,"url":"https://github.com/dkogan/findglobals","last_synced_at":"2026-06-14T10:33:25.597Z","repository":{"id":136714280,"uuid":"73678899","full_name":"dkogan/FindGlobals","owner":"dkogan","description":"Finds all global state in a program by looking at the DWARF data","archived":false,"fork":false,"pushed_at":"2019-01-03T22:41:42.000Z","size":24,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-11T02:25:38.055Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dkogan.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-14T07:30:17.000Z","updated_at":"2025-07-23T21:54:29.000Z","dependencies_parsed_at":"2023-07-09T12:16:18.035Z","dependency_job_id":null,"html_url":"https://github.com/dkogan/FindGlobals","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dkogan/FindGlobals","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2FFindGlobals","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2FFindGlobals/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2FFindGlobals/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2FFindGlobals/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dkogan","download_url":"https://codeload.github.com/dkogan/FindGlobals/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dkogan%2FFindGlobals/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34318523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T07:16:52.614Z","updated_at":"2026-06-14T10:33:25.579Z","avatar_url":"https://github.com/dkogan.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"* Overview\nThis is a proof-of-concept program that is able to find all global state in a\nprogram by parsing its debug information (which is assumed to be available).\n\nThe global state I'm looking for is all persistent data:\n\n- globals variables (static or otherwise)\n- static local variables in functions\n\nI'm only interested in data that can change, so I look /only/ at the writeable\nsegment. This program is beta-quality, but works for me, and is very useful.\n\n* Example\n=tst1.c=:\n#+BEGIN_SRC C\n// ....\nstruct S1 v1[10];\n\nvolatile const char volatile_const_char;\nconst volatile char const_volatile_char;\nconst char          const_char = 1;\n\nvoid print_tst1(void)\n{\n    showvar(v1);\n    showvar(volatile_const_char);\n    showvar(const_volatile_char);\n    showvar_readonly(const_char);\n}\n#+END_SRC\n\n=tst2.c=:\n#+BEGIN_SRC C\n// ....\nint v2 = 5;\n\nconst char*       const_char_pointer       = NULL;\nconst char const* const_char_const_pointer = NULL;\nchar const*       char_const_pointer       = NULL;\n\nconst        char  const_string_array[]        = \"456\";\nstatic const char  static_const_string_array[] = \"abc\";\n\nstruct S0 s0;\nint       x0[0];\nint       x1[30];\n\n\n\nvoid print_tst2(void)\n{\n    static int    static_int_5[5];\n    static double static_double;\n    double dynamic_d;\n\n    showvar(static_int_5);\n    showvar(static_double);\n    showvar(v2);\n    showvar(const_char_pointer);\n    showvar_readonly(const_char_const_pointer);\n    showvar_readonly(char_const_pointer);\n    showvar_readonly(const_string_array);\n    showvar_readonly(static_const_string_array);\n    showvar(s0);\n    showvar(x0);\n    showvar(x1);\n}\n#+END_SRC\n\n=show_globals_from_this_process.c=:\n#+BEGIN_SRC C\n// ...\n#include \"getglobals.h\"\n\nint main(int argc, char* argv[])\n{\n    printf(\"=================== Program sees: ===================\\n\");\n\n    print_tst1();\n    print_tst2();\n\n    printf(\"=================== DWARF sees: ===================\\n\");\n\n    get_addrs_from_this_process_from_DSO_with_function((void (*)())\u0026print_tst1, \"tst\");\n    return 0;\n}\n#+END_SRC\n\nResults:\n\n#+BEGIN_EXAMPLE\n$ ./show_globals_from_this_process 2\u003e/dev/null\n\n=================== Program sees: ===================\nv1 at 0x55756bc8e240, size 80\nvolatile_const_char at 0x55756bc8e220, size 1\nconst_volatile_char at 0x55756bc8e290, size 1\nreadonly const_char at 0x55756ba8cc65, size 1\nstatic_int_5 at 0x55756bc8e040, size 20\nstatic_double at 0x55756bc8e038, size 8\nv2 at 0x55756bc8e010, size 4\nconst_char_pointer at 0x55756bc8e030, size 8\nreadonly const_char_pointer_const at 0x55756ba8cbd0, size 8\nreadonly char_pointer_const at 0x55756ba8cbc8, size 8\nreadonly const_string_array at 0x55756ba8cbc4, size 4\nreadonly static_const_string_array at 0x55756ba8cbc0, size 4\ns0 at 0x55756bc8e120, size 100\nx0 at 0x55756bc8e184, size 0\nx1 at 0x55756bc8e1a0, size 120\n=================== DWARF sees: ===================\nv2 at 0x55756bc8e010, size 4\nconst_char_pointer at 0x55756bc8e030, size 8\nreadonly const_char_pointer_const at 0x55756ba8cbd0, size 8\nreadonly char_pointer_const at 0x55756ba8cbc8, size 8\nreadonly const_string_array at 0x55756ba8cbc4, size 4\nreadonly static_const_string_array at 0x55756ba8cbc0, size 4\ns0 at 0x55756bc8e120, size 100\nx1 at 0x55756bc8e1a0, size 120\nstatic_int_5 at 0x55756bc8e040, size 20\nstatic_double at 0x55756bc8e038, size 8\nv1 at 0x55756bc8e240, size 80\nvolatile_const_char at 0x55756bc8e220, size 1\nconst_volatile_char at 0x55756bc8e290, size 1\nreadonly const_char at 0x55756ba8cc65, size 1\n\n\ndima@shorty:$ ./show_globals_from_this_process 2\u003e/dev/null | sort | uniq -c | sort\n\n      1 =================== DWARF sees: ===================\n      1 =================== Program sees: ===================\n      1 x0 at 0x55be5ba3d184, size 0\n      2 const_char_pointer at 0x55be5ba3d030, size 8\n      2 const_volatile_char at 0x55be5ba3d290, size 1\n      2 readonly char_pointer_const at 0x55be5b83bbc8, size 8\n      2 readonly const_char at 0x55be5b83bc65, size 1\n      2 readonly const_char_pointer_const at 0x55be5b83bbd0, size 8\n      2 readonly const_string_array at 0x55be5b83bbc4, size 4\n      2 readonly static_const_string_array at 0x55be5b83bbc0, size 4\n      2 s0 at 0x55be5ba3d120, size 100\n      2 static_double at 0x55be5ba3d038, size 8\n      2 static_int_5 at 0x55be5ba3d040, size 20\n      2 v1 at 0x55be5ba3d240, size 80\n      2 v2 at 0x55be5ba3d010, size 4\n      2 volatile_const_char at 0x55be5ba3d220, size 1\n      2 x1 at 0x55be5ba3d1a0, size 120\n#+END_EXAMPLE\n\nIn the example above we see the test program report the locations and addreses\nof the data in the test DSO. Then the instrumentation reports the addresses and\ndata that it sees. These should be identical: the instrumentation should figure\nout the correct addresses. We then sort and count duplicate lines in the output.\nIf the two sets of reports were identical, we should see all lines appear 2\ntimes. We see this with 2 trivial exceptions:\n\n- The lines containing ======= are delimiters\n- =x0= has size 0, so the instrumentation doesn't even bother to report it\n\nIt is also possible to query non-loaded ELF files by running a different\nutility, and passing the query DSO on the commandline:\n\n#+BEGIN_EXAMPLE\ndima@shorty:$ ./show_globals_from_elf_file tst.so 2\u003e/dev/null\n\nv2 at 0x212028, size 4\nconst_char_pointer at 0x212050, size 8\nreadonly const_char_pointer_const at 0x10cc8, size 8\nreadonly char_pointer_const at 0x10cc0, size 8\nreadonly const_string_array at 0x10cbc, size 4\nreadonly static_const_string_array at 0x10cb8, size 4\ns0 at 0x212080, size 100\nx1 at 0x212100, size 120\nstatic_int_5 at 0x212060, size 20\nstatic_double at 0x212058, size 8\nv1 at 0x2121a0, size 80\nvolatile_const_char at 0x212180, size 1\nconst_volatile_char at 0x2121f0, size 1\nreadonly const_char at 0x10d60, size 1\n#+END_EXAMPLE\n\nThis is the same data, but since this DSO wasn't loaded, the addresses all have\noffsets.\n\nFinally, the variable ranges can be visualized with something like this:\n\n#+BEGIN_EXAMPLE\ndima@shorty:$ ./show_globals_from_elf_file tst.so 2\u003e/dev/null | \\\n               awk -n '!/readonly/ \u0026\u0026 /, size/ \\\n                 { addr = and($3,0xFFFFFFFF); \\\n                   print addr,\"range\", 0,addr, addr+$5; \\\n                   print addr,\"labels\",1,$1 }' | \\\n               feedgnuplot --domain --dataid --rangesize range 3 --rangesize labels 2 \\\n                           --style range 'with xerrorbars' \\\n                           --style labels 'with labels' \\\n                           --ymin -2 --ymax 3 \\\n                           --set 'xtics format \"0x%08x\"'\n#+END_EXAMPLE\n\n* Notes\n- The example in this tree works with both static linking\n  (=show_globals_from_this_process=) and dynamic linking\n  (=show_globals_from_this_process_viaso=).\n\n- This is proof-of-concept software. It's an excellent starting point if you\n  need this functionality, but do thoroughly test it for your use case.\n\n- This was written with C code in mind, and tested to work with Fortran as well.\n  I can imagine that C++ can produce persistent state in more ways. Again, test\n  it thoroughly\n\n- The libraries I'm using to parse the DWARF are woefully underdocumented, and\n  I'm probably not doing everything 100% correctly. At the risk of repeating\n  myself: test it thoroughly.\n\n- For ELF objects linked into the executable normally (whether statically or\n  dynamically) this works. If we're doing something funny like loading\n  libraries ourselves with =libdl=, then it /probably/ works too, but I'd test\n  it before assuming.\n\nThis effort uncovered a bug in gcc, and one in elfutils.\n\n** gcc bug\n\nhttps://gcc.gnu.org/bugzilla/show_bug.cgi?id=78100\n\n\nIt turns out that gcc erroneously omits the sizing information if you have an\narray object pre-declared as an =extern= of unknown size (as was done in my\nspecific library). So if you have this source:\n\n#+BEGIN_SRC C\n#include \u003cstdio.h\u003e\n\nextern int s[];\nint s[] = { 1,2,3 };\n\nint main(void)\n{\n    printf(\"%zd\\n\", sizeof(s));\n    return 0;\n}\n#+END_SRC\n\nthen the object produced by gcc \u003c= 6.2 doesn't know that =s= has /3/ integers.\n\n** elfutils bug\n\nApparently elfutils was misreporting the sizes of multi-dimensional arrays.\nReported and fixed here:\n\nhttps://sourceware.org/bugzilla/show_bug.cgi?id=22546\n\n* Copyright and License\nCopyright 2016      Dima Kogan\n          2017-2018 California Institute of Technology\n\nReleased under an MIT-style license:\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Ffindglobals","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdkogan%2Ffindglobals","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkogan%2Ffindglobals/lists"}