visualize the data structures in a C program
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
12 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Struct Visualization</title>
  6. <base href="/">
  7. <meta name="viewport" content="width=device-width, initial-scale=1">
  8. <link rel="icon" type="image/x-icon" href="favicon.ico">
  9. </head>
  10. <style>
  11. :root {
  12. --r1: pink;
  13. --r2: blue;
  14. --r3: magenta;
  15. --r4: yellow;
  16. --r5: cyan;
  17. --r6: orange;
  18. --r7: lime;
  19. --r8: olive;
  20. }
  21. *::before,
  22. *::after,
  23. * {
  24. margin: 0;
  25. padding: 0;
  26. box-sizing: border-box;
  27. }
  28. html, body {
  29. min-height: 100vh;
  30. height: 100vh;
  31. overscroll-behavior: none;
  32. background: #F0EAD6;
  33. padding-top: 10px;
  34. direction: ltr;
  35. font: 16px HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;
  36. }
  37. .struct-info {
  38. padding: 0 20px 20px 20px;
  39. border-bottom: 1px solid silver;
  40. margin-bottom: 20px;
  41. }
  42. .struct-info-declaration {
  43. position: absolute;
  44. font-family: monospace;
  45. min-width: min-content;
  46. max-width: 20em;
  47. text-overflow: ellipsis;
  48. white-space: nowrap;
  49. font-size: 0.9em;
  50. transform: translateX(calc(50% - 10px));
  51. color: black;
  52. font-weight: normal;
  53. }
  54. .struct-info-declaration-name {
  55. font: 16px HelveticaNeue-Light,Helvetica Neue Light,Helvetica Neue,Helvetica,Arial,Lucida Grande,sans-serif;
  56. }
  57. .struct-info-declaration-top {
  58. top: -30px;
  59. }
  60. .struct-info-declaration-bottom {
  61. bottom: -30px;
  62. }
  63. .struct-info-byte-row-ellipsis {
  64. position: absolute;
  65. right: 1em;
  66. }
  67. .struct-info-byte-rows {
  68. display: flex;
  69. flex-direction: column;
  70. justify-content: flex-start;
  71. align-items: flex-start;
  72. }
  73. .struct-info-byte-row {
  74. display: flex;
  75. flex-wrap: wrap;
  76. flex-direction: row;
  77. justify-content: flex-start;
  78. align-items: center;
  79. }
  80. .struct-info-bytegroup {
  81. margin: 2em 0;
  82. display: flex;
  83. flex-wrap: wrap;
  84. flex-direction: row;
  85. justify-content: flex-start;
  86. align-items: center;
  87. }
  88. .struct-info-bytegroup:hover {
  89. background-color: orange;
  90. .struct-info-declaration {
  91. font-weight: bold;
  92. color: orange;
  93. }
  94. }
  95. .struct-info-header {
  96. font-weight: bold;
  97. font-family: monospace;
  98. }
  99. .struct-info-byte {
  100. position: relative;
  101. display: flex;
  102. justify-content: center;
  103. align-items: center;
  104. border: 1px solid black;
  105. width: 30px;
  106. height: 45px;
  107. }
  108. .struct-info-byte-alignment {
  109. background-color: seagreen;
  110. opacity: 0.4;
  111. }
  112. .struct-info-byte-first {
  113. border-left-width: 3px;
  114. }
  115. .struct-info-byte-unknown {
  116. border-left-width: 3px;
  117. background-color: maroon;
  118. font-weight: bold;
  119. color: white;
  120. }
  121. .struct-info-byte-counted-ellipsis {
  122. background-color: #808000;
  123. font-weight: bold;
  124. }
  125. .struct-info-byte-ellipsis {
  126. background-color: #400000;
  127. font-weight: bold;
  128. color: white;
  129. }
  130. dialog {
  131. position: sticky;
  132. top: 50vh;
  133. left: 50vw;
  134. transform: translate(-50%, -50%);
  135. padding: 20px;
  136. border: none;
  137. border-radius: 3px;
  138. background-color: #F0EAD6;
  139. box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.75);
  140. max-width: 80vw;
  141. max-height: 80vh;
  142. }
  143. input:not([type=checkbox]):not([type=radio]) {
  144. display: block;
  145. height: 2em;
  146. }
  147. p {
  148. margin: 20px;
  149. }
  150. input[type=checkbox] {
  151. width: 1.2rem;
  152. height: 1.2rem;
  153. }
  154. label {
  155. display: block;
  156. }
  157. label > input {
  158. margin: 5px 15px 15px 15px;
  159. }
  160. .fix-missing-declaration-dialog-footer {
  161. width: 100%;
  162. display: flex;
  163. flex-direction: row;
  164. justify-content: space-between;
  165. align-items: center;
  166. }
  167. button {
  168. width: 10rem;
  169. height: 2rem;
  170. }
  171. .help-idk {
  172. color: darkslategray;
  173. font-size: 0.9rem;
  174. }
  175. .help-idk-container {
  176. width: 100%;
  177. margin-bottom: 10px;
  178. display: flex;
  179. flex-direction: row;
  180. justify-content: flex-end;
  181. align-items: center;
  182. }
  183. </style>
  184. <body>
  185. <dialog
  186. id="fix-missing-declaration-dialog"
  187. >
  188. <p>What's the size and alignment of this type on your architecture?</p>
  189. <div class="help-idk-container">
  190. <p class="help-idk">
  191. Help, I don't know!
  192. </p>
  193. </div>
  194. <label>
  195. It's a bitfield!
  196. <input
  197. type="checkbox"
  198. />
  199. </label>
  200. <label>
  201. size (in bytes)
  202. <input
  203. type="number"
  204. min="1"
  205. value="8"
  206. />
  207. </label>
  208. <label>
  209. alignment (in bytes)
  210. <input
  211. type="number"
  212. value="8"
  213. />
  214. </label>
  215. <footer class="fix-missing-declaration-dialog-footer">
  216. <button
  217. onclick="fixMissingDeclDialog.close()"
  218. >
  219. Confirm
  220. </button>
  221. </footer>
  222. </dialog>
  223. <script defer>
  224. const fixMissingDeclDialog = document.getElementById("fix-missing-declaration-dialog");
  225. function createWithClasses(e, ...classes) {
  226. const elem = document.createElement(e);
  227. elem.classList.add(...classes);
  228. return elem;
  229. }
  230. function alignForward(a, b) {
  231. }
  232. function renderStruct(structInfo, containingElement) {
  233. const div = createWithClasses("div", "struct-info");
  234. const structInfoHeader = createWithClasses("label", "struct-info-header");
  235. structInfoHeader.innerText = `struct ${structInfo.name} - alias: ${structInfo.alias}`;
  236. div.appendChild(structInfoHeader);
  237. for (let i = 0; i < structInfo.declarations.length; i++) {
  238. const decl = structInfo.declarations[i];
  239. const position = i % 2 == 0;
  240. const positionClass = position ? "struct-info-declaration-top" : "struct-info-declaration-bottom";
  241. let bytesInStructSoFar = 0;
  242. if (decl.size === -1) {
  243. const byteGroup = createWithClasses("struct-info-bytegroup");
  244. byteGroup.onclick = fixMissingDeclDialog.showMoodal();
  245. const unknownByte = createWithClasses("div", "struct-info-byte", "struct-info-byte-unknown");
  246. unknownByte.innerText = "?";
  247. byteGroup.appendChild(unknownByte);
  248. const declaration = createWithClasses("div", "struct-info-declaration", positionClass);
  249. declaration.innerHTML = `${decl.type} <span class="struct-info-declaration-name">${decl.name}</span>`;
  250. unknownByte.appendChild(declaration);
  251. const ellipsisByte = createWithClasses("div", "struct-info-byte", "struct_info_byte_ellipsis");
  252. ellipsisByte.innerText = "...";
  253. byteGroup.appendChild(ellipsisByte);
  254. div.appendChild(byteGroup);
  255. } else {
  256. // find if we need to align this field - pad some alignment bytes visually if we do.
  257. const aligned = alignForward(bytesInStructSoFar, decl.align);
  258. const needsAlign = aligned !== bytesInStructSoFar;
  259. if (needsAlign) {
  260. //sb_concatf("%s", "<div class='struct-info-bytegroup'>");
  261. //for (int a = 0; a < (aligned - bytesInStructSoFar); a++) {
  262. // sb_concatf("%s", "<div class='struct-info-byte struct-info-byte-alignment'></div>");
  263. //}
  264. //sb_concatf("%s", "</div>");
  265. //bytesInStructSoFar += aligned - bytesInStructSoFar;
  266. }
  267. // now for the bytes representing the actual field.
  268. //sb_concatf("%s", "<div class='struct-info-bytegroup'>");
  269. //for (int b = 0; b < decl->size; b++) {
  270. // if (b == 0) {
  271. // sb_concatf(
  272. // "<div class='struct-info-byte struct-info-byte-first'>"
  273. // "<div class='struct-info-declaration %s'>"
  274. // "%s <span class='struct-info-declaration-name'>%s</span>"
  275. // "</div>"
  276. // "</div>"
  277. // , positionClass, decl->type, decl->name);
  278. // } else {
  279. // sb_concatf("%s", "<div class='struct-info-byte'></div>");
  280. // }
  281. //}
  282. //bytesInStructSoFar += decl->size;
  283. //sb_concatf("%s", "</div>"); // end bytegroup
  284. }
  285. //sb_concatf("%s", "</div></div>");
  286. }
  287. containingElement.appendChild(div);
  288. }
  289. function renderAllStructs() {
  290. for (let i = 0; i < window.structs.length; i++) {
  291. const structInfo = structs[i];
  292. renderStruct(structInfo, document.body);
  293. }
  294. }
  295. </script>
  296. <!-- c code will place a script tag containing all of the data structures in JSON format, and terminate the body and html tags -->
  297. <script>
  298. window.structs = JSON.parse(`[
  299. {"name":"Dummy","alias":"","filename":"main.c","lineNumber":78,"lineOffset":7,"size":13,"declarations":[{"type": "char*","name": "p","size": "8","align": "8","isBitfield": false},{"type": "char","name": "c","size": "1","align": "1","isBitfield": false},{"type": "int","name": "x","size": "4","align": "4","isBitfield": false}]},{"name":"Declaration","alias":"","filename":"main.c","lineNumber":162,"lineOffset":7,"size":145,"declarations":[{"type": "char","name": "type[64]","size": "64","align": "1","isBitfield": false},{"type": "char","name": "name[64]","size": "64","align": "1","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "ssize_t","name": "align","size": "8","align": "8","isBitfield": false},{"type": "bool","name": "isBitfield","size": "1","align": "1","isBitfield": false}]},{"name":"StructInfo","alias":"","filename":"main.c","lineNumber":170,"lineOffset":7,"size":151,"declarations":[{"type": "char","name": "name[64]","size": "64","align": "1","isBitfield": false},{"type": "char","name": "alias[64]","size": "64","align": "1","isBitfield": false},{"type": "char*","name": "filename","size": "8","align": "8","isBitfield": false},{"type": "int","name": "lineNumber","size": "4","align": "4","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "struct Declaration","name": "declarations[16]","size": "-1","align": "-1","isBitfield": false},{"type": "int","name": "numDeclarations","size": "4","align": "4","isBitfield": false}]},{"name":"Array","alias":"","filename":"main.c","lineNumber":214,"lineOffset":7,"size":16,"declarations":[{"type": "unsigned int","name": "length","size": "4","align": "4","isBitfield": false},{"type": "unsigned int","name": "capacity","size": "4","align": "4","isBitfield": false},{"type": "void*","name": "data","size": "8","align": "8","isBitfield": false}]},{"name":"TableEntry","alias":"TableEntry","filename":"table.h","lineNumber":27,"lineOffset":15,"size":23,"declarations":[{"type": "struct TableEntry*","name": "next","size": "8","align": "8","isBitfield": false},{"type": "char key","name": "TABLE_KEY_SIZE","size": "-1","align": "-1","isBitfield": false},{"type": "ssize_t","name": "size","size": "8","align": "8","isBitfield": false},{"type": "ssize_t","name": "align","size": "8","align": "8","isBitfield": false}]},{"name":"Table","alias":"Table","filename":"table.h","lineNumber":35,"lineOffset":15,"size":8,"declarations":[{"type": "TableEntry**","name": "entries","size": "8","align": "8","isBitfield": false}]},{"name":"","alias":"stb_lexer","filename":"stb_c_lexer.h","lineNumber":113,"lineOffset":0,"size":88,"declarations":[{"type": "char*","name": "input_stream","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "eof","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "parse_point","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "string_storage","size": "8","align": "8","isBitfield": false},{"type": "int","name": "string_storage_len","size": "4","align": "4","isBitfield": false},{"type": "char*","name": "where_firstchar","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "where_lastchar","size": "8","align": "8","isBitfield": false},{"type": "long","name": "token","size": "8","align": "8","isBitfield": false},{"type": "double","name": "real_number","size": "8","align": "8","isBitfield": false},{"type": "long","name": "int_number","size": "8","align": "8","isBitfield": false},{"type": "char*","name": "string","size": "8","align": "8","isBitfield": false},{"type": "int","name": "string_len","size": "4","align": "4","isBitfield": false}]},{"name":"","alias":"stb_lex_location","filename":"stb_c_lexer.h","lineNumber":134,"lineOffset":0,"size":8,"declarations":[{"type": "int","name": "line_number","size": "4","align": "4","isBitfield": false},{"type": "int","name": "line_offset","size": "4","align": "4","isBitfield": false}]}]`);renderAllStructs();
  300. </script></body></html>