]> git.draconx.ca Git - dxcommon.git/blobdiff - scripts/pe-subsys.awk
Add a macro to probe -mwindows on MinGW.
[dxcommon.git] / scripts / pe-subsys.awk
diff --git a/scripts/pe-subsys.awk b/scripts/pe-subsys.awk
new file mode 100755 (executable)
index 0000000..62e9057
--- /dev/null
@@ -0,0 +1,145 @@
+#!/bin/awk -f
+#
+# Determine the subsystem of a PE32 executable.
+#
+# Copyright © 2022 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+BEGIN {
+  filename = ARGV[1];
+  subsys = "unknown";
+  endian = "unknown";
+
+  if (!filename) {
+    exit(1);
+  }
+  probe_dumper(filename);
+
+  od_read("0");
+  if ($2 == "055115") {
+    endian = "little";
+  } else if ($2 == "046532") {
+    endian = "big";
+  } else {
+    exit(1);
+  }
+
+  od_read("74");
+  val = 65536*od_decode($3) + od_decode($2);
+
+  pe_offset = sprintf("%o", val);
+  pe32_offset = sprintf("%o", val+24);
+  subsys_offset = sprintf("%o", val+24+68);
+
+  od_read(pe_offset);
+  if ($2 != "042520" || $3 != "000000") {
+    # bad PE header
+    exit(1);
+  }
+
+  od_read(pe32_offset);
+  if ($2 != "000413" && $2 != "001013") {
+    # bad PE32(+) header
+    exit(1);
+  }
+
+  od_read(subsys_offset);
+  subsys = od_decode($2);
+  if (subsys == 2)
+    subsys = "gui";
+  else if (subsys == 3)
+    subsys = "console";
+  else
+    subsys = "unknown (" subsys ")";
+
+  exit(0);
+}
+
+END {
+  print subsys
+}
+
+function probe_dumper(filename)
+{
+  (cmd = "od " filename " +10 2>/dev/null") | getline
+  close(cmd)
+
+  sub(/^0*/, "", $1);
+  if ($1 == 10) {
+    dumper_style = "od_traditional";
+    return;
+  }
+
+  (cmd = "od -j010 " filename " 2>/dev/null") | getline
+  close(cmd)
+
+  sub(/^0*/, "", $1);
+  if ($1 == 10) {
+    dumper_style = "od_posix";
+    return;
+  }
+
+  exit(1);
+}
+
+function od_read(offset, cmd)
+{
+  if (dumper_style == "od_traditional") {
+    cmd = "od " filename " +" offset;
+  } else if (dumper_style == "od_posix") {
+    cmd = "od -j0" offset " " filename;
+  }
+
+  cmd | getline
+  close(cmd);
+
+  if (endian == "big") {
+    $2 = od_bswap($2);
+    $3 = od_bswap($3);
+  }
+}
+
+# Byte-swap one of the 2-byte blocks of octal digits emitted by od.
+function od_bswap(word, i, digits, carry)
+{
+  for (i = 0; i < 6; i++) {
+    digits[i] = substr(word, i+1, 1);
+  }
+
+  # suss out the first byte by adjusting the first 4 digits left by 1 bit
+  if (carry = (digits[3] >= 4))
+    digits[3] -= 4;
+
+  for (i = 2; i >= 0; i--) {
+    if (carry = ( (digits[i] = digits[i]*2 + carry) >= 8 ))
+      digits[i] -= 8;
+  }
+
+  # now munge the second byte by adjusting the last 3 digits right 1 bit
+  carry = 0;
+  for (i = 3; i < 6; i++) {
+    carry = (digits[i] += 8*carry) % 2;
+    digits[i] = int(digits[i] / 2);
+  }
+
+  # and put the leftover bit in place
+  digits[0] += 4*carry;
+
+  return digits[3] digits[4] digits[5] digits[0] digits[1] digits[2];
+}
+
+# Parse a string of octal digits into a number.
+function od_decode(word, result)
+{
+  result = 0;
+
+  while (word) {
+    result = 8*result + substr(word, 1, 1);
+    word = substr(word, 2);
+  }
+
+  return result;
+}