Browse Source

misaka: initial merge

K. Lange 2 years ago
parent
commit
b35f7ac8c9
100 changed files with 2647 additions and 3163 deletions
  1. 11 29
      .github/workflows/build.yml
  2. 22 74
      .gitignore
  3. 7 1
      .gitmodules
  4. 181 383
      Makefile
  5. 1 1
      apps/about.c
  6. 41 41
      apps/compositor.c
  7. 6 0
      apps/demo.c
  8. 4 0
      apps/demo.krk
  9. 374 0
      apps/dhcp_bitbanger.c
  10. 1 1
      apps/du.c
  11. 1 1
      apps/fetch.c
  12. 4 4
      apps/file-browser.c
  13. 0 16
      apps/go-video.sh
  14. 8 8
      apps/help-browser.c
  15. 11 0
      apps/ifconfig.c
  16. 1 1
      apps/imgviewer.c
  17. 3 3
      apps/json-test.c
  18. 1 1
      apps/julia.c
  19. 1 1
      apps/killall.c
  20. 0 1166
      apps/kuroko.c
  21. 9 3
      apps/lspci.c
  22. 1 1
      apps/migrate.c
  23. 66 0
      apps/misaka-test.c
  24. 2 2
      apps/msk.c
  25. 2 2
      apps/package-manager.c
  26. 1 1
      apps/pidof.c
  27. 1 1
      apps/plasma.c
  28. 2 2
      apps/pong.c
  29. 1 1
      apps/ps.c
  30. 3 3
      apps/pstree.c
  31. 632 200
      apps/readelf.c
  32. 0 5
      apps/reload_desktop.sh
  33. 1 1
      apps/sdf-demo.c
  34. 1 1
      apps/set-resolution.c
  35. 0 12
      apps/set_wallpaper.sh
  36. 2 1
      apps/sh.c
  37. 1 1
      apps/showdialog.c
  38. 1 1
      apps/sleep.c
  39. 25 60
      apps/splash-log.c
  40. 8 8
      apps/tar.c
  41. BIN
      apps/terminal-font.h
  42. 1 1
      apps/terminal-vga.c
  43. 10 6
      apps/terminal.c
  44. 6 0
      apps/test-cxx.c++
  45. 1 1
      apps/test-tls.c
  46. 0 5
      apps/test.sh
  47. 4 4
      apps/tutorial.c
  48. 1 1
      apps/wallpaper-picker.c
  49. 1 0
      apps/weather-tool.c
  50. 1 1
      base/etc/msk.conf
  51. 0 0
      base/lib/.dummy
  52. 0 23
      base/opt/asm-demo.s
  53. 0 54
      base/opt/bochsrc.txt
  54. 0 7
      base/opt/build.sh
  55. 0 6
      base/opt/test.c
  56. 1 1
      base/usr/include/ctype.h
  57. 1 1
      base/usr/include/errno.h
  58. 16 5
      base/usr/include/inttypes.h
  59. 53 0
      base/usr/include/kernel/arch/x86_64/acpi.h
  60. 5 0
      base/usr/include/kernel/arch/x86_64/cmos.h
  61. 87 0
      base/usr/include/kernel/arch/x86_64/irq.h
  62. 41 0
      base/usr/include/kernel/arch/x86_64/mmu.h
  63. 23 0
      base/usr/include/kernel/arch/x86_64/pml.h
  64. 12 0
      base/usr/include/kernel/arch/x86_64/ports.h
  65. 18 0
      base/usr/include/kernel/arch/x86_64/regs.h
  66. 3 6
      base/usr/include/kernel/args.h
  67. 0 141
      base/usr/include/kernel/ata.h
  68. 0 19
      base/usr/include/kernel/bitset.h
  69. 0 20
      base/usr/include/kernel/boot.h
  70. 337 169
      base/usr/include/kernel/elf.h
  71. 0 174
      base/usr/include/kernel/ext2.h
  72. 22 0
      base/usr/include/kernel/generic.h
  73. 16 0
      base/usr/include/kernel/gzip.h
  74. 42 0
      base/usr/include/kernel/hashmap.h
  75. 0 188
      base/usr/include/kernel/ipv4.h
  76. 50 0
      base/usr/include/kernel/list.h
  77. 0 27
      base/usr/include/kernel/logging.h
  78. 0 16
      base/usr/include/kernel/mem.h
  79. 14 0
      base/usr/include/kernel/misc.h
  80. 2 0
      base/usr/include/kernel/mmu.h
  81. 2 0
      base/usr/include/kernel/mod/net.h
  82. 1 2
      base/usr/include/kernel/mod/snd.h
  83. 0 43
      base/usr/include/kernel/module.h
  84. 2 0
      base/usr/include/kernel/mouse.h
  85. 44 44
      base/usr/include/kernel/multiboot.h
  86. 102 0
      base/usr/include/kernel/net/e1000.h
  87. 3 1
      base/usr/include/kernel/pci.h
  88. 10 3
      base/usr/include/kernel/pipe.h
  89. 6 7
      base/usr/include/kernel/printf.h
  90. 186 128
      base/usr/include/kernel/process.h
  91. 12 0
      base/usr/include/kernel/procfs.h
  92. 3 2
      base/usr/include/kernel/pty.h
  93. 7 0
      base/usr/include/kernel/ramdisk.h
  94. 6 1
      base/usr/include/kernel/ringbuffer.h
  95. 5 6
      base/usr/include/kernel/shm.h
  96. 16 7
      base/usr/include/kernel/signal.h
  97. 19 0
      base/usr/include/kernel/spinlock.h
  98. 7 6
      base/usr/include/kernel/libc.h
  99. 11 0
      base/usr/include/kernel/symboltable.h
  100. 0 0
      base/usr/include/kernel/syscall.h

+ 11 - 29
.github/workflows/build.yml

@@ -8,37 +8,19 @@ jobs:
         uses: actions/checkout@v2
         with:
             fetch-depth: 0
-            submodules: true
+      - name: Clone Kuroko
+        uses: actions/checkout@v2
+        with:
+          repository: kuroko-lang/kuroko
+          path: kuroko
       - name: Pull Builder Image
-        run: docker pull toaruos/build-tools:1.8.x
+        run: docker pull toaruos/build-tools:1.99.x
       - name: Run Builder
-        run: docker run -v ${GITHUB_WORKSPACE}:/root/toaruos -w /root/toaruos -e LANG=C.UTF-8 -t toaruos/build-tools:1.8.x util/build-in-docker.sh
+        run: docker run -v ${GITHUB_WORKSPACE}:/root/misaka -w /root/misaka -e LANG=C.UTF-8 -t toaruos/build-tools:1.99.x util/build-in-docker.sh
       - name: Upload Branch Image
         uses: actions/upload-artifact@v2
         with:
-          name: image
-          path: ./image.iso
-      - name: Draft Release notes
-        if: startsWith(github.ref, 'refs/tags/v')
-        run: bash util/generate-release-notes.sh > notes.md
-      - name: Create Release
-        if: startsWith(github.ref, 'refs/tags/v')
-        uses: actions/create-release@v1
-        id: create_release
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        with:
-          tag_name: ${{ github.ref }}
-          release_name: ToaruOS ${{ github.ref }}
-          body_path: ./notes.md
-          draft: true
-      - name: Upload Release Image
-        if: startsWith(github.ref, 'refs/tags/v')
-        uses: actions/upload-release-asset@v1
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        with:
-          upload_url: ${{ steps.create_release.outputs.upload_url }}
-          asset_path: ./image.iso
-          asset_name: image.iso
-          asset_content_type: application/x-iso9660-image
+          name: build
+          path: |
+            ramdisk.tar
+            misaka-kernel

+ 22 - 74
.gitignore

@@ -1,80 +1,28 @@
-*.so
-*.a
+*.aux
+*.idx
+*.ilg
+*.ind
+*.log
 *.o
-*.iso
-*.efi
+*.a
+*.out
+*.pdf
+*.so
+*.swp
+*.swn
+*.toc
+*.ko
+*.pcap
 .gdb_history
-/tags
-
-/.make/*
-/base/bin/*
-/base/lib/kuroko
-/base/src
-/_base
-/cdrom/extra
-/cdrom/kernel
-/cdrom/netinit
-/cdrom/mod/*
-/cdrom/ramdisk.img
-/cdrom/ramdisk.igz
-/cdrom/boot.sys
-/cdrom/fat.img
-/fatbase/extra
-/fatbase/kernel
-/fatbase/netinit
-/fatbase/mod/*
-/fatbase/ramdisk.img
-/fatbase/ramdisk.igz
-/fatbase/efi/boot/bootia32.efi
-/util/tarballs
+/ramdisk.tar
+/ramdisk.igz
+/misaka-kernel.64
+/misaka-kernel
+/kernel/symbols.S
 /util/build
 /util/local
-/util/devtable
-/util/tmp-gcc
-/util/kuroko
-/kernel/symbols.S
-/base/usr/python
+/util/cross
+/base/bin/*
 /base/usr/bin/*
 /base/usr/lib/*
-/base/usr/share/python-demos
-
-# Generic
-/base/usr/share/aclocal
-/base/usr/share/gtk-doc
-/base/usr/share/man
-/base/usr/share/info/
-/base/usr/share/doc/
-/base/usr/local
-
-# GMP
-/base/usr/include/gmp.h
-
-# MPFR
-/base/usr/include/mpf2mpfr.h
-/base/usr/include/mpfr.h
-
-# MPC
-/base/usr/include/mpc.h
-
-# zlib
-/base/usr/include/zconf.h
-/base/usr/include/zlib.h
-/util/ungz
-
-# binutils
-/base/usr/i686-pc-toaru
-
-# Freetype
-/base/usr/include/freetype2
-/base/usr/include/ft2build.h
-/base/usr/share/fonts
-
-# Cairo + Pixman
-/base/usr/include/cairo
-/base/usr/include/pixman-1
-
-# SDL
-/base/usr/include/SDL
-
-# Kuroko build files
-/base/usr/share/kuroko
+/.make/

+ 7 - 1
.gitmodules

@@ -1,3 +1,9 @@
+[submodule "util/binutils-gdb"]
+	path = util/binutils-gdb
+	url = ../../toaruos/binutils-gdb.git
+[submodule "util/gcc"]
+	path = util/gcc
+	url = ../../toaruos/gcc
 [submodule "kuroko"]
 	path = kuroko
-	url = git@github.com:kuroko-lang/kuroko
+	url = ../../kuroko-lang/kuroko

+ 181 - 383
Makefile

@@ -1,170 +1,190 @@
-ifeq ($(TOOLCHAIN),)
-  ifeq ($(shell util/check.sh),y)
-    export PATH := $(shell util/activate.sh)
-  else
-    FOO := $(shell util/prompt.sh)
-    ifeq ($(shell util/check.sh),y)
-      export PATH := $(shell util/activate.sh)
-    else
-      $(error "No toolchain, and you did not ask to build it.")
-    endif
-  endif
-endif
-
-# Prevents Make from removing intermediary files on failure
-.SECONDARY:
-
-# Disable built-in rules
-.SUFFIXES:
+TOOLCHAIN=util
+BASE=base
+export PATH := $(shell $(TOOLCHAIN)/activate.sh)
 
-all: image.iso
+include build/x86_64.mk
 
-TARGET_TRIPLET=i686-pc-toaru
+CC = ${TARGET}-gcc
+NM = ${TARGET}-nm
+CXX= ${TARGET}-g++
+AR = ${TARGET}-ar
+AS = ${TARGET}-as
+OC = ${TARGET}-objcopy
 
-# Userspace flags
+KERNEL_CFLAGS  = -ffreestanding -O2 -std=gnu11 -g -static
+KERNEL_CFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter
+KERNEL_CFLAGS += -pedantic -Wwrite-strings ${ARCH_KERNEL_CFLAGS}
 
-CC=$(TARGET_TRIPLET)-gcc
-AR=$(TARGET_TRIPLET)-ar
-AS=$(TARGET_TRIPLET)-as
-CFLAGS= -O2 -s -std=gnu99 -I. -Iapps -pipe -mmmx -msse -msse2 -fplan9-extensions -Wall -Wextra -Wno-unused-parameter
+# Defined constants for the kernel
+KERNEL_CFLAGS += -D_KERNEL_ -DKERNEL_ARCH=${ARCH}
+KERNEL_CFLAGS += -DKERNEL_GIT_TAG=`util/make-version`
 
-##
-# C library objects from libc/ C sources (and setjmp, which is assembly)
-LIBC_OBJS  = $(patsubst %.c,%.o,$(wildcard libc/*.c))
-LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c))
-LIBC_OBJS += libc/setjmp.o
-LC=base/lib/libc.so
-
-##
-#  APPS      = C sources from apps/
-#  APPS_X    = binaries
-#  APPS_Y    = generated makefiles for binaries
-#  APPS_SH   = shell scripts to copy to base/bin/ and mark executable
-#  APPS_SH_X = destinations for shell scripts
-APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c))
-APPS_X=$(foreach app,$(APPS),base/bin/$(app))
+KERNEL_OBJS =  $(patsubst %.c,%.o,$(wildcard kernel/*.c))
+KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c))
+KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/arch/${ARCH}/*.c))
+
+KERNEL_ASMOBJS  = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/arch/${ARCH}/*.S)))
+
+KERNEL_SOURCES  = $(wildcard kernel/*.c) $(wildcard kernel/*/*.c) $(wildcard kernel/${ARCH}/*/*.c)
+KERNEL_SOURCES += $(wildcard kernel/arch/${ARCH}/*.S)
+
+MODULES = $(patsubst %.c,%.ko,$(wildcard modules/*.c))
+
+# Configs you can override.
+SMP ?= 1
+RAM ?= 3G
+EXTRA_ARGS ?=
+
+EMU = qemu-system-x86_64
+EMU_ARGS  = -kernel misaka-kernel
+EMU_ARGS += -M q35
+EMU_ARGS += -m $(RAM)
+EMU_ARGS += -smp $(SMP)
+EMU_ARGS += -no-reboot
+#EMU_ARGS += -display none
+EMU_ARGS += -serial mon:stdio
+EMU_ARGS += -rtc base=localtime
+EMU_ARGS += -soundhw pcspk,ac97
+EMU_ARGS += -netdev user,id=u1,hostfwd=tcp::5555-:23 -device e1000e,netdev=u1 -object filter-dump,id=f1,netdev=u1,file=qemu-e1000e.pcap
+EMU_ARGS += -netdev user,id=u2,hostfwd=tcp::5580-:80 -device e1000,netdev=u2 -object filter-dump,id=f2,netdev=u2,file=qemu.pcap
+#EMU_ARGS += -hda toaruos-disk.img
+EMU_KVM  ?= -enable-kvm
+
+APPS=$(patsubst apps/%.c,%,$(wildcard apps/*.c)) $(patsubst apps/%.c++,%,$(wildcard apps/*.c++))
+APPS_X=$(foreach app,$(APPS),$(BASE)/bin/$(app))
 APPS_Y=$(foreach app,$(APPS),.make/$(app).mak)
 APPS_SH=$(patsubst apps/%.sh,%.sh,$(wildcard apps/*.sh))
-APPS_SH_X=$(foreach app,$(APPS_SH),base/bin/$(app))
+APPS_SH_X=$(foreach app,$(APPS_SH),$(BASE)/bin/$(app))
 APPS_KRK=$(patsubst apps/%.krk,%.krk,$(wildcard apps/*.krk))
-APPS_KRK_X=$(foreach app,$(APPS_KRK),base/bin/$(app))
+APPS_KRK_X=$(foreach app,$(APPS_KRK),$(BASE)/bin/$(app))
 
-##
-# LIBS   = C sources from lib/
-# LIBS_X = Shared libraries (.so)
-# LIBS_Y = Generated makefiles for libraries
 LIBS=$(patsubst lib/%.c,%,$(wildcard lib/*.c))
-LIBS_X=$(foreach lib,$(LIBS),base/lib/libtoaru_$(lib).so)
+LIBS_X=$(foreach lib,$(LIBS),$(BASE)/lib/libtoaru_$(lib).so)
 LIBS_Y=$(foreach lib,$(LIBS),.make/$(lib).lmak)
 
-SOURCE_FILES  = $(wildcard kernel/*.c kernel/*/*.c kernel/*/*/*.c modules/*.c)
-SOURCE_FILES += $(wildcard apps/*.c linker/*.c libc/*.c libc/*/*.c lib/*.c)
+KRK_MODS = $(patsubst kuroko/src/modules/module_%.c,$(BASE)/lib/kuroko/%.so,$(wildcard kuroko/src/modules/module_*.c))
+KRK_MODS_X = $(patsubst lib/kuroko/%.c,$(BASE)/lib/kuroko/%.so,$(wildcard lib/kuroko/*.c))
+KRK_MODS_Y = $(patsubst lib/kuroko/%.c,.make/%.kmak,$(wildcard lib/kuroko/*.c))
 
-tags: $(SOURCE_FILES) $(wildcard kuroko/src/*.c kuroko/src/*.h)
-	ctags -f tags $(SOURCE_FILES) $(wildcard kuroko/src/*.c kuroko/src/*.h)
+CFLAGS= -O2 -std=gnu11 -I. -Iapps -fplan9-extensions -Wall -Wextra -Wno-unused-parameter
 
-##
-# Files that must be present in the ramdisk (apps, libraries)
-RAMDISK_FILES= ${APPS_X} ${APPS_SH_X} ${APPS_KRK_X} ${LIBS_X} base/lib/ld.so base/lib/libm.so ${KUROKO_FILES}
+LIBC_OBJS  = $(patsubst %.c,%.o,$(wildcard libc/*.c))
+LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/*/*.c))
+LIBC_OBJS += $(patsubst %.c,%.o,$(wildcard libc/arch/${ARCH}/*.c))
 
-# Kernel / module flags
+GCC_SHARED = $(BASE)/usr/lib/libgcc_s.so.1 $(BASE)/usr/lib/libgcc_s.so
+LIBSTDCXX =  $(BASE)/usr/lib/libstdc++.so.6.0.28 $(BASE)/usr/lib/libstdc++.so.6 $(BASE)/usr/lib/libstdc++.so
 
-ifeq (,${USE_CLANG})
-KCC = $(TARGET_TRIPLET)-gcc
-LGCC = -lgcc
-EXTRALIB = 
-else
-KCC = clang --target=i686-elf -static -Ibase/usr/include -nostdinc -mno-sse
-LGCC = util/compiler-rt.o
-EXTRALIB = util/compiler-rt.o
-util/compiler-rt.o: util/compiler-rt.S
-	${KAS} ${ASFLAGS} $< -o $@
-endif
-KAS = $(TARGET_TRIPLET)-as
-KLD = $(TARGET_TRIPLET)-ld
-KNM = $(TARGET_TRIPLET)-nm
-
-KCFLAGS  = -O2 -std=c99
-KCFLAGS += -finline-functions -ffreestanding
-KCFLAGS += -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-format
-KCFLAGS += -pedantic -fno-omit-frame-pointer
-KCFLAGS += -D_KERNEL_
-KCFLAGS += -DKERNEL_GIT_TAG=$(shell util/make-version)
-KASFLAGS = --32
-
-##
-# Kernel objects from kernel/ C sources
-KERNEL_OBJS = $(patsubst %.c,%.o,$(wildcard kernel/*.c))
-KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*.c))
-KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c))
-
-##
-# Kernel objects from kernel/ assembly sources
-KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S)))
-HEADERS = $(wildcard base/usr/include/kernel/*.h base/usr/include/kernel/*/*.h)
-
-# Kernel
-
-fatbase/kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o ${EXTRALIB}
-	${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o $@ ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o ${LGCC}
-
-##
-# Symbol table for the kernel. Instead of relying on getting
-# the symbol table from our bootloader (eg. through ELF
-# headers provided via multiboot structure), we have a dedicated
-# object that build with all the symbols. This allows us to
-# build the kernel as a flat binary or load it with less-capable
-# multiboot loaders and still get symbols, which we need to
-# load kernel modules and link them properly.
-kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/generate_symbols.krk ${EXTRALIB} | util/kuroko
-	-rm -f kernel/symbols.o
-	${KCC} -T kernel/link.ld ${KCFLAGS} -nostdlib -o .toaruos-kernel ${KERNEL_ASMOBJS} ${KERNEL_OBJS} ${LGCC}
-	${KNM} .toaruos-kernel -g | util/kuroko util/generate_symbols.krk > kernel/symbols.S
-	${KAS} ${KASFLAGS} kernel/symbols.S -o $@
-	-rm -f .toaruos-kernel
+CRTS  = $(BASE)/lib/crt0.o $(BASE)/lib/crti.o $(BASE)/lib/crtn.o
 
-##
-# version.o should be rebuilt whenever the kernel changes
-# in order to get fresh git commit hash information.
-kernel/sys/version.o: kernel/*/*.c kernel/*.c
+LC = $(BASE)/lib/libc.so $(GCC_SHARED) $(LIBSTDCXX)
 
-kernel/%.o: kernel/%.S
-	${KAS} ${ASFLAGS} $< -o $@
+.PHONY: all system clean run shell
 
-kernel/%.o: kernel/%.c ${HEADERS}
-	${KCC} ${KCFLAGS} -nostdlib -g -c -o $@ $<
+all: system
+system: misaka-kernel $(MODULES) ramdisk.igz
+
+%.ko: %.c
+	${CC} -c ${KERNEL_CFLAGS} -o $@ $<
+
+ramdisk.igz: $(wildcard $(BASE)/* $(BASE)/*/* $(BASE)/*/*/*) $(APPS_X) $(LIBS_X) $(KRK_MODS_X) $(BASE)/bin/kuroko $(BASE)/lib/ld.so $(APPS_KRK_X) $(KRK_MODS)
+	python3 util/createramdisk.py
+
+KRK_SRC = $(sort $(wildcard kuroko/src/*.c))
+$(BASE)/bin/kuroko: $(KRK_SRC) $(CRTS) | $(LC)
+	$(CC) -O2 -g -o $@ -Wl,--export-dynamic -Ikuroko/src $(KRK_SRC) kuroko/src/vendor/rline.c
+
+$(BASE)/lib/kuroko/%.so: kuroko/src/modules/module_%.c| dirs $(LC)
+	$(CC) -O2 -shared -fPIC -Ikuroko/src -o $@ $<
 
-# Modules
+$(BASE)/lib/libkuroko.so: $(KRK_SRC) | $(LC)
+	$(CC) -O2 -shared -fPIC -Ikuroko/src -o $@ $(filter-out kuroko/src/kuroko.c,$(KRK_SRC))
 
-fatbase/mod:
-	@mkdir -p $@
+$(BASE)/lib/ld.so: linker/linker.c $(BASE)/lib/libc.a | dirs $(LC)
+	$(CC) -g -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $<
 
-##
-# Modules need to be installed on the boot image
-MODULES = $(patsubst modules/%.c,fatbase/mod/%.ko,$(wildcard modules/*.c))
+run: system
+	${EMU} ${EMU_ARGS} ${EMU_KVM} -append "root=/dev/ram0 start=live-session migrate $(EXTRA_ARGS)" -initrd ramdisk.igz
 
-fatbase/mod/%.ko: modules/%.c ${HEADERS} | fatbase/mod
-	${KCC} -nostdlib ${KCFLAGS} -c -o $@ $<
+shell: system
+	${EMU} -m $(RAM) ${EMU_KVM} -kernel misaka-kernel -append "root=/dev/ram0 start=--headless migrate" -initrd ramdisk.igz \
+		-nographic -no-reboot -audiodev none,id=id -serial null -serial mon:stdio \
+		-fw_cfg name=opt/org.toaruos.gettyargs,string="-a local /dev/ttyS1" \
+		-fw_cfg name=opt/org.toaruos.term,string=${TERM}
 
-modules: ${MODULES}
+misaka-kernel: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o
+	${CC} -g -T kernel/arch/${ARCH}/link.ld ${KERNEL_CFLAGS} -o $@.64 ${KERNEL_ASMOBJS} ${KERNEL_OBJS} kernel/symbols.o -lgcc
+	${OC} -I elf64-x86-64 -O elf32-i386 $@.64 $@
 
-# Root Filesystem
+kernel/sys/version.o: ${KERNEL_SOURCES}
 
-base/dev:
+kernel/symbols.o: ${KERNEL_ASMOBJS} ${KERNEL_OBJS} util/gensym.krk
+	-rm -f kernel/symbols.o
+	${CC} -T kernel/arch/${ARCH}/link.ld ${KERNEL_CFLAGS} -o misaka-kernel.64 ${KERNEL_ASMOBJS} ${KERNEL_OBJS} -lgcc
+	${NM} misaka-kernel.64 -g | kuroko util/gensym.krk > kernel/symbols.S
+	${CC} -c kernel/symbols.S -o $@
+
+kernel/%.o: kernel/%.S
+	echo ${PATH}
+	${CC} -c $< -o $@
+
+HEADERS = $(wildcard base/usr/include/kernel/*.h)
+
+kernel/%.o: kernel/%.c ${HEADERS}
+	${CC} ${KERNEL_CFLAGS} -nostdlib -g -Iinclude -c -o $@ $<
+
+clean:
+	-rm -f ${KERNEL_ASMOBJS}
+	-rm -f ${KERNEL_OBJS}
+	-rm -f kernel/symbols.o misaka-kernel misaka-kernel.64
+	-rm -f ramdisk.tar ramdisk.igz 
+	-rm -f $(APPS_Y) $(LIBS_Y) $(KRK_MODS_Y) $(KRK_MODS)
+	-rm -f $(APPS_X) $(LIBS_X) $(KRK_MODS_X) $(APPS_KRK_X) $(APPS_SH_X)
+	-rm -f $(BASE)/lib/crt0.o $(BASE)/lib/crti.o $(BASE)/lib/crtn.o
+	-rm -f $(BASE)/lib/libc.so $(BASE)/lib/libc.a
+	-rm -f $(LIBC_OBJS) $(BASE)/lib/ld.so $(BASE)/lib/libkuroko.so $(BASE)/lib/libm.so
+	-rm -f $(BASE)/bin/kuroko
+	-rm -f $(GCC_SHARED) $(LIBSTDCXX)
+
+libc/%.o: libc/%.c base/usr/include/syscall.h 
+	$(CC) -O2 -std=gnu11 -Wall -Wextra -Wno-unused-parameter -fPIC -c -o $@ $<
+
+.PHONY: libc
+libc: $(BASE)/lib/libc.a $(BASE)/lib/libc.so
+
+$(BASE)/lib/libc.a: ${LIBC_OBJS} $(CRTS)
+	$(AR) cr $@ $(LIBC_OBJS)
+
+$(BASE)/lib/libc.so: ${LIBC_OBJS} | $(CRTS)
+	${CC} -nodefaultlibs -shared -fPIC -o $@ $^
+
+$(BASE)/lib/crt%.o: libc/arch/${ARCH}/crt%.S
+	${AS} -o $@ $<
+
+$(BASE)/usr/lib/%: util/local/${TARGET}/lib/% | dirs
+	cp -a $< $@
+	-strip $@
+
+$(BASE)/lib/libm.so: util/libm.c
+	$(CC) -shared -nostdlib -fPIC -o $@ $<
+
+$(BASE)/dev:
 	mkdir -p $@
-base/tmp:
+$(BASE)/tmp:
 	mkdir -p $@
-base/proc:
+$(BASE)/proc:
 	mkdir -p $@
-base/bin:
+$(BASE)/bin:
 	mkdir -p $@
-base/lib:
+$(BASE)/lib:
 	mkdir -p $@
-base/cdrom:
+$(BASE)/cdrom:
 	mkdir -p $@
-base/var:
+$(BASE)/var:
 	mkdir -p $@
-base/lib/kuroko:
+$(BASE)/lib/kuroko:
+	mkdir -p $@
+$(BASE)/usr/lib:
 	mkdir -p $@
 fatbase/efi/boot:
 	mkdir -p $@
@@ -172,271 +192,49 @@ cdrom:
 	mkdir -p $@
 .make:
 	mkdir -p .make
-dirs: base/dev base/tmp base/proc base/bin base/lib base/cdrom base/lib/kuroko cdrom base/var fatbase/efi/boot .make
-
-# C Library
-
-crts: base/lib/crt0.o base/lib/crti.o base/lib/crtn.o | dirs
-
-base/lib/crt%.o: libc/crt%.S
-	$(AS) -o $@ $<
-
-libc/setjmp.o: libc/setjmp.S
-	$(AS) -o $@ $<
-
-libc/%.o: libc/%.c
-	$(CC) $(CFLAGS) -fPIC -c -o $@ $<
-
-base/lib/libc.a: ${LIBC_OBJS} | dirs crts
-	$(AR) cr $@ $^
-
-base/lib/libc.so: ${LIBC_OBJS} | dirs crts
-	$(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc
-
-base/lib/libm.so: util/lm.c | dirs crts
-	$(CC) -nodefaultlibs -o $@ $(CFLAGS) -shared -fPIC $^ -lgcc
-
-KUROKO_OBJS=$(patsubst %.c, %.o, $(filter-out kuroko/src/kuroko.c,$(sort $(wildcard kuroko/src/*.c))))
-kuroko/%.o: kuroko/%.c
-	$(CC) $(CFLAGS) -fPIC -c -o $@ $^
-
-KUROKO_CMODS=$(patsubst kuroko/src/modules/module_%.c,%,$(wildcard kuroko/src/modules/module_*.c)) $(patsubst lib/kuroko/%.c,%,$(wildcard lib/kuroko/*.c))
-KUROKO_CMODS_X=$(foreach lib,$(KUROKO_CMODS),base/lib/kuroko/$(lib).so)
-KUROKO_CMODS_Y=$(foreach lib,$(KUROKO_CMODS),.make/$(lib).kmak)
-KUROKO_KRK_MODS=$(patsubst kuroko/modules/%.krk,base/lib/kuroko/%.krk,$(wildcard kuroko/modules/*.krk kuroko/modules/*/*.krk))
-
-KUROKO_FILES=$(KUROKO_CMODS_X) $(KUROKO_KRK_MODS) base/lib/libkuroko.so
-
-base/lib/kuroko/%.krk: kuroko/modules/%.krk
-	@mkdir -p `dirname $@`
-	cp $< $@
-
-MINIMAL_KUROKO = $(filter-out kuroko/src/modules/module_%,$(sort $(wildcard kuroko/src/*.c)))
-util/kuroko: $(MINIMAL_KUROKO)
-	gcc -Ikuroko/src -DNO_RLINE -DSTATIC_ONLY -DKRK_DISABLE_THREADS -o $@ $^
-
-.make/%.kmak: kuroko/src/modules/module_%.c util/auto-dep.krk | dirs util/kuroko
-	util/kuroko util/auto-dep.krk --makekurokomod $< > $@
-
-.make/%.kmak: lib/kuroko/%.c util/auto-dep.krk | dirs util/kuroko
-	util/kuroko util/auto-dep.krk --makekurokomod $< > $@
-
-ifeq (,$(findstring clean,$(MAKECMDGOALS)))
--include ${KUROKO_CMODS_Y}
-endif
-
-base/lib/libkuroko.so: $(KUROKO_OBJS)  | dirs crts ${LC}
-	$(CC) $(CFLAGS) -shared -fPIC -o $@ $^ -lgcc
-
-# Userspace Linker/Loader
-
-base/lib/ld.so: linker/linker.c base/lib/libc.a | dirs
-	$(CC) -static -Wl,-static $(CFLAGS) -o $@ -Os -T linker/link.ld $<
-
-# Shared Libraries
-.make/%.lmak: lib/%.c util/auto-dep.krk | dirs crts util/kuroko
-	util/kuroko util/auto-dep.krk --makelib $< > $@
+dirs: $(BASE)/dev $(BASE)/tmp $(BASE)/proc $(BASE)/bin $(BASE)/lib $(BASE)/cdrom $(BASE)/usr/lib $(BASE)/lib/kuroko cdrom $(BASE)/var fatbase/efi/boot .make
 
 ifeq (,$(findstring clean,$(MAKECMDGOALS)))
+-include ${APPS_Y}
 -include ${LIBS_Y}
+-include ${KRK_MODS_Y}
 endif
 
-# netinit needs to go in the CD/FAT root, so it gets built specially
-fatbase/netinit: util/netinit.c base/lib/libc.a | dirs
-	$(CC) $(CFLAGS) -o $@ $<
+.make/%.lmak: lib/%.c util/auto-dep.krk | dirs $(CRTS)
+	kuroko util/auto-dep.krk --makelib $< > $@
 
-# Userspace applications
+.make/%.mak: apps/%.c util/auto-dep.krk | dirs $(CRTS)
+	kuroko util/auto-dep.krk --make $< > $@
 
-.make/%.mak: apps/%.c util/auto-dep.krk | dirs crts util/kuroko
-	util/kuroko util/auto-dep.krk --make $< > $@
+.make/%.mak: apps/%.c++ util/auto-dep.krk | dirs $(CRTS)
+	kuroko util/auto-dep.krk --make $< > $@
 
-ifeq (,$(findstring clean,$(MAKECMDGOALS)))
--include ${APPS_Y}
-endif
+.make/%.kmak: lib/kuroko/%.c util/auto-dep.krk | dirs
+	kuroko util/auto-dep.krk --makekurokomod $< > $@
 
-base/bin/%.sh: apps/%.sh
+$(BASE)/bin/%.sh: apps/%.sh
 	cp $< $@
 	chmod +x $@
 
-base/bin/%.krk: apps/%.krk
+$(BASE)/bin/%.krk: apps/%.krk
 	cp $< $@
 	chmod +x $@
 
-# Ramdisk
-fatbase/ramdisk.igz: ${RAMDISK_FILES} $(shell find base) Makefile util/createramdisk.py | dirs
-	python3 util/createramdisk.py
-	gzip -c fatbase/ramdisk.img > fatbase/ramdisk.igz
-	rm fatbase/ramdisk.img
+.PHONY: libs
+libs: $(LIBS_X)
 
-# CD image
-
-ifeq (,$(wildcard /usr/lib32/crt0-efi-ia32.o))
-$(error Missing GNU-EFI.)
-endif
-
-EFI_XORRISO=-eltorito-alt-boot -e fat.img -no-emul-boot -isohybrid-gpt-basdat
-EFI_BOOT=cdrom/fat.img
-EFI_UPDATE=util/update-extents.py
-
-image.iso: ${EFI_BOOT} cdrom/boot.sys fatbase/netinit ${MODULES} util/update-extents.py
-	xorriso -as mkisofs -R -J -c bootcat \
-	  -b boot.sys -no-emul-boot -boot-load-size full \
-	  ${EFI_XORRISO} \
-	  -o image.iso cdrom
-	${EFI_UPDATE}
-
-# Boot loader
-
-##
-# FAT EFI payload
-# This is the filesystem the EFI loaders see, so it must contain
-# the kernel, modules, and ramdisk, plus anything else we want
-# available to the bootloader (eg., netinit).
-cdrom/fat.img: fatbase/ramdisk.igz ${MODULES} fatbase/kernel fatbase/netinit fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi util/mkdisk.sh | dirs
-	util/mkdisk.sh $@ fatbase
-
-##
-# For EFI, we build two laoders: ia32 and x64
-# We build them as ELF shared objects and the use objcopy to convert
-# them to PE executables / DLLs (as expected by EFI).
-EFI_CFLAGS=-fno-stack-protector -fpic -DEFI_PLATFORM -ffreestanding -fshort-wchar -I /usr/include/efi -mno-red-zone
-EFI_SECTIONS=-j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc
-
-# ia32
-boot/efi.so: boot/cstuff.c boot/*.h
-	$(CC) ${EFI_CFLAGS} -I /usr/include/efi/ia32 -c -o boot/efi.o $<
-	$(LD) boot/efi.o /usr/lib32/crt0-efi-ia32.o -nostdlib -znocombreloc -T /usr/lib32/elf_ia32_efi.lds -shared -Bsymbolic -L /usr/lib32 -lefi -lgnuefi -o boot/efi.so
-
-fatbase/efi/boot/bootia32.efi: boot/efi.so
-	objcopy ${EFI_SECTIONS} --target=efi-app-ia32 $< $@
-
-# x64
-boot/efi64.so: boot/cstuff.c boot/*.h
-	gcc ${EFI_CFLAGS} -I /usr/include/efi/x86_64 -DEFI_FUNCTION_WRAPPER -c -o boot/efi64.o $<
-	$(LD) boot/efi64.o /usr/lib/crt0-efi-x86_64.o -nostdlib -znocombreloc -T /usr/lib/elf_x86_64_efi.lds -shared -Bsymbolic -L /usr/lib -lefi -lgnuefi -o boot/efi64.so
-
-fatbase/efi/boot/bootx64.efi: boot/efi64.so
-	objcopy ${EFI_SECTIONS} --target=efi-app-x86_64 $< $@
-
-# BIOS loader
-cdrom/boot.sys: boot/boot.o boot/cstuff.o boot/link.ld | dirs
-	${KLD} -T boot/link.ld -o $@ boot/boot.o boot/cstuff.o
-
-boot/cstuff.o: boot/cstuff.c boot/*.h
-	${CC} -c -Os -fno-strict-aliasing -finline-functions -ffreestanding -o $@ $<
-
-boot/boot.o: boot/boot.S
-	${AS} -o $@ $<
-
-.PHONY: clean
-clean:
-	rm -f base/lib/*.so
-	rm -f base/lib/libc.a
-	rm -f ${APPS_X} ${APPS_SH_X}
-	rm -f libc/*.o libc/*/*.o
-	rm -f image.iso
-	rm -f fatbase/ramdisk.img fatbase/ramdisk.igz
-	rm -f cdrom/boot.sys
-	rm -f boot/*.o
-	rm -f boot/*.efi
-	rm -f boot/*.so
-	rm -f cdrom/fat.img cdrom/kernel cdrom/mod/* cdrom/ramdisk.img
-	rm -f fatbase/kernel fatbase/efi/boot/bootia32.efi fatbase/efi/boot/bootx64.efi
-	rm -f cdrom/netinit fatbase/netinit
-	rm -f ${KERNEL_OBJS} ${KERNEL_ASMOBJS} kernel/symbols.o kernel/symbols.S
-	rm -f base/lib/crt*.o
-	rm -f ${MODULES}
-	rm -f ${APPS_Y} ${LIBS_Y} ${EXT_LIBS_Y}
-	rm -f ${KUROKO_FILES} ${KUROKO_CMODS_Y} ${KUROKO_CMODS_X}
-	rm -f kuroko/src/*.o
-	rm -f util/kuroko
-
-ifneq (,$(findstring Microsoft,$(shell uname -r)))
-  QEMU_ARGS=-serial mon:stdio -m 1G -rtc base=localtime -vnc :0
-else
-  ifeq (,${NO_KVM})
-    KVM=-enable-kvm
-  else
-    KVM=
-  endif
-  QEMU_ARGS=-serial mon:stdio -m 1G -soundhw ac97,pcspk ${KVM} -rtc base=localtime ${QEMU_EXTRA}
-endif
-
-
-.PHONY: run
-run: image.iso
-	qemu-system-i386 -cdrom $< ${QEMU_ARGS}
-
-.PHONY: fast
-fast: image.iso
-	qemu-system-i386 -cdrom $< ${QEMU_ARGS} \
-	  -fw_cfg name=opt/org.toaruos.bootmode,string=normal
-
-.PHONY: headless
-headless: image.iso
-	@qemu-system-i386 -cdrom $< -m 1G ${KVM} -rtc base=localtime ${QEMU_EXTRA} \
-	  -serial null -serial mon:stdio \
-	  -nographic -no-reboot -audiodev none,id=id \
-	  -fw_cfg name=opt/org.toaruos.bootmode,string=headless \
-	  -fw_cfg name=opt/org.toaruos.gettyargs,string="-a local /dev/ttyS1"
-
-.PHONY: shell
-shell: image.iso
-	@qemu-system-i386 -cdrom $< ${QEMU_ARGS} \
-	  -nographic -no-reboot \
-	  -fw_cfg name=opt/org.toaruos.bootmode,string=headless \
-	  -fw_cfg name=opt/org.toaruos.forceuser,string=local \
-	  -fw_cfg name=opt/org.toaruos.term,string=${TERM} </dev/null >/dev/null & \
-	  stty raw -echo && nc -l 127.0.0.1 8090 && stty sane && wait
-
-.PHONY: efi64
-efi64: image.iso
-	qemu-system-x86_64 -cdrom $< ${QEMU_ARGS} \
-	  -bios /usr/share/qemu/OVMF.fd
-
-
-VMNAME=ToaruOS CD
-
-define virtualbox-runner =
-.PHONY: $1
-$1: image.iso
-	-VBoxManage unregistervm "$(VMNAME)" --delete
-	VBoxManage createvm --name "$(VMNAME)" --ostype $2 --register
-	VBoxManage modifyvm "$(VMNAME)" --memory 1024 --vram 32 --audio pulse --audiocontroller ac97 --bioslogodisplaytime 1 --bioslogofadeout off --bioslogofadein off --biosbootmenu disabled $3
-	VBoxManage storagectl "$(VMNAME)" --add ide --name "IDE"
-	VBoxManage storageattach "$(VMNAME)" --storagectl "IDE" --port 0 --device 0 --medium $$(shell pwd)/image.iso --type dvddrive
-	VBoxManage setextradata "$(VMNAME)" GUI/DefaultCloseAction PowerOff
-	VBoxManage startvm "$(VMNAME)" --type separate
-endef
-
-$(eval $(call virtualbox-runner,virtualbox,"Other",))
-$(eval $(call virtualbox-runner,virtualbox-efi,"Other",--firmware efi))
-$(eval $(call virtualbox-runner,virtualbox-efi64,"Other_64",--firmware efi))
-
-##
-# Optional Extensions
-#
-# These optional extension libraries require third-party components to build,
-# but allow the native applications to make use of functionality such as
-# TrueType fonts or PNG images. You must have the necessary elements to build
-# these already installed into your sysroot for this to work.
-EXT_LIBS=$(patsubst ext/%.c,%,$(wildcard ext/*.c))
-EXT_LIBS_X=$(foreach lib,$(EXT_LIBS),base/lib/libtoaru_$(lib).so)
-EXT_LIBS_Y=$(foreach lib,$(EXT_LIBS),.make/$(lib).elmak)
-
-.make/%.elmak: ext/%.c util/auto-dep.krk | dirs util/kuroko
-	util/kuroko util/auto-dep.krk --makelib $< > $@
-
-ifeq (,$(findstring clean,$(MAKECMDGOALS)))
--include ${EXT_LIBS_Y}
-endif
+.PHONY: apps
+apps: $(APPS_X)
 
-# Freetype: Terminal text rendering backend
-ext-freetype: base/lib/libtoaru_ext_freetype_fonts.so
+.PHONY: libstdcxx
+libstdcxx: $(LIBSTDCXX)
 
-# Cairo: Compositor rendering backend
-ext-cairo: base/lib/libtoaru_ext_cairo_renderer.so
+util/local/${TARGET}/lib/libstdc++.so.6.0.28: | $(BASE)/lib/libm.so
+	cd util/build/gcc && make all-target-libstdc++-v3 && make install-target-libstdc++-v3
 
-# Other extra stuff
-util/ungz: util/ungz.c
-	$(CC) -o $@ $< -lz
+SOURCE_FILES  = $(wildcard kernel/*.c kernel/*/*.c kernel/*/*/*.c kernel/*/*/*/*.c)
+SOURCE_FILES += $(wildcard apps/*.c linker/*.c libc/*.c libc/*/*.c lib/*.c lib/kuroko/*.c)
+SOURCE_FILES += $(wildcard kuroko/src/*.c kuroko/src/*.h kuroko/src/*/*.c kuroko/src/*/*.h)
+SOURCE_FILES += $(wildcard $(BASE)/usr/include/*.h $(BASE)/usr/include/*/*.h $(BASE)/usr/include/*/*/*.h)
+tags: $(SOURCE_FILES)
+	ctags -f tags $(SOURCE_FILES)

+ 1 - 1
apps/about.c

@@ -171,7 +171,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win) {
 							win->focused = wf->focused;
 							redraw();

+ 41 - 41
apps/compositor.c

@@ -46,7 +46,7 @@
 #include <toaru/list.h>
 #include <toaru/spinlock.h>
 
-//#define _DEBUG_YUTANI
+#define _DEBUG_YUTANI
 #ifdef _DEBUG_YUTANI
 #include <toaru/trace.h>
 #define TRACE_APP_NAME "yutani"
@@ -175,7 +175,7 @@ static int next_wid(void) {
 	return _next++;
 }
 
-uint32_t yutani_current_time(yutani_globals_t * yg) {
+uint64_t yutani_current_time(yutani_globals_t * yg) {
 	struct timeval t;
 	gettimeofday(&t, NULL);
 
@@ -187,13 +187,13 @@ uint32_t yutani_current_time(yutani_globals_t * yg) {
 		usec_diff = (1000000 + t.tv_usec) - yg->start_subtime;
 	}
 
-	return (uint32_t)(sec_diff * 1000 + usec_diff / 1000);
+	return (uint64_t)(sec_diff * 1000 + usec_diff / 1000);
 }
 
-uint32_t yutani_time_since(yutani_globals_t * yg, uint32_t start_time) {
+uint64_t yutani_time_since(yutani_globals_t * yg, uint64_t start_time) {
 
-	uint32_t now = yutani_current_time(yg);
-	uint32_t diff = now - start_time; /* Milliseconds */
+	uint64_t now = yutani_current_time(yg);
+	uint64_t diff = now - start_time; /* Milliseconds */
 
 	return diff;
 }
@@ -390,13 +390,13 @@ static int yutani_pick_animation(uint32_t flags, int direction) {
  *
  * Initializes a window of the particular size for a given client.
  */
-static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int width, int height, uint32_t owner, uint32_t flags) {
+static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int width, int height, uintptr_t owner, uint32_t flags) {
 	yutani_server_window_t * win = malloc(sizeof(yutani_server_window_t));
 
 	win->wid = next_wid();
 	win->owner = owner;
 	list_insert(yg->windows, win);
-	hashmap_set(yg->wids_to_windows, (void*)win->wid, win);
+	hashmap_set(yg->wids_to_windows, (void*)(uintptr_t)win->wid, win);
 
 	list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)owner);
 	list_insert(client_list, win);
@@ -733,7 +733,7 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi
 				case YUTANI_EFFECT_FADE_OUT:
 					{
 						frame = yutani_animation_lengths[window->anim_mode] - frame;
-					}
+					} /* fallthrough */
 				case YUTANI_EFFECT_SQUEEZE_IN:
 				case YUTANI_EFFECT_FADE_IN:
 					{
@@ -1018,7 +1018,7 @@ static void redraw_windows(yutani_globals_t * yg) {
 
 		if ((!yg->bottom_z || yg->bottom_z->anim_mode) && renderer_blit_screen) {
 			/* TODO: Need to clear with Cairo backend */
-			draw_fill(yg->backend_ctx, rgb(110,110,110));
+			draw_fill(yg->backend_ctx, rgb(5,5,5));
 		}
 
 		if (renderer_set_clip) renderer_set_clip(yg);
@@ -1252,7 +1252,7 @@ static void window_mark_for_close(yutani_globals_t * yg, yutani_server_window_t
  * Remove a window from its owner's child set.
  */
 static void window_remove_from_client(yutani_globals_t * yg, yutani_server_window_t * w) {
-	list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)w->owner);
+	list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)(uintptr_t)w->owner);
 	if (client_list) {
 		node_t * n = list_find(client_list, w);
 		if (n) {
@@ -1267,7 +1267,7 @@ static void window_remove_from_client(yutani_globals_t * yg, yutani_server_windo
  */
 static void window_actually_close(yutani_globals_t * yg, yutani_server_window_t * w) {
 	/* Remove from the wid -> window mapping */
-	hashmap_remove(yg->wids_to_windows, (void *)w->wid);
+	hashmap_remove(yg->wids_to_windows, (void *)(uintptr_t)w->wid);
 
 	/* Remove from the general list of windows. */
 	list_remove(yg->windows, list_index_of(yg->windows, w));
@@ -1319,7 +1319,7 @@ static uint32_t ad_flags(yutani_globals_t * yg, yutani_server_window_t * win) {
 /**
  * Send a result for a window query.
  */
-static void yutani_query_result(yutani_globals_t * yg, uint32_t dest, yutani_server_window_t * win) {
+static void yutani_query_result(yutani_globals_t * yg, uintptr_t dest, yutani_server_window_t * win) {
 	if (win && win->client_length) {
 		yutani_msg_buildx_window_advertise_alloc(response, win->client_length);
 		yutani_msg_buildx_window_advertise(response, win->wid, ad_flags(yg, win), win->client_offsets, win->client_length, win->client_strings);
@@ -1335,7 +1335,7 @@ static void notify_subscribers(yutani_globals_t * yg) {
 	yutani_msg_buildx_notify(response);
 	list_t * remove = NULL;
 	foreach(node, yg->window_subscribers) {
-		uint32_t subscriber = (uint32_t)node->value;
+		uintptr_t subscriber = (uintptr_t)node->value;
 		if (!hashmap_has(yg->clients_to_windows, (void *)subscriber)) {
 			if (!remove) {
 				remove = list_create();
@@ -1601,8 +1601,8 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event
 	 * External bindings registered by clients.
 	 */
 	uint32_t key_code = ((ke->event.modifiers << 24) | (ke->event.keycode));
-	if (hashmap_has(yg->key_binds, (void*)key_code)) {
-		struct key_bind * bind = hashmap_get(yg->key_binds, (void*)key_code);
+	if (hashmap_has(yg->key_binds, (void*)(uintptr_t)key_code)) {
+		struct key_bind * bind = hashmap_get(yg->key_binds, (void*)(uintptr_t)key_code);
 
 		yutani_msg_buildx_key_event_alloc(response);
 		yutani_msg_buildx_key_event(response,focused ? focused->wid : UINT32_MAX, &ke->event, &ke->state);
@@ -1630,9 +1630,9 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event
  * req - bind message
  * owner - client to assign the binding to
  */
-static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req, unsigned int owner) {
+static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req, uintptr_t owner) {
 	uint32_t key_code = (((uint8_t)req->modifiers << 24) | ((uint32_t)req->key & 0xFFFFFF));
-	struct key_bind * bind = hashmap_get(yg->key_binds, (void*)key_code);
+	struct key_bind * bind = hashmap_get(yg->key_binds, (void*)(uintptr_t)key_code);
 
 	if (!bind) {
 		bind = malloc(sizeof(struct key_bind));
@@ -1640,7 +1640,7 @@ static void add_key_bind(yutani_globals_t * yg, struct yutani_msg_key_bind * req
 		bind->owner = owner;
 		bind->response = req->response;
 
-		hashmap_set(yg->key_binds, (void*)key_code, bind);
+		hashmap_set(yg->key_binds, (void*)(uintptr_t)key_code, bind);
 	} else {
 		bind->owner = owner;
 		bind->response = req->response;
@@ -2103,7 +2103,7 @@ int main(int argc, char * argv[]) {
 	yg->width = yg->backend_ctx->width;
 	yg->height = yg->backend_ctx->height;
 
-	draw_fill(yg->backend_ctx, rgb(110,110,110));
+	draw_fill(yg->backend_ctx, rgb(5,5,5));
 	flip(yg->backend_ctx);
 
 	yg->backend_framebuffer = yg->backend_ctx->backbuffer;
@@ -2388,10 +2388,10 @@ int main(int argc, char * argv[]) {
 		switch(m->type) {
 			case YUTANI_MSG_HELLO:
 				{
-					TRACE("And hello to you, %08x!", p->source);
+					TRACE("And hello to you, %p!", p->source);
 					list_t * client_list = hashmap_get(yg->clients_to_windows, (void *)p->source);
 					if (!client_list) {
-						TRACE("Client is new: %x", p->source);
+						TRACE("Client is new: %p", p->source);
 						client_list = list_create();
 						hashmap_set(yg->clients_to_windows, (void *)p->source, client_list);
 					}
@@ -2404,7 +2404,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_NEW_FLAGS:
 				{
 					struct yutani_msg_window_new_flags * wn = (void *)m->data;
-					TRACE("Client %08x requested a new window (%dx%d).", p->source, wn->width, wn->height);
+					TRACE("Client %p requested a new window (%dx%d).", p->source, wn->width, wn->height);
 					yutani_server_window_t * w = server_window_create(yg, wn->width, wn->height, p->source, m->type != YUTANI_MSG_WINDOW_NEW ? wn->flags : 0);
 					yutani_msg_buildx_window_init_alloc(response);
 					yutani_msg_buildx_window_init(response,w->wid, w->width, w->height, w->bufid);
@@ -2420,7 +2420,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_FLIP:
 				{
 					struct yutani_msg_flip * wf = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wf->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wf->wid);
 					if (w) {
 						mark_window(yg, w);
 					}
@@ -2429,7 +2429,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_FLIP_REGION:
 				{
 					struct yutani_msg_flip_region * wf = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wf->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wf->wid);
 					if (w) {
 						mark_window_relative(yg, w, wf->x, wf->y, wf->width, wf->height);
 					}
@@ -2457,7 +2457,7 @@ int main(int argc, char * argv[]) {
 						TRACE("Refusing to move window to these coordinates.");
 						break;
 					}
-					yutani_server_window_t * win = hashmap_get(yg->wids_to_windows, (void*)wm->wid);
+					yutani_server_window_t * win = hashmap_get(yg->wids_to_windows, (void*)(uintptr_t)wm->wid);
 					if (win) {
 						window_move(yg, win, wm->x, wm->y);
 					} else {
@@ -2468,7 +2468,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_CLOSE:
 				{
 					struct yutani_msg_window_close * wc = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wc->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wc->wid);
 					if (w) {
 						window_mark_for_close(yg, w);
 						window_remove_from_client(yg, w);
@@ -2478,7 +2478,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_STACK:
 				{
 					struct yutani_msg_window_stack * ws = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)ws->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)ws->wid);
 					if (w) {
 						reorder_window(yg, w, ws->z);
 					}
@@ -2487,7 +2487,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_RESIZE_REQUEST:
 				{
 					struct yutani_msg_window_resize * wr = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid);
 					if (w) {
 						yutani_msg_buildx_window_resize_alloc(response);
 						yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled);
@@ -2498,7 +2498,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_RESIZE_OFFER:
 				{
 					struct yutani_msg_window_resize * wr = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid);
 					if (w) {
 						yutani_msg_buildx_window_resize_alloc(response);
 						yutani_msg_buildx_window_resize(response,YUTANI_MSG_RESIZE_OFFER, w->wid, wr->width, wr->height, 0, w->tiled);
@@ -2509,7 +2509,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_RESIZE_ACCEPT:
 				{
 					struct yutani_msg_window_resize * wr = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid);
 					if (w) {
 						uint32_t newbufid = server_window_resize(yg, w, wr->width, wr->height);
 						yutani_msg_buildx_window_resize_alloc(response);
@@ -2521,7 +2521,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_RESIZE_DONE:
 				{
 					struct yutani_msg_window_resize * wr = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wr->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wr->wid);
 					if (w) {
 						server_window_resize_finish(yg, w, wr->width, wr->height);
 					}
@@ -2542,7 +2542,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_SUBSCRIBE:
 				{
 					foreach(node, yg->window_subscribers) {
-						if ((uint32_t)node->value == p->source) {
+						if ((uintptr_t)node->value == p->source) {
 							break;
 						}
 					}
@@ -2560,7 +2560,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_ADVERTISE:
 				{
 					struct yutani_msg_window_advertise * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						if (w->client_strings) free(w->client_strings);
 
@@ -2587,7 +2587,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_FOCUS:
 				{
 					struct yutani_msg_window_focus * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						set_focused_window(yg, w);
 					}
@@ -2602,7 +2602,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_DRAG_START:
 				{
 					struct yutani_msg_window_drag_start * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						/* Start dragging */
 						mouse_start_drag(yg, w);
@@ -2612,7 +2612,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_UPDATE_SHAPE:
 				{
 					struct yutani_msg_window_update_shape * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						/* Set shape parameter */
 						server_window_update_shape(yg, w, wa->set_shape);
@@ -2622,7 +2622,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_WARP_MOUSE:
 				{
 					struct yutani_msg_window_warp_mouse * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						if (yg->focused_window == w) {
 							int32_t x, y;
@@ -2643,7 +2643,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_SHOW_MOUSE:
 				{
 					struct yutani_msg_window_show_mouse * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						if (wa->show_mouse == -1) {
 							w->show_mouse = w->default_mouse;
@@ -2662,7 +2662,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_WINDOW_RESIZE_START:
 				{
 					struct yutani_msg_window_resize_start * wa = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)wa->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)wa->wid);
 					if (w) {
 						if (yg->focused_window == w && !yg->resizing_window) {
 							yg->resizing_window = w;
@@ -2675,7 +2675,7 @@ int main(int argc, char * argv[]) {
 			case YUTANI_MSG_SPECIAL_REQUEST:
 				{
 					struct yutani_msg_special_request * sr = (void *)m->data;
-					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)sr->wid);
+					yutani_server_window_t * w = hashmap_get(yg->wids_to_windows, (void *)(uintptr_t)sr->wid);
 					switch (sr->request) {
 						case YUTANI_SPECIAL_REQUEST_MAXIMIZE:
 							if (w) {

+ 6 - 0
apps/demo.c

@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char * argv[]) {
+    printf("Hello, world! I am %s! I was called with '%s'\n", argv[0], argv[1]);
+    return 0;
+}

+ 4 - 0
apps/demo.krk

@@ -0,0 +1,4 @@
+import os, kuroko
+
+print('Kuroko',kuroko.version, kuroko.buildenv, kuroko.builddate)
+print('Running on:',os.uname())

+ 374 - 0
apps/dhcp_bitbanger.c

@@ -0,0 +1,374 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+struct ethernet_packet {
+	uint8_t destination[6];
+	uint8_t source[6];
+	uint16_t type;
+	uint8_t payload[];
+} __attribute__((packed)) __attribute__((aligned(2)));
+
+struct ipv4_packet {
+	uint8_t  version_ihl;
+	uint8_t  dscp_ecn;
+	uint16_t length;
+	uint16_t ident;
+	uint16_t flags_fragment;
+	uint8_t  ttl;
+	uint8_t  protocol;
+	uint16_t checksum;
+	uint32_t source;
+	uint32_t destination;
+	uint8_t  payload[];
+} __attribute__ ((packed)) __attribute__((aligned(2)));
+
+struct udp_packet {
+	uint16_t source_port;
+	uint16_t destination_port;
+	uint16_t length;
+	uint16_t checksum;
+	uint8_t  payload[];
+} __attribute__ ((packed)) __attribute__((aligned(2)));
+
+struct dhcp_packet {
+	uint8_t op;
+	uint8_t htype;
+	uint8_t hlen;
+	uint8_t hops;
+
+	uint32_t xid;
+
+	uint16_t secs;
+	uint16_t flags;
+
+	uint32_t ciaddr;
+	uint32_t yiaddr;
+	uint32_t siaddr;
+	uint32_t giaddr;
+
+	uint8_t  chaddr[16];
+
+	uint8_t sname[64];
+	uint8_t file[128];
+
+	uint32_t magic;
+
+	uint8_t  options[];
+} __attribute__ ((packed)) __attribute__((aligned(2)));
+
+struct dns_packet {
+	uint16_t qid;
+	uint16_t flags;
+	uint16_t questions;
+	uint16_t answers;
+	uint16_t authorities;
+	uint16_t additional;
+	uint8_t data[];
+} __attribute__ ((packed)) __attribute__((aligned(2)));
+
+struct tcp_header {
+	uint16_t source_port;
+	uint16_t destination_port;
+
+	uint32_t seq_number;
+	uint32_t ack_number;
+
+	uint16_t flags;
+	uint16_t window_size;
+	uint16_t checksum;
+	uint16_t urgent;
+
+	uint8_t  payload[];
+} __attribute__((packed)) __attribute__((aligned(2)));
+
+struct tcp_check_header {
+	uint32_t source;
+	uint32_t destination;
+	uint8_t  zeros;
+	uint8_t  protocol;
+	uint16_t tcp_len;
+	uint8_t  tcp_header[];
+};
+
+#define SOCK_STREAM 1
+#define SOCK_DGRAM 2
+
+// Note: Data offset is in upper 4 bits of flags field. Shift and subtract 5 since that is the min TCP size.
+//       If the value is more than 5, multiply by 4 because this field is specified in number of words
+#define TCP_OPTIONS_LENGTH(tcp) (((((tcp)->flags) >> 12) - 5) * 4)
+#define TCP_HEADER_LENGTH(tcp) ((((tcp)->flags) >> 12) * 4)
+#define TCP_HEADER_LENGTH_FLIPPED(tcp) (((htons((tcp)->flags)) >> 12) * 4)
+
+#define htonl(l)  ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24))
+#define htons(s)  ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) )
+#define ntohl(l)  htonl((l))
+#define ntohs(s)  htons((s))
+
+#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+#define IPV4_PROT_UDP 17
+#define IPV4_PROT_TCP 6
+#define DHCP_MAGIC 0x63825363
+
+#define TCP_FLAGS_FIN (1 << 0)
+#define TCP_FLAGS_SYN (1 << 1)
+#define TCP_FLAGS_RES (1 << 2)
+#define TCP_FLAGS_PSH (1 << 3)
+#define TCP_FLAGS_ACK (1 << 4)
+#define TCP_FLAGS_URG (1 << 5)
+#define TCP_FLAGS_ECE (1 << 6)
+#define TCP_FLAGS_CWR (1 << 7)
+#define TCP_FLAGS_NS  (1 << 8)
+#define DATA_OFFSET_5 (0x5 << 12)
+
+#define ETHERNET_TYPE_IPV4 0x0800
+#define ETHERNET_TYPE_ARP  0x0806
+
+struct payload {
+	struct ethernet_packet eth_header;
+	struct ipv4_packet     ip_header;
+	struct udp_packet      udp_header;
+	struct dhcp_packet     dhcp_header;
+	uint8_t payload[32];
+};
+
+static void eth_ntoa(const uint8_t addr[6], char * out) {
+	/* XX:XX:XX:XX:XX:XX */
+	snprintf(out, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+		addr[0], addr[1], addr[2],
+		addr[3], addr[4], addr[5]);
+}
+
+static void ip_ntoa(const uint32_t src_addr, char * out) {
+	snprintf(out, 16, "%d.%d.%d.%d",
+		(src_addr & 0xFF000000) >> 24,
+		(src_addr & 0xFF0000) >> 16,
+		(src_addr & 0xFF00) >> 8,
+		(src_addr & 0xFF));
+}
+
+static const char * eth_type_str(uint16_t type) {
+	switch(type) {
+		case ETHERNET_TYPE_IPV4: return "IPv4";
+		case ETHERNET_TYPE_ARP: return "ARP";
+		default: return "unknown";
+	}
+}
+
+static void print_ipv4_header(struct ipv4_packet * packet) {
+	/* get addresses, type... */
+	char dest_addr[16];
+	char src_addr[16];
+	ip_ntoa(ntohl(packet->destination), dest_addr);
+	ip_ntoa(ntohl(packet->source), src_addr);
+	fprintf(stderr, "%s -> %s %d (%s) ",
+		src_addr, dest_addr, packet->protocol,
+		packet->protocol == IPV4_PROT_UDP ? "udp" :
+			packet->protocol == IPV4_PROT_TCP ? "tcp" : "?");
+}
+
+void print_header(const struct payload * header) {
+	/* Assume it's at least an Ethernet frame */
+	char dest_addr[18];
+	char src_addr[18];
+	eth_ntoa(header->eth_header.destination, dest_addr);
+	eth_ntoa(header->eth_header.source, src_addr);
+	fprintf(stderr, "%s -> %s %d (%s) ",
+		src_addr, dest_addr, ntohs(header->eth_header.type), eth_type_str(ntohs(header->eth_header.type)));
+	switch (ntohs(header->eth_header.type)) {
+		case ETHERNET_TYPE_IPV4:
+			print_ipv4_header((void*)&header->eth_header.payload);
+			break;
+		case ETHERNET_TYPE_ARP:
+			//print_arp_header(&header->eth_header.payload);
+			break;
+	}
+	fprintf(stderr, "\n");
+}
+
+uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) {
+	uint32_t sum = 0;
+	uint16_t * s = (uint16_t *)p;
+
+	/* TODO: Checksums for options? */
+	for (int i = 0; i < 10; ++i) {
+		sum += ntohs(s[i]);
+	}
+
+	if (sum > 0xFFFF) {
+		sum = (sum >> 16) + (sum & 0xFFFF);
+	}
+
+	return ~(sum & 0xFFFF) & 0xFFFF;
+}
+
+uint8_t mac_addr[6];
+
+void fill(struct payload *it, size_t payload_size) {
+
+	it->eth_header.source[0] = mac_addr[0];
+	it->eth_header.source[1] = mac_addr[1];
+	it->eth_header.source[2] = mac_addr[2];
+	it->eth_header.source[3] = mac_addr[3];
+	it->eth_header.source[4] = mac_addr[4];
+	it->eth_header.source[5] = mac_addr[5];
+
+	it->eth_header.destination[0] = 0xFF;
+	it->eth_header.destination[1] = 0xFF;
+	it->eth_header.destination[2] = 0xFF;
+	it->eth_header.destination[3] = 0xFF;
+	it->eth_header.destination[4] = 0xFF;
+	it->eth_header.destination[5] = 0xFF;
+
+	it->eth_header.type = htons(0x0800);
+
+	it->ip_header.version_ihl = ((0x4 << 4) | (0x5 << 0));
+	it->ip_header.dscp_ecn    = 0;
+	it->ip_header.length      = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + sizeof(struct dhcp_packet) + payload_size);
+	it->ip_header.ident       = htons(1);
+	it->ip_header.flags_fragment = 0;
+	it->ip_header.ttl         = 0x40;
+	it->ip_header.protocol    = IPV4_PROT_UDP;
+	it->ip_header.checksum    = 0;
+	it->ip_header.source      = htonl(0);
+	it->ip_header.destination = htonl(0xFFFFFFFF);
+
+	it->ip_header.checksum = htons(calculate_ipv4_checksum(&it->ip_header));
+
+	it->udp_header.source_port = htons(68);
+	it->udp_header.destination_port = htons(67);
+	it->udp_header.length = htons(sizeof(struct udp_packet) + sizeof(struct dhcp_packet) + payload_size);
+	it->udp_header.checksum = 0; /* uh */
+
+	it->dhcp_header.op = 1;
+	it->dhcp_header.htype = 1;
+	it->dhcp_header.hlen = 6;
+	it->dhcp_header.hops = 0;
+	it->dhcp_header.xid = htons(0x1337); /* transaction id... */
+	it->dhcp_header.secs = 0;
+	it->dhcp_header.flags = 0;
+
+	it->dhcp_header.ciaddr = 0;
+	it->dhcp_header.yiaddr = 0;
+	it->dhcp_header.siaddr = 0;
+	it->dhcp_header.giaddr = 0;
+	it->dhcp_header.chaddr[0] = mac_addr[0];
+	it->dhcp_header.chaddr[1] = mac_addr[1];
+	it->dhcp_header.chaddr[2] = mac_addr[2];
+	it->dhcp_header.chaddr[3] = mac_addr[3];
+	it->dhcp_header.chaddr[4] = mac_addr[4];
+	it->dhcp_header.chaddr[5] = mac_addr[5];
+
+	it->dhcp_header.magic = htonl(DHCP_MAGIC);
+}
+
+int main(int argc, char * argv[]) {
+
+#if 0
+	/* Let's make a socket. */
+	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sockfd < 0) { perror("socket"); return 1; }
+
+	/* Bind the socket to the requested device. */
+	//if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, 
+#endif
+
+	char * if_name = "enp0s4";
+	char if_path[100];
+
+	if (argc > 1) {
+		if_name = argv[1];
+	}
+
+	snprintf(if_path, 100, "/dev/net/%s", if_name);
+
+	int netdev = open(if_path, O_RDWR);
+
+	fprintf(stderr, "Configuring %s\n", if_name);
+
+	if (ioctl(netdev, 0x12340001, &mac_addr)) {
+		fprintf(stderr, "could not get mac address\n");
+		return 1;
+	}
+
+	fprintf(stderr, "mac address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		mac_addr[0], mac_addr[1], mac_addr[2],
+		mac_addr[3], mac_addr[4], mac_addr[5]);
+
+	/* Try to frob the whatsit */
+	{
+		struct payload thething = {
+			.payload = {53,1,1,55,2,3,6,255,0}
+		};
+
+		fill(&thething, 8);
+
+		write(netdev, &thething, sizeof(struct payload));
+	}
+
+	uint32_t yiaddr;
+	int stage = 1;
+
+	do {
+		char buf[8092] = {0};
+
+		struct pollfd fds[1];
+		fds[0].fd = netdev;
+		fds[0].events = POLLIN;
+		int ret = poll(fds,1,2000);
+		if (ret <= 0) {
+			printf("...\n");
+			continue;
+		}
+		ssize_t rsize = read(netdev, &buf, 8092);
+
+		if (rsize <= 0) {
+			printf("bad size? %zd\n", rsize);
+			continue;
+		}
+
+		struct payload * response = (void*)buf;
+
+		print_header(response);
+
+		if (ntohs(response->udp_header.destination_port) != 68) {
+			continue;
+		}
+
+		if (stage == 1) {
+			yiaddr = response->dhcp_header.yiaddr;
+			char yiaddr_ip[16];
+			ip_ntoa(ntohl(yiaddr), yiaddr_ip);
+
+			printf("Response from DHCP Discover: %s\n", yiaddr_ip);
+			struct payload thething = {
+				.payload = {53,1,3,50,4,
+					(yiaddr) & 0xFF,
+					(yiaddr >> 8) & 0xFF,
+					(yiaddr >> 16) & 0xFF,
+					(yiaddr >> 24) & 0xFF,
+					55,2,3,6,255,0}
+			};
+
+			fill(&thething, 14);
+			write(netdev, &thething, sizeof(struct payload));
+
+			stage = 2;
+		} else if (stage == 2) {
+			yiaddr = response->dhcp_header.yiaddr;
+			char yiaddr_ip[16];
+			ip_ntoa(ntohl(yiaddr), yiaddr_ip);
+
+			printf("ACK returns: %s\n", yiaddr_ip);
+			printf("Address is configured, continuing trace mode.\n");
+
+			stage = 3;
+		}
+	} while (1);
+	return 0;
+}

+ 1 - 1
apps/du.c

@@ -38,7 +38,7 @@ static int print_human_readable_size(char * _out, size_t s) {
 }
 
 static void print_size(uint64_t size, char * name) {
-	char sizes[8];
+	char sizes[30];
 	if (!human) {
 		sprintf(sizes, "%-7llu", size/1024LLU);
 	} else {

+ 1 - 1
apps/fetch.c

@@ -289,7 +289,7 @@ int main(int argc, char * argv[]) {
 	struct http_req my_req;
 	parse_url(argv[optind], &my_req);
 
-	char file[100];
+	char file[600];
 	sprintf(file, "/dev/net/%s", my_req.domain);
 
 	if (fetch_options.calculate_output) {

+ 4 - 4
apps/file-browser.c

@@ -85,7 +85,7 @@ static int  nav_bar_cursor_x = 0;
 static int  nav_bar_focused = 0;
 
 /* Status bar displayed at the bottom of the window */
-static char window_status[512] = {0};
+static char window_status[1024] = {0};
 
 /* Button row visibility statuses */
 static int _button_hilights[4] = {3,3,3,3};
@@ -435,7 +435,7 @@ static void update_status(void) {
 	char tmp_size[50];
 	if (selected_count == 0) {
 		print_human_readable_size(tmp_size, total_size);
-		sprintf(window_status, "%d item%s (%s)", file_pointers_len, file_pointers_len == 1 ? "" : "s", tmp_size);
+		sprintf(window_status, "%zd item%s (%s)", file_pointers_len, file_pointers_len == 1 ? "" : "s", tmp_size);
 	} else if (selected_count == 1) {
 		print_human_readable_size(tmp_size, selected->size);
 		sprintf(window_status, "\"%s\" (%s) %s", selected->name, tmp_size, selected->filetype);
@@ -1955,7 +1955,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win == main_window) {
 							win->focused = wf->focused;
 							redraw_files();
@@ -1994,7 +1994,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_MOUSE_EVENT:
 					{
 						struct yutani_msg_window_mouse_event * me = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid);
 						struct decor_bounds bounds;
 						_decor_get_bounds(win, &bounds);
 

+ 0 - 16
apps/go-video.sh

@@ -1,16 +0,0 @@
-#!/bin/sh
-
-# Start font server if freetype is available
-if stat -Lq /usr/lib/libfreetype.so then font-server
-
-if empty? "$1" then export WIDTH=1024 else export WIDTH="$1"
-if empty? "$2" then export HEIGHT=768 else export HEIGHT="$2"
-
-# Switch to graphics mode
-if not set-resolution --initialize auto $WIDTH $HEIGHT then exec sh -c "echo 'Failed to set video mode, bailing.'; exit 1"
-
-# Tell the terminal to pause input
-killall -s USR2 terminal-vga
-
-# Start the compositor
-compositor

+ 8 - 8
apps/help-browser.c

@@ -118,13 +118,13 @@ static void write_buffer(void) {
 
 static int parser_open(struct markup_state * self, void * user, struct markup_tag * tag) {
 	if (!strcmp(tag->name, "b")) {
-		list_insert(state, (void*)current_state);
+		list_insert(state, (void*)(uintptr_t)current_state);
 		current_state |= (1 << 0);
 	} else if (!strcmp(tag->name, "i")) {
-		list_insert(state, (void*)current_state);
+		list_insert(state, (void*)(uintptr_t)current_state);
 		current_state |= (1 << 1);
 	} else if (!strcmp(tag->name, "h1")) {
-		list_insert(state, (void*)current_state);
+		list_insert(state, (void*)(uintptr_t)current_state);
 		current_state |= (1 << 2);
 	} else if (!strcmp(tag->name, "br")) {
 		write_buffer();
@@ -138,18 +138,18 @@ static int parser_open(struct markup_state * self, void * user, struct markup_ta
 static int parser_close(struct markup_state * self, void * user, char * tag_name) {
 	if (!strcmp(tag_name, "b")) {
 		node_t * nstate = list_pop(state);
-		current_state = (int)nstate->value;
+		current_state = (int)(uintptr_t)nstate->value;
 		free(nstate);
 	} else if (!strcmp(tag_name, "i")) {
 		node_t * nstate = list_pop(state);
-		current_state = (int)nstate->value;
+		current_state = (int)(uintptr_t)nstate->value;
 		free(nstate);
 	} else if (!strcmp(tag_name, "h1")) {
 		write_buffer();
 		cursor_x = BASE_X;
 		cursor_y += current_line_height();
 		node_t * nstate = list_pop(state);
-		current_state = (int)nstate->value;
+		current_state = (int)(uintptr_t)nstate->value;
 		free(nstate);
 	}
 	return 0;
@@ -413,7 +413,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win == main_window) {
 							win->focused = wf->focused;
 							redraw_window();
@@ -431,7 +431,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_MOUSE_EVENT:
 					{
 						struct yutani_msg_window_mouse_event * me = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid);
 
 						if (win == main_window) {
 							int result = decor_handle_event(yctx, m);

+ 11 - 0
apps/ifconfig.c

@@ -0,0 +1,11 @@
+/**
+ * @file  apps/ifconfig.c
+ * @brief Network interface configuration tool.
+ *
+ * Manipulates and enumerates network interfaces.
+ */
+#include <stdio.h>
+
+int main(int argc, char * argv[]) {
+	/* I have no idea how this works on Linux or BSD, but based on some manpages... */
+}

+ 1 - 1
apps/imgviewer.c

@@ -190,7 +190,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win && win == window) {
 							win->focused = wf->focused;
 							decors();

+ 3 - 3
apps/json-test.c

@@ -24,19 +24,19 @@ int main(int argc, char * argv[]) {
 	{
 		Value * result = json_parse("-123");
 		assert(result && result->type == JSON_TYPE_NUMBER);
-		assert(fabs(result->number - (-123.0) < 0.0001));
+		assert(fabs(result->number - (-123.0)) < 0.0001);
 	}
 
 	{
 		Value * result = json_parse("2e3");
 		assert(result && result->type == JSON_TYPE_NUMBER);
-		assert(fabs(result->number - (2000.0) < 0.0001));
+		assert(fabs(result->number - (2000.0)) < 0.0001);
 	}
 
 	{
 		Value * result = json_parse("0.124");
 		assert(result && result->type == JSON_TYPE_NUMBER);
-		assert(fabs(result->number - (0.124) < 0.0001));
+		assert(fabs(result->number - (0.124)) < 0.0001);
 	}
 
 	{

+ 1 - 1
apps/julia.c

@@ -299,7 +299,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win && win == window) {
 							win->focused = wf->focused;
 							decors();

+ 1 - 1
apps/killall.c

@@ -31,7 +31,7 @@ typedef struct process {
 #define LINE_LEN 4096
 
 p_t * build_entry(struct dirent * dent) {
-	char tmp[256];
+	char tmp[300];
 	FILE * f;
 	char line[LINE_LEN];
 

File diff suppressed because it is too large
+ 0 - 1166
apps/kuroko.c


+ 9 - 3
apps/lspci.c

@@ -63,10 +63,16 @@ struct {
 	{0x15ad, 0x0405, "SVGA II Adapter"},
 	{0x15ad, 0x0790, "PCI bridge"},
 	{0x15ad, 0x07a0, "PCI Express Root Port"},
-	{0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)"},
-	{0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)"},
+	{0x8086, 0x1004, "82543GC Gigabit Ethernet Controller (e1000)"},
+	{0x8086, 0x100e, "82540EM Gigabit Ethernet Controller (e1000)"},
+	{0x8086, 0x100f, "82545EM Gigabit Ethernet Controller (e1000)"},
+	{0x8086, 0x10ea, "82577LM Gigabit Ethernet Controller (e1000)"},
 	{0x8086, 0x1237, "PCI & Memory"},
-	{0x8086, 0x2415, "AC'97 Audio Chipset"},
+	{0x8086, 0x2415, "82801AA AC'97 Audio Controller"},
+	{0x8086, 0x29c0, "DRAM Controller"},
+	{0x8086, 0x2918, "ICH9 LPC Interface Controller"},
+	{0x8086, 0x2922, "ICH9 6-port SATA Controller"},
+	{0x8086, 0x2930, "ICH9 SMBus Controller"},
 	{0x8086, 0x7000, "PCI-to-ISA Bridge"},
 	{0x8086, 0x7010, "IDE Interface"},
 	{0x8086, 0x7110, "PIIX4 ISA"},

+ 1 - 1
apps/migrate.c

@@ -217,7 +217,7 @@ int main(int argc, char * argv[]) {
 	}
 	char * root_type = hashmap_get(cmdline,"root_type");
 	if (!root_type) {
-		root_type = "ext2";
+		root_type = "tar";
 	}
 
 	char tmp[1024];

+ 66 - 0
apps/misaka-test.c

@@ -0,0 +1,66 @@
+/**
+ * @file  misaka-test.c
+ * @brief Test app for Misaka with a bunch of random stuff.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <toaru/graphics.h>
+
+#include <kuroko/kuroko.h>
+#include <kuroko/vm.h>
+
+static void demo_runKurokoSnippet(void) {
+	krk_initVM(0);
+	krk_startModule("__main__");
+	krk_interpret("import kuroko\nprint('Kuroko',kuroko.version)\n", "<stdin>");
+	krk_freeVM();
+}
+
+static void demo_drawWallpaper(void) {
+	/* Set up a wrapper context for the framebuffer */
+	gfx_context_t * ctx = init_graphics_fullscreen();
+
+	/* Load the wallpaper. */
+	sprite_t wallpaper = { 0 };
+	load_sprite(&wallpaper, "/usr/share/wallpaper.jpg");
+	wallpaper.alpha = ALPHA_EMBEDDED;
+
+	printf("wallpaper sprite info: %d x %d\n", wallpaper.width, wallpaper.height);
+
+	draw_sprite_scaled(ctx, &wallpaper, 0, 0, 1440, 900);
+	flip(ctx);
+	//blur_context_box(&ctx, 10);
+}
+
+int main(int argc, char * argv[]) {
+	demo_drawWallpaper();
+	demo_runKurokoSnippet();
+
+	//execve("/bin/kuroko",(char*[]){"kuroko",NULL},(char*[]){NULL});
+	char * args[] = {
+		"/bin/sh",
+		"-c",
+		"sleep 2; echo hi; echo glorp",
+		NULL,
+	};
+	pid_t pid = fork();
+	if (!pid) {
+		printf("returned from fork in child\n");
+		execvp(args[0], args);
+		exit(1);
+	} else {
+		printf("returned from fork with pid = %d\n", pid);
+		int status;
+		waitpid(pid, &status, 0);
+		printf("done with waitpid, looping\n");
+		while (1) {
+			sched_yield();
+		}
+		return WEXITSTATUS(status);
+	}
+
+	return 0;
+}

+ 2 - 2
apps/msk.c

@@ -423,8 +423,8 @@ static int install_packages(int argc, char * argv[]) {
 		}
 		fprintf(stderr, "\nContinue? [Y/n] ");
 		fflush(stderr);
-		char resp[4];
-		fgets(resp, 4, stdin);
+		char resp[5];
+		fgets(resp, 5, stdin);
 		if (!(!strcmp(resp,"\n") || !strcmp(resp,"y\n") || !strcmp(resp,"Y\n") || !strcmp(resp,"yes\n"))) {
 			fprintf(stderr, "Aborting.\n");
 			return 1;

+ 2 - 2
apps/package-manager.c

@@ -552,7 +552,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win == main_window) {
 							win->focused = wf->focused;
 							redraw_packages();
@@ -571,7 +571,7 @@ int main(int argc, char * argv[]) {
 				case YUTANI_MSG_WINDOW_MOUSE_EVENT:
 					{
 						struct yutani_msg_window_mouse_event * me = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)me->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)me->wid);
 
 						if (win == main_window) {
 							int result = decor_handle_event(yctx, m);

+ 1 - 1
apps/pidof.c

@@ -26,7 +26,7 @@ typedef struct process {
 #define LINE_LEN 4096
 
 p_t * build_entry(struct dirent * dent) {
-	char tmp[256];
+	char tmp[300];
 	FILE * f;
 	char line[LINE_LEN];
 

+ 1 - 1
apps/plasma.c

@@ -163,7 +163,7 @@ int main (int argc, char ** argv) {
 				case YUTANI_MSG_WINDOW_FOCUS_CHANGE:
 					{
 						struct yutani_msg_window_focus_change * wf = (void*)m->data;
-						yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid);
+						yutani_window_t * win = hashmap_get(yctx->windows, (void*)(uintptr_t)wf->wid);
 						if (win && win == wina) {
 							win->focused = wf->focused;
 						}

+ 2 - 2
apps/pong.c

@@ -177,7 +177,7 @@ void update_stuff(void) {
 
 	if (colliding(&ball, &left)) {
 		ball.x = left.x + left.width + 2;
-		ball.vel_x   = (abs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x;
+		ball.vel_x   = (fabs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x;
 
 		double intersect = ((ball.y + ball.height/2) - (left.y)) / ((double)left.height) - 0.5;
 		ball.vel_y = intersect * 8.0;
@@ -186,7 +186,7 @@ void update_stuff(void) {
 
 	if (colliding(&ball, &right)) {
 		ball.x = right.x - ball.width - 2;
-		ball.vel_x   = (abs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x;
+		ball.vel_x   = (fabs(ball.vel_x) < 8.0) ? -ball.vel_x * 1.05 : -ball.vel_x;
 
 		double intersect = ((ball.y + ball.height/2) - (right.y)) / ((double)right.height/2.0);
 		ball.vel_y = intersect * 3.0;

+ 1 - 1
apps/ps.c

@@ -55,7 +55,7 @@ void print_username(int uid) {
 }
 
 struct process * process_entry(struct dirent *dent) {
-	char tmp[256];
+	char tmp[300];
 	FILE * f;
 	char line[LINE_LEN];
 

+ 3 - 3
apps/pstree.c

@@ -29,7 +29,7 @@ typedef struct process {
 #define LINE_LEN 4096
 
 p_t * build_entry(struct dirent * dent) {
-	char tmp[256];
+	char tmp[300];
 	FILE * f;
 	char line[LINE_LEN];
 
@@ -87,7 +87,7 @@ p_t * build_entry(struct dirent * dent) {
 
 uint8_t find_pid(void * proc_v, void * pid_v) {
 	p_t * p = proc_v;
-	pid_t i = (pid_t)pid_v;
+	pid_t i = (pid_t)(uintptr_t)pid_v;
 
 	return (uint8_t)(p->pid == i);
 }
@@ -161,7 +161,7 @@ int main (int argc, char * argv[]) {
 			if (proc->ppid == 0 && proc->pid == 1) {
 				tree_set_root(procs, proc);
 			} else {
-				tree_node_t * parent = tree_find(procs,(void *)proc->ppid,find_pid);
+				tree_node_t * parent = tree_find(procs,(void *)(uintptr_t)proc->ppid,find_pid);
 				if (parent) {
 					tree_node_insert_child(procs, parent, proc);
 				}

+ 632 - 200
apps/readelf.c

@@ -1,256 +1,688 @@
-/* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2013-2018 K Lange
- *
- * readelf - Show information about ELF objects
+/**
+ * @file  readelf.c
+ * @brief Display information about a 64-bit Elf binary or object.
  *
- * This is a very custom implementation and nothing remotely
- * like the version that comes with binutils. Making it more
- * like that version might be worthwhile.
+ * Implementation of a `readelf` utility.
  */
 #include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
 #include <string.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <kernel/elf.h>
 
-/**
- * Show usage for the readelf application.
- * @param argc Argument count (unused)
- * @param argv Arguments to binary
- */
-void usage(int argc, char ** argv) {
-	/* Show usage */
-	printf("%s [filename]\n", argv[0]);
-	printf("\tDisplays information on ELF binaries such as section names,\n");
-	printf("\tlocations, sizes, and loading positions in memory.\n");
-	exit(1);
+
+static const char * elf_classToStr(unsigned char ei_class) {
+	static char buf[64];
+	switch (ei_class) {
+		case ELFCLASS32: return "ELF32";
+		case ELFCLASS64: return "ELF64";
+		default:
+			sprintf(buf, "unknown (%d)", ei_class);
+			return buf;
+	}
 }
 
-/**
- * Application entry point.
- * @returns 0 on sucess, 1 on failure
- */
-int main(int argc, char ** argv) {
-	/* Process arguments */
-	if (argc < 2) usage(argc,argv);
+static const char * elf_dataToStr(unsigned char ei_data) {
+	static char buf[64];
+	switch (ei_data) {
+		case ELFDATA2LSB: return "2's complement, little endian";
+		case ELFDATA2MSB: return "2's complement, big endian";
+		default:
+			sprintf(buf, "unknown (%d)", ei_data);
+			return buf;
+	}
+}
 
-	FILE * binary;           /**< File pointer for requested executable */
-	size_t binary_size;      /**< Size of the file */
-	char * binary_buf;       /**< Buffer to store the binary in memory */
-	Elf32_Header * header;   /**< ELF header */
-	char * string_table = NULL;     /**< The section header string table */
-	char * sym_string_table = NULL; /**< The symbol string table */
+static char * elf_versionToStr(unsigned char ei_version) {
+	static char buf[64];
+	switch (ei_version) {
+		case 1: return "1 (current)";
+		default:
+			sprintf(buf, "unknown (%d)", ei_version);
+			return buf;
+	}
+}
+
+static char * elf_osabiToStr(unsigned char ei_osabi) {
+	static char buf[64];
+	switch (ei_osabi) {
+		case 0: return "UNIX - System V";
+		case 1: return "HP-UX";
+		case 255: return "Standalone";
+		default:
+			sprintf(buf, "unknown (%d)", ei_osabi);
+			return buf;
+	}
+}
 
-	/* Open the requested binary */
-	binary = fopen(argv[1], "r");
+static char * elf_typeToStr(Elf64_Half type) {
+	static char buf[64];
+	switch (type) {
+		case ET_NONE: return "NONE (No file type)";
+		case ET_REL:  return "REL (Relocatable object file)";
+		case ET_EXEC: return "EXEC (Executable file)";
+		case ET_DYN:  return "DYN (Shared object file)";
+		case ET_CORE: return "CORE (Core file)";
+		default:
+			sprintf(buf, "unknown (%d)", type);
+			return buf;
+	}
+}
 
-	if (!binary) {
-		fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno));
-		return 1;
+static char * elf_machineToStr(Elf64_Half machine) {
+	static char buf[64];
+	switch (machine) {
+		case EM_X86_64: return "Advanced Micro Devices X86-64";
+		default:
+			sprintf(buf, "unknown (%d)", machine);
+			return buf;
 	}
+}
 
-	/* Jump to the end so we can get the size */
-	fseek(binary, 0, SEEK_END);
-	binary_size = ftell(binary);
-	fseek(binary, 0, SEEK_SET);
+static char * sectionHeaderTypeToStr(Elf64_Word type) {
+	static char buf[64];
+	switch (type) {
+		case SHT_NULL: return "NULL";
+		case SHT_PROGBITS: return "PROGBITS";
+		case SHT_SYMTAB: return "SYMTAB";
+		case SHT_STRTAB: return "STRTAB";
+		case SHT_RELA: return "RELA";
+		case SHT_HASH: return "HASH";
+		case SHT_DYNAMIC: return "DYNAMIC";
+		case SHT_NOTE: return "NOTE";
+		case SHT_NOBITS: return "NOBITS";
+		case SHT_REL: return "REL";
+		case SHT_SHLIB: return "SHLIB";
+		case SHT_DYNSYM: return "DYNSYM";
 
-	/* Some sanity checks */
-	if (binary_size < 4 || binary_size > 0xFFFFFFF) {
-		printf("Oh no! I don't quite like the size of this binary.\n");
-		return 1;
+		case 0xE: return "INIT_ARRAY";
+		case 0xF: return "FINI_ARRAY";
+		case 0x6ffffff6: return "GNU_HASH";
+		case 0x6ffffffe: return "VERNEED";
+		case 0x6fffffff: return "VERSYM";
+		default:
+			sprintf(buf, "(%x)", type);
+			return buf;
 	}
-	printf("Binary is %u bytes.\n", (unsigned int)binary_size);
-
-	/* Read the binary into a buffer */
-	binary_buf = malloc(binary_size);
-	fread((void *)binary_buf, binary_size, 1, binary);
-
-	/* Let's start considering this guy an elf, 'eh? */
-	header = (Elf32_Header *)binary_buf;
-
-	/* Verify the magic */
-	if (	header->e_ident[0] != ELFMAG0 ||
-			header->e_ident[1] != ELFMAG1 ||
-			header->e_ident[2] != ELFMAG2 ||
-			header->e_ident[3] != ELFMAG3) {
-		printf("Header magic is wrong!\n");
-		printf("Are you sure this is a 32-bit ELF binary or object file?\n");
-		return 1;
+}
+
+static char * programHeaderTypeToStr(Elf64_Word type) {
+	static char buf[64];
+	switch (type) {
+		case PT_NULL: return "NULL";
+		case PT_LOAD: return "LOAD";
+		case PT_DYNAMIC: return "DYNAMIC";
+		case PT_INTERP: return "INTERP";
+		case PT_NOTE: return "NOTE";
+		case PT_PHDR: return "PHDR";
+		case PT_GNU_EH_FRAME: return "GNU_EH_FRAME";
+
+		case 0x6474e553: return "GNU_PROPERTY";
+		case 0x6474e551: return "GNU_STACK";
+		case 0x6474e552: return "GNU_RELRO";
+
+		default:
+			sprintf(buf, "(%x)", type);
+			return buf;
 	}
+}
+
+static char * programHeaderFlagsToStr(Elf64_Word flags) {
+	static char buf[10];
 
-	/* Let's print out some of the header information, shall we? */
-	printf("\033[1mELF Header\033[0m\n");
+	snprintf(buf, 10, "%c%c%c   ",
+		(flags & PF_R) ? 'R' : ' ',
+		(flags & PF_W) ? 'W' : ' ',
+		(flags & PF_X) ? 'E' : ' '); /* yes, E, not X... */
 
-	/* File type */
-	printf("[Type %d] ", header->e_type);
-	switch (header->e_type) {
-		case ET_NONE:
-			printf("No file type.\n");
+	return buf;
+}
+
+static char * dynamicTagToStr(Elf64_Dyn * dynEntry, char * dynstr) {
+	static char buf[1024];
+	static char extra[500];
+	char * name = NULL;
+	sprintf(extra, "0x%lx", dynEntry->d_un.d_val);
+
+	switch (dynEntry->d_tag) {
+		case DT_NULL:
+			name = "(NULL)";
+			break;
+		case DT_NEEDED:
+			name = "(NEEDED)";
+			sprintf(extra, "[shared lib = %s]", dynstr + dynEntry->d_un.d_val);
+			break;
+		case DT_PLTRELSZ:
+			name = "(PLTRELSZ)";
+			break;
+		case DT_PLTGOT:
+			name = "(PLTGOT)";
+			break;
+		case DT_HASH:
+			name = "(HASH)";
+			break;
+		case DT_STRTAB:
+			name = "(STRTAB)";
+			break;
+		case DT_SYMTAB:
+			name = "(SYMTAB)";
+			break;
+		case DT_RELA:
+			name = "(RELA)";
+			break;
+		case DT_RELASZ:
+			name = "(RELASZ)";
+			break;
+		case DT_RELAENT:
+			name = "(RELAENT)";
+			break;
+		case DT_STRSZ:
+			name = "(STRSZ)";
+			sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val);
+			break;
+		case DT_SYMENT:
+			name = "(SYMENT)";
+			sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val);
+			break;
+		case DT_INIT:
+			name = "(INIT)";
+			break;
+		case DT_FINI:
+			name = "(FINI)";
+			break;
+		case DT_SONAME:
+			name = "(SONAME)";
+			break;
+		case DT_RPATH:
+			name = "(RPATH)";
+			break;
+		case DT_SYMBOLIC:
+			name = "(SYMBOLIC)";
 			break;
-		case ET_REL:
-			printf("Relocatable file.\n");
+		case DT_REL:
+			name = "(REL)";
 			break;
-		case ET_EXEC:
-			printf("Executable file.\n");
+		case DT_RELSZ:
+			name = "(RELSZ)";
+			sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val);
 			break;
-		case ET_DYN:
-			printf("Shared object file.\n");
+		case DT_RELENT:
+			name = "(RELENT)";
 			break;
-		case ET_CORE:
-			printf("Core file.\n");
+		case DT_PLTREL:
+			name = "(PLTREL)";
+			sprintf(extra, "%s",
+				dynEntry->d_un.d_val == DT_REL ? "REL" : "RELA");
+			break;
+		case DT_DEBUG:
+			name = "(DEBUG)";
+			break;
+		case DT_TEXTREL:
+			name = "(TEXTREL)";
+			break;
+		case DT_JMPREL:
+			name = "(JMPREL)";
+			break;
+		case DT_BIND_NOW:
+			name = "(BIND_NOW)";
+			break;
+		case DT_INIT_ARRAY:
+			name = "(INIT_ARRAY)";
+			break;
+		case DT_FINI_ARRAY:
+			name = "(FINI_ARRAY)";
+			break;
+		case DT_INIT_ARRAYSZ:
+			name = "(INIT_ARRAYSZ)";
+			sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val);
+			break;
+		case DT_FINI_ARRAYSZ:
+			name = "(FINI_ARRASZ)";
+			sprintf(extra, "%ld (bytes)", dynEntry->d_un.d_val);
+			break;
+		case 0x1E:
+			name = "(FLAGS)";
+			break;
+		case 0x6ffffef5:
+			name = "(GNU_HASH)";
+			break;
+		case 0x6ffffffb:
+			name = "(FLAGS_1)";
+			break;
+		case 0x6ffffffe:
+			name = "(VERNEED)";
+			break;
+		case 0x6fffffff:
+			name = "(VERNEEDNUM)";
+			sprintf(extra, "%ld", dynEntry->d_un.d_val);
+			break;
+		case 0x6ffffff0:
+			name = "(VERSYM)";
+			break;
+		case 0x6ffffff9:
+			name = "(RELACOUNT)";
+			sprintf(extra, "%ld", dynEntry->d_un.d_val);
 			break;
 		default:
-			printf("(Unknown file type)\n");
+			name = "(unknown)";
 			break;
 	}
 
-	/* Machine Type */
-	switch (header->e_machine) {
-		case EM_386:
-			printf("Intel x86\n");
-			break;
+	sprintf(buf,"%-15s %s", name, extra);
+	return buf;
+}
+
+static char * relocationInfoToStr(Elf64_Xword info) {
+#define CASE(o) case o: return #o;
+	switch (info) {
+		CASE(R_X86_64_NONE)
+		CASE(R_X86_64_64)
+		CASE(R_X86_64_PC32)
+		CASE(R_X86_64_GOT32)
+		CASE(R_X86_64_PLT32)
+		CASE(R_X86_64_COPY)
+		CASE(R_X86_64_GLOB_DAT)
+		CASE(R_X86_64_JUMP_SLOT)
+		CASE(R_X86_64_RELATIVE)
+		CASE(R_X86_64_GOTPCREL)
+		CASE(R_X86_64_32)
+		CASE(R_X86_64_32S)
+		CASE(R_X86_64_DTPMOD64)
+		CASE(R_X86_64_DTPOFF64)
+		CASE(R_X86_64_TPOFF64)
+		CASE(R_X86_64_TLSGD)
+		CASE(R_X86_64_TLSLD)
+		CASE(R_X86_64_DTPOFF32)
+		CASE(R_X86_64_GOTTPOFF)
+		CASE(R_X86_64_TPOFF32)
+		CASE(R_X86_64_PC64)
+		CASE(R_X86_64_GOTOFF64)
+		CASE(R_X86_64_GOTPC32)
+		CASE(R_X86_64_GOT64)
+		CASE(R_X86_64_GOTPCREL64)
+		CASE(R_X86_64_GOTPC64)
+		CASE(R_X86_64_GOTPLT64)
+		CASE(R_X86_64_PLTOFF64)
+		CASE(R_X86_64_SIZE32)
+		CASE(R_X86_64_SIZE64)
+		CASE(R_X86_64_GOTPC32_TLSDESC)
+		CASE(R_X86_64_TLSDESC_CALL)
+		CASE(R_X86_64_TLSDESC)
+		CASE(R_X86_64_IRELATIVE)
 		default:
-			printf("Unknown machine: %d\n", header->e_machine);
-			break;
+			return "unknown";
 	}
+#undef CASE
+}
 
-	/* Version == EV_CURRENT? */
-	if (header->e_version == EV_CURRENT) {
-		printf("ELF version is 1, as it should be.\n");
+static int sizeOfRelocationValue(int type) {
+	switch (type) {
+		case R_X86_64_TLSDESC:
+			return 16;
+		case R_X86_64_64:
+		case R_X86_64_GLOB_DAT:
+		case R_X86_64_JUMP_SLOT:
+		case R_X86_64_RELATIVE:
+		case R_X86_64_DTPMOD64:
+		case R_X86_64_DTPOFF64:
+		case R_X86_64_TPOFF64:
+		case R_X86_64_PC64:
+		case R_X86_64_GOTOFF64:
+		case R_X86_64_GOT64:
+		case R_X86_64_GOTPCREL64:
+		case R_X86_64_GOTPC64:
+		case R_X86_64_GOTPLT64:
+		case R_X86_64_PLTOFF64:
+		case R_X86_64_SIZE64:
+		case R_X86_64_IRELATIVE:
+			return 8;
+		case R_X86_64_PC32:
+		case R_X86_64_GOT32:
+		case R_X86_64_PLT32:
+		case R_X86_64_GOTPCREL:
+		case R_X86_64_32:
+		case R_X86_64_32S:
+		case R_X86_64_TLSGD:
+		case R_X86_64_TLSLD:
+		case R_X86_64_DTPOFF32:
+		case R_X86_64_GOTTPOFF:
+		case R_X86_64_TPOFF32:
+		case R_X86_64_GOTPC32:
+		case R_X86_64_SIZE32:
+		case R_X86_64_GOTPC32_TLSDESC:
+			return 4;
+		case R_X86_64_16:
+		case R_X86_64_PC16:
+			return 2;
+		case R_X86_64_8:
+		case R_X86_64_PC8:
+			return 1;
+		case R_X86_64_NONE:
+		case R_X86_64_COPY:
+		case R_X86_64_TLSDESC_CALL:
+		default:
+			return 0;
 	}
+}
 
-	/* Entry point in memory */
-	printf("Binary entry point in virtual memory is at 0x%x\n", (unsigned int)header->e_entry);
+static char * symbolTypeToStr(int type) {
+	static char buf[10];
+	switch (type) {
+		case STT_NOTYPE:  return "NOTYPE";
+		case STT_OBJECT:  return "OBJECT";
+		case STT_FUNC:    return "FUNC";
+		case STT_SECTION: return "SECTION";
+		case STT_FILE:    return "FILE";
+		default:
+			sprintf(buf, "%x", type);
+			return buf;
+	}
+}
 
-	/* Program header table offset */
-	printf("Program header table is at +0x%x and one entry is 0x%x bytes.\n"
-			"There are %d total program headers.\n",
-			(unsigned int)header->e_phoff, (unsigned int)header->e_phentsize, (unsigned int)header->e_phnum);
+static char * symbolBindToStr(int bind) {
+	static char buf[10];
+	switch (bind) {
+		case STB_LOCAL:  return "LOCAL";
+		case STB_GLOBAL: return "GLOBAL";
+		case STB_WEAK:   return "WEAK";
+		default:
+			sprintf(buf, "%x", bind);
+			return buf;
+	}
+}
 
-	/* Section header table offset */
-	printf("Section header table is at +0x%x and one entry is 0x%x bytes.\n"
-			"There are %d total section headers.\n",
-			(unsigned int)header->e_shoff, (unsigned int)header->e_shentsize, (unsigned int)header->e_shnum);
+int main(int argc, char * argv[]) {
+	if (argc < 2) {
+		fprintf(stderr, "%s: expected filename\n", argv[0]);
+		return 1;
+	}
 
-	/* Read the program headers */
-	printf("\033[1mProgram Headers\033[0m\n");
-	for (uint32_t x = 0; x < header->e_phentsize * header->e_phnum; x += header->e_phentsize) {
-		if (header->e_phoff + x > binary_size) {
-			printf("Tried to read beyond the end of the file.\n");
-			return 1;
-		}
-		/* Grab the program header */
-		Elf32_Phdr * phdr = (Elf32_Phdr *)((uintptr_t)binary_buf + (header->e_phoff + x));
+	FILE * f = fopen(argv[1],"r");
 
-		/* Print the header type */
-		switch (phdr->p_type) {
-			case PT_LOAD:
-				printf("[Loadable Segment]\n");
-				break;
-			case PT_DYNAMIC:
-				printf("[Dynamic Loading Information]\n");
-				break;
-			case PT_INTERP:
-				printf("[Interpreter Path]\n");
-				break;
-			default:
-				printf("[Unused Segement]\n");
-				break;
-		}
+	if (!f) {
+		fprintf(stderr, "%s: %s: %s\n", argv[0], argv[1], strerror(errno));
+		return 1;
 	}
 
-	uint32_t i = 0;
-	for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
-		if (header->e_shoff + x > binary_size) {
-			printf("Tried to read beyond the end of the file.\n");
-			return 1;
-		}
-		Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x));
-		if (shdr->sh_type == SHT_STRTAB) {
-			if (i == header->e_shstrndx) {
-				string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
-				printf("Found the section string table at 0x%x\n", (unsigned int)shdr->sh_offset);
-			}
-		}
-		i++;
-	}
+	/**
+	 * Validate header.
+	 */
+	Elf64_Header header;
+	fread(&header, sizeof(Elf64_Header), 1, f);
 
-	if (!string_table) {
-		printf("No string table, skipping rest of output.\n");
+	if (memcmp("\x7F" "ELF",&header,4)) {
+		fprintf(stderr, "%s: %s: not an elf\n", argv[0], argv[1]);
 		return 1;
 	}
 
-	/* Find the (hopefully two) string tables */
-	printf("\033[1mString Tables\033[0m\n");
-	for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
-		if (header->e_shoff + x > binary_size) {
-			printf("Tried to read beyond the end of the file.\n");
-			return 1;
-		}
-		Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x));
-		if (shdr->sh_type == SHT_STRTAB) {
-			if (!strcmp((char *)((uintptr_t)string_table + shdr->sh_name), ".strtab")) {
-				sym_string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
-				printf("Found the symbol string table at 0x%x\n", (unsigned int)shdr->sh_offset);
-			}
-			printf("Displaying string table at 0x%x\n", (unsigned int)shdr->sh_offset);
-			char * _string_table = (char *)((uintptr_t)binary_buf + shdr->sh_offset);
-			unsigned int j = 1;
-			int k = 0;
-			printf("%d\n", (unsigned int)shdr->sh_size);
-			while (j < shdr->sh_size) {
-				int t = strlen((char *)((uintptr_t)_string_table + j));
-				if (t) {
-					printf("%d [%d] %s\n", k, j, (char *)((uintptr_t)_string_table + j));
-					k++;
-					j += t;
-				} else {
-					j += 1;
-				}
-			}
-		}
+	printf("ELF Header:\n");
+	printf("  Magic:   %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		header.e_ident[0],  header.e_ident[1],  header.e_ident[2],  header.e_ident[3],
+		header.e_ident[4],  header.e_ident[5],  header.e_ident[6],  header.e_ident[7],
+		header.e_ident[8],  header.e_ident[9],  header.e_ident[10], header.e_ident[11],
+		header.e_ident[12], header.e_ident[13], header.e_ident[14], header.e_ident[15]);
+	printf("  Class:                             %s\n", elf_classToStr(header.e_ident[EI_CLASS]));
+	printf("  Data:                              %s\n", elf_dataToStr(header.e_ident[EI_DATA]));
+	printf("  Version:                           %s\n", elf_versionToStr(header.e_ident[EI_VERSION]));
+	printf("  OS/ABI:                            %s\n", elf_osabiToStr(header.e_ident[EI_OSABI]));
+	printf("  ABI Version:                       %u\n", header.e_ident[EI_ABIVERSION]);
+
+	if (header.e_ident[EI_CLASS] != ELFCLASS64) {
+		return 0;
 	}
 
-	/* Read the section headers */
-	printf("\033[1mSection Headers\033[0m\n");
-	for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
-		if (header->e_shoff + x > binary_size) {
-			printf("Tried to read beyond the end of the file.\n");
-			return 1;
-		}
-		Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x));
+	/* Byte-order dependent from here on out... */
+	printf("  Type:                              %s\n", elf_typeToStr(header.e_type));
+	printf("  Machine:                           %s\n", elf_machineToStr(header.e_machine));
+	printf("  Version:                           0x%x\n", header.e_version);
+	printf("  Entry point address:               0x%lx\n", header.e_entry);
+	printf("  Start of program headers:          %lu (bytes into file)\n", header.e_phoff);
+	printf("  Start of section headers:          %lu (bytes into file)\n", header.e_shoff);
+	printf("  Flags:                             0x%x\n", header.e_flags);
+	printf("  Size of this header:               %u (bytes)\n", header.e_ehsize);
+	printf("  Size of program headers:           %u (bytes)\n", header.e_phentsize);
+	printf("  Number of program headers:         %u\n", header.e_phnum);
+	printf("  Size of section headers:           %u (bytes)\n", header.e_shentsize);
+	printf("  Number of section headers:         %u\n", header.e_shnum);
+	printf("  Section header string table index: %u\n", header.e_shstrndx);
 
-		printf("[%d] %s\n", (unsigned int)shdr->sh_type, (char *)((uintptr_t)string_table + shdr->sh_name));
-		printf("Section starts at 0x%x and is 0x%x bytes long.\n", (unsigned int)shdr->sh_offset, (unsigned int)shdr->sh_size);
-		if (shdr->sh_addr) {
-			printf("It should be loaded at 0x%x.\n", (unsigned int)shdr->sh_addr);
-		}
+	/* Get the section header string table */
+	Elf64_Shdr shstr_hdr;
+	fseek(f, header.e_shoff + header.e_shentsize * header.e_shstrndx, SEEK_SET);
+	fread(&shstr_hdr, sizeof(Elf64_Shdr), 1, f);
+
+	char * stringTable = malloc(shstr_hdr.sh_size);
+	fseek(f, shstr_hdr.sh_offset, SEEK_SET);
+	fread(stringTable, shstr_hdr.sh_size, 1, f);
+
+	/**
+	 * Section Headers
+	 */
+	printf("\nSection Headers:\n");
+	printf("  [Nr] Name              Type             Address           Offset\n");
+	printf("       Size              EntSize          Flags  Link  Info  Align\n");
+	for (unsigned int i = 0; i < header.e_shnum; ++i) {
+		fseek(f, header.e_shoff + header.e_shentsize * i, SEEK_SET);
+		Elf64_Shdr sectionHeader;
+		fread(&sectionHeader, sizeof(Elf64_Shdr), 1, f);
+
+		printf("  [%2d] %-17.17s %-16.16s %016lx  %08lx\n",
+			i, stringTable + sectionHeader.sh_name, sectionHeaderTypeToStr(sectionHeader.sh_type),
+			sectionHeader.sh_addr, sectionHeader.sh_offset);
+		printf("       %016lx  %016lx %4ld %6d %5d %5ld\n",
+			sectionHeader.sh_size, sectionHeader.sh_entsize, sectionHeader.sh_flags,
+			sectionHeader.sh_link, sectionHeader.sh_info, sectionHeader.sh_addralign);
 	}
 
-#if 1
-	printf("\033[1mSymbol Tables\033[0m\n");
-	for (uint32_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
-		if (header->e_shoff + x > binary_size) {
-			printf("Tried to read beyond the end of the file.\n");
-			return 1;
-		}
-		Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)binary_buf + (header->e_shoff + x));
+	/**
+	 * Program Headers
+	 */
+	if (header.e_phoff && header.e_phnum) {
+		printf("\nProgram Headers:\n");
+		printf("  Type           Offset             VirtAddr           PhysAddr\n");
+		printf("                 FileSiz            MemSiz              Flags  Align\n");
+		for (unsigned int i = 0; i < header.e_phnum; ++i) {
+			fseek(f, header.e_phoff + header.e_phentsize * i, SEEK_SET);
+			Elf64_Phdr programHeader;
+			fread(&programHeader, sizeof(Elf64_Phdr), 1, f);
 
-		if (shdr->sh_type == SHT_SYMTAB) {
-			printf("Found symbol table: %s\n", (char *)((uintptr_t)string_table + shdr->sh_name));
+			printf("  %-14.14s 0x%016lx 0x%016lx 0x%016lx\n",
+				programHeaderTypeToStr(programHeader.p_type),
+				programHeader.p_offset, programHeader.p_vaddr, programHeader.p_paddr);
+			printf("                 0x%016lx 0x%016lx  %s 0x%lx\n",
+				programHeader.p_filesz, programHeader.p_memsz,
+				programHeaderFlagsToStr(programHeader.p_flags), programHeader.p_align);
 
-			Elf32_Sym * table = (Elf32_Sym *)((uintptr_t)binary_buf + (shdr->sh_offset));
-			while ((uintptr_t)table - ((uintptr_t)binary_buf + shdr->sh_offset) < shdr->sh_size) {
-				printf("%s: 0x%x [0x%x]\n", (char *)((uintptr_t)sym_string_table + table->st_name), (unsigned int)table->st_value, (unsigned int)table->st_size);
-				table++;
+			if (programHeader.p_type == PT_INTERP) {
+				/* Read interpreter string */
+				char * tmp = malloc(programHeader.p_filesz);
+				fseek(f, programHeader.p_offset, SEEK_SET);
+				fread(tmp, programHeader.p_filesz, 1, f);
+				printf("    [Requesting program interpreter: %.*s]\n",
+					(int)programHeader.p_filesz, tmp);
+				free(tmp);
 			}
 		}
 	}
-#endif
+
+	/* TODO Section to segment mapping? */
+
+	/**
+	 * Dump section information.
+	 */
+	for (unsigned int i = 0; i < header.e_shnum; ++i) {
+		fseek(f, header.e_shoff + header.e_shentsize * i, SEEK_SET);
+		Elf64_Shdr sectionHeader;
+		fread(&sectionHeader, sizeof(Elf64_Shdr), 1, f);
+
+		/* I think there should only be one of these... */
+		switch (sectionHeader.sh_type) {
+			case SHT_DYNAMIC:
+				{
+					printf("\nDynamic section at offset 0x%lx contains (up to) %ld entries:\n",
+						sectionHeader.sh_offset, sectionHeader.sh_size / sectionHeader.sh_entsize);
+					printf("  Tag        Type                         Name/Value\n");
+
+					/* Read the linked string table */
+					Elf64_Shdr dynstr;
+					fseek(f, header.e_shoff + header.e_shentsize * sectionHeader.sh_link, SEEK_SET);
+					fread(&dynstr, sizeof(Elf64_Shdr), 1, f);
+					char * dynStr = malloc(dynstr.sh_size);
+					fseek(f, dynstr.sh_offset, SEEK_SET);
+					fread(dynStr, dynstr.sh_size, 1, f);
+
+					char * dynTable = malloc(sectionHeader.sh_size);
+					fseek(f, sectionHeader.sh_offset, SEEK_SET);
+					fread(dynTable, sectionHeader.sh_size, 1, f);
+
+					for (unsigned int i = 0; i < sectionHeader.sh_size / sectionHeader.sh_entsize; i++) {
+						Elf64_Dyn * dynEntry = (Elf64_Dyn *)(dynTable + sectionHeader.sh_entsize * i);
+
+						printf(" 0x%016lx %s\n",
+							dynEntry->d_tag,
+							dynamicTagToStr(dynEntry, dynStr));
+
+						if (dynEntry->d_tag == DT_NULL) break;
+					}
+
+					free(dynStr);