#!/usr/bin/env bash

# Copyright 2017 The Fuchsia Authors
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT

header() {
  echo "// This file is generated by $0.  DO NOT EDIT."
  echo
  echo '#include <stdint.h>'
  echo '#include "vdso-code.h"'
  echo
  echo "\
struct VDso::ValidSyscallPC {
"
}

footer() {
  echo '};'
}

scan() {
  local define symbol rest syscall caller
  local syscalls=''

  while read define symbol rest; do
    case "$symbol" in
    VDSO_CODE_SYSRET_*) ;;
    *) continue ;;
    esac

    syscall="${symbol#VDSO_CODE_SYSRET_zx_}"
    caller="${syscall#*_VIA_}"
    syscall="${syscall%_VIA_*}"
    if eval "test -z \"\$syscall_callers_${syscall}\""; then
      syscalls+=" $syscall"
      eval "local syscall_callers_${syscall}=\$caller"
    else
      eval "syscall_callers_${syscall}+=\" \$caller\""
    fi
  done

  for syscall in $syscalls; do
    echo "\
    static bool ${syscall}(uintptr_t offset) {
        switch (offset) {\
"
    eval "local callers=\$syscall_callers_$syscall"
    for caller in $callers; do
      echo "\
        case VDSO_CODE_SYSRET_zx_${syscall}_VIA_${caller} - VDSO_CODE_START:
            return true;\
"
    done
    echo "\
        }
        return false;
    }
"
  done
}

set -e

case $# in
1)
  exec < "$1"
  ;;
2)
  trap "rm -f '$2'" ERR HUP INT TERM
  exec < "$1" > "$2"
  ;;
esac

header
scan < "$1"
footer
