Skip to content

dwtypes + dw2elf: Plan9 type-info sidecar + a.out→ELF64 converter#131

Merged
staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd
May 21, 2026
Merged

dwtypes + dw2elf: Plan9 type-info sidecar + a.out→ELF64 converter#131
staalmannen merged 1 commit into
mainfrom
claude/upgrade-ape-c-library-mmZGd

Conversation

@staalmannen

Copy link
Copy Markdown
Owner

Replace the aborted sys/src/ape/cmd/compiler/ approach with a simpler two-step pipeline that needs no libdwarfp in the compiler itself:

pcc -g foo.c

├─ 6c (unmodified, but _DWTYPES env var set by pcc)
│ → foo.o + foo.dwtypes (via new dwtypes.c hook in cc/)
├─ 6l → foo (Plan9 a.out, unchanged)
└─ dw2elf -o foo.elf foo foo.dwtypes
→ foo.elf (ELF64, executable on 9front + dwarfdump-readable)

New files:
sys/src/cmd/cc/dwtypes.c — writes per-function type-info sidecar;
activates when /env/_DWTYPES exists;
derives .dwtypes path from outfile
sys/src/cmd/cc/dwtypes.h — declaration for pgen.c hook
sys/src/ape/cmd/dw2elf/ — APE tool: reads Plan9 a.out fat header +
.dwtypes sidecar(s), emits ELF64 binary
with DW_TAG_subprogram / DW_TAG_formal_parameter
DIEs via libdwarfp

Modified:
sys/src/cmd/cc/pgen.c — call dwtypes_emit_func() at end of codgen()
sys/src/cmd/cc/mkfile — add dwtypes.$O and dwtypes.h
sys/src/ape/9src/cc.c — -g flag: set _DWTYPES, run dw2elf post-link
sys/src/ape/cmd/mkfile — add dw2elf, remove compiler

Removed:
sys/src/ape/cmd/compiler/ — obsolete (was trying to rebuild compilers
with libdwarfp; no longer needed)

https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs

Replace the aborted sys/src/ape/cmd/compiler/ approach with a simpler
two-step pipeline that needs no libdwarfp in the compiler itself:

  pcc -g foo.c
    │
    ├─ 6c (unmodified, but _DWTYPES env var set by pcc)
    │    → foo.o  +  foo.dwtypes   (via new dwtypes.c hook in cc/)
    ├─ 6l → foo               (Plan9 a.out, unchanged)
    └─ dw2elf -o foo.elf foo foo.dwtypes
         → foo.elf (ELF64, executable on 9front + dwarfdump-readable)

New files:
  sys/src/cmd/cc/dwtypes.c   — writes per-function type-info sidecar;
                               activates when /env/_DWTYPES exists;
                               derives .dwtypes path from outfile
  sys/src/cmd/cc/dwtypes.h   — declaration for pgen.c hook
  sys/src/ape/cmd/dw2elf/    — APE tool: reads Plan9 a.out fat header +
                               .dwtypes sidecar(s), emits ELF64 binary
                               with DW_TAG_subprogram / DW_TAG_formal_parameter
                               DIEs via libdwarfp

Modified:
  sys/src/cmd/cc/pgen.c      — call dwtypes_emit_func() at end of codgen()
  sys/src/cmd/cc/mkfile      — add dwtypes.$O and dwtypes.h
  sys/src/ape/9src/cc.c      — -g flag: set _DWTYPES, run dw2elf post-link
  sys/src/ape/cmd/mkfile     — add dw2elf, remove compiler

Removed:
  sys/src/ape/cmd/compiler/  — obsolete (was trying to rebuild compilers
                               with libdwarfp; no longer needed)

https://claude.ai/code/session_01WGAwvvTwDg2yknFkmZ3qzs
@staalmannen staalmannen merged commit bf4f40e into main May 21, 2026
1 check passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces DWARF debug information support for the Plan 9 C compiler suite by adding a -g flag to the compiler driver, implementing .dwtypes sidecar emission for type information, and providing a dw2elf utility to produce ELF64 binaries. The review feedback identified several areas for improved robustness, including the need for proper error handling for memory allocations and file reads, the prevention of potential integer overflows during bounds checking, and the use of safer string formatting functions.

static uint32_t sc_u32(void)
{
uint32_t v;
if(sc_pos + 4 > sc_len) return 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The bounds check sc_pos + 4 > sc_len can overflow if sc_pos is near the maximum value of size_t. It is safer to use subtraction to avoid the overflow.

	if(sc_pos > sc_len || sc_len - sc_pos < 4) return 0;

{
uint32_t n = sc_u32();
char *s;
if(n == 0 || sc_pos + n > sc_len) return strdup("?");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The bounds check sc_pos + n > sc_len is susceptible to integer overflow if n is large, which could lead to an out-of-bounds read in the subsequent memcpy. Using subtraction for the check is more robust.

	if(n == 0 || n > sc_len - sc_pos) return strdup("?");

uint32_t n = sc_u32();
char *s;
if(n == 0 || sc_pos + n > sc_len) return strdup("?");
s = malloc(n + 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The return value of malloc is not checked. Since n is read from an external file, it could be maliciously large, leading to a memory allocation failure and a subsequent crash in memcpy.

	s = malloc(n + 1);
	if(!s) return strdup("?");

rewind(f);
buf = malloc(*outlen ? *outlen : 1);
if(!buf) { fprintf(stderr, "dw2elf: out of memory\n"); exit(1); }
fread(buf, 1, *outlen, f);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The return value of fread should be checked to ensure that the entire file was read successfully. If fread returns less than *outlen, the buffer will contain uninitialized data.

	if(fread(buf, 1, *outlen, f) != *outlen) { perror("fread"); exit(1); }

int shn_text, shn_data, shn_bss, shn_shstr;
uint8_t zero = 0;

sidecars = malloc(argc * sizeof(char *));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The result of malloc is not checked for NULL. If the allocation fails, the program will crash when attempting to store pointers in the sidecars array.

	sidecars = malloc(argc * sizeof(char *));
	if(!sidecars) { fprintf(stderr, "dw2elf: out of memory\n"); exit(1); }

Comment on lines +450 to +451
dw_sects[k].data =
malloc(blen ? blen : 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The result of malloc is not checked. If memory allocation fails for a DWARF section, the program will continue with a NULL pointer, leading to a crash later when xwrite is called.

							dw_sects[k].data = malloc(blen ? blen : 1);
							if(!dw_sects[k].data) { fprintf(stderr, "dw2elf: out of memory\n"); exit(1); }

Comment thread sys/src/cmd/cc/dwtypes.c
Comment on lines +99 to +102
p = utfrrune(buf, '.');
if(p != nil)
*p = 0;
strncat(buf, ".dwtypes", sizeof(buf) - strlen(buf) - 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using strncat here is safe but slightly fragile. If the path in buf is already near the limit, the extension might be truncated. Using snprint to construct the full path is generally preferred in Plan 9 code for better clarity and safety.

Suggested change
p = utfrrune(buf, '.');
if(p != nil)
*p = 0;
strncat(buf, ".dwtypes", sizeof(buf) - strlen(buf) - 1);
p = utfrrune(buf, '.');
if(p == nil)
p = buf + strlen(buf);
snprint(p, sizeof(buf) - (p - buf), ".dwtypes");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants