diff --git a/bin/pcc-asm.exe b/bin/pcc-asm.exe index 7c075cf..efa0d33 100644 Binary files a/bin/pcc-asm.exe and b/bin/pcc-asm.exe differ diff --git a/tools/pcc-asm.c b/tools/pcc-asm.c index 3e7c3a4..aa4008b 100644 --- a/tools/pcc-asm.c +++ b/tools/pcc-asm.c @@ -5,8 +5,10 @@ * Uses llvm-objdump if available, else objdump. * * Usage: - * pcc-asm program.exe disassemble all code - * pcc-asm program.exe main disassemble, filter by symbol + * pcc-asm program.exe disassemble all code (stdout) + * pcc-asm program.exe -o out.asm disassemble, save to file + * pcc-asm program.exe main disassemble, filter by symbol + * pcc-asm program.exe main -o out.asm filter and save * * License: MIT */ @@ -17,6 +19,9 @@ #ifdef _WIN32 # include +#else +# include +# include #endif static int file_exists(const char *f) @@ -28,7 +33,6 @@ static int file_exists(const char *f) static const char *find_objdump(void) { - /* common locations, first match wins */ static const char *cands[] = { "llvm-objdump.exe", "objdump.exe", @@ -43,67 +47,105 @@ static const char *find_objdump(void) for (i = 0; cands[i]; i++) if (file_exists(cands[i])) return cands[i]; - return "objdump"; /* hope it's in PATH */ + return "objdump"; +} + +/* run a command line; Windows uses cmd /c so that shell + redirection (>) and pipes (|) work */ +static void run_cmd(const char *cmd) +{ +#ifdef _WIN32 + STARTUPINFOA si; + PROCESS_INFORMATION pi; + char *full = (char*)malloc(strlen(cmd) + 24); + if (!full) return; + /* cmd /c "cmd" - double quotes so embedded quotes survive */ + strcpy(full, "cmd /c \""); + strcat(full, cmd); + strcat(full, "\""); + memset(&si, 0, sizeof si); + si.cb = sizeof si; + if (CreateProcessA(NULL, full, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + free(full); +#else + system(cmd); +#endif } int main(int argc, char **argv) { const char *objdump = find_objdump(); - const char *file; + const char *file = NULL; const char *filter = NULL; - char cmd[1024]; + const char *outfile = NULL; + char cmd[2048]; int len; + int i; + const char *tmpfile = NULL; - if (argc < 2) { + /* parse args: file [filter] [-o outfile] */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { + outfile = argv[++i]; + } else if (!file) { + file = argv[i]; + } else if (!filter) { + filter = argv[i]; + } else { + fprintf(stderr, "pcc-asm: too many arguments\n"); + return 1; + } + } + + if (!file) { fprintf(stderr, "pcc-asm - disassemble a PCC binary\n" "\n" "Usage:\n" - " pcc-asm program.exe disassemble all code\n" - " pcc-asm program.exe main disassemble, filter by symbol\n" + " pcc-asm program.exe disassemble all code\n" + " pcc-asm program.exe -o out.asm save to file\n" + " pcc-asm program.exe main filter by symbol\n" + " pcc-asm program.exe main -o out.asm filter and save\n" "\n" "Uses %s\n", objdump); return 1; } - file = argv[1]; - if (argc > 2) - filter = argv[2]; - if (!file_exists(file)) { fprintf(stderr, "pcc-asm: cannot open '%s'\n", file); return 1; } -#ifdef _WIN32 - len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\"", objdump, file); -#else - len = snprintf(cmd, sizeof cmd, "%s -d \"%s\"", objdump, file); -#endif - - if (filter) { - /* use objdump's symbol filter if supported, else grep-style */ - len += snprintf(cmd + len, sizeof cmd - len, " | findstr /c:\"%s\"", filter); + /* Step 1: disassemble. + If filtering, first write full output to a temp file, + then filter that file. */ + if (filter && outfile) { + /* need a temp file for the full listing */ + static char tmp[L_tmpnam + 1]; + tmpfile = tmpnam(tmp); + if (!tmpfile) { fprintf(stderr, "pcc-asm: tmpnam failed\n"); return 1; } + len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\" > \"%s\"", objdump, file, tmpfile); + run_cmd(cmd); + /* then filter temp -> outfile */ + len = snprintf(cmd, sizeof cmd, "findstr /c:\"%s\" \"%s\" > \"%s\"", filter, tmpfile, outfile); + run_cmd(cmd); + remove(tmpfile); + printf("pcc-asm: wrote %s\n", outfile); + } else if (filter) { + len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\" | findstr /c:\"%s\"", objdump, file, filter); + run_cmd(cmd); + } else if (outfile) { + len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\" > \"%s\"", objdump, file, outfile); + run_cmd(cmd); + printf("pcc-asm: wrote %s\n", outfile); + } else { + len = snprintf(cmd, sizeof cmd, "\"%s\" -d \"%s\"", objdump, file); + run_cmd(cmd); } - -#ifdef _WIN32 - { - STARTUPINFOA si; - PROCESS_INFORMATION pi; - char *cmdline = (char*)malloc(strlen(cmd) + 1); - if (!cmdline) return 1; - strcpy(cmdline, cmd); - memset(&si, 0, sizeof si); - si.cb = sizeof si; - if (CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { - WaitForSingleObject(pi.hProcess, INFINITE); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - free(cmdline); - } -#else - system(cmd); -#endif + (void)len; return 0; }