summarylogtreecommitdiffstats
path: root/mhwd-nvidia
blob: 65c344386287dbdebf06a1ee270c6105f2901b3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/bin/sh

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

set -e

# This is a nasty kluge, but it seems to work. Better check the output when
# upgrading to a new release of the nvidia driver, though.

if [ "$#" -ne 2 ]; then
  >&2 printf 'USAGE: %s README.txt nv-kernel.o\n' "$0"
  exit 1
fi

device_ids() {
  local readme="$1"; shift
  local object="$1"; shift

  local ret=1

  local symbols="$(mktemp)"
  local readme_list="$(mktemp)"
  local object_list="$(mktemp)"
  local diff="$(mktemp)"

  sed -nr '/^Appendix .\. Supported NVIDIA /,/legacy/ {
    s/.*   ([0-9a-fA-F]{4})(   .*|$)/\1/p
  }' "$readme" | tr A-F a-f | sort | uniq >"$readme_list"

  local readme_length="$(grep -Ec . "$readme_list")"

  objdump --section=.rodata --syms "$object" |
  sed -nr '/SYMBOL TABLE/,/^$/ {
    s/^([0-9a-f]+)\s+l\s+O\s+\S+\s+([0-9a-f]+)\s+\S+.*/\2 \1/p
  }' |
  sort -nr >"$symbols" # The list is probably among the larger symbols.

  while read length start; do
    [ "$((0x$length))" -gt 0 ] || continue

    objdump --section=.rodata --full-contents \
      --start-address="0x$start" \
      --stop-address="$((0x$start+0x$length))" "$object" |
    sed -nr 's/^ [0-9a-f]+ ([0-9a-f]{2})([0-9a-f]{2}).*/\2\1/p' |
    sort | uniq | (grep -vx 0000 || :) >"$object_list"

    local object_length="$(grep -Ec . "$object_list")"

    diff -u "$readme_list" "$object_list" | tail -n +3 >"$diff"
    local num_deletions="$(grep -Ec '^-' "$diff")"
    local num_additions="$(grep -Ec '^\+' "$diff")"

    # Some thresholds for now.
    if [ "$num_deletions" -eq 0 ] &&
       [ "$num_additions" -le "$(($readme_length*3/2))" ]; then
      >&2 printf 'DEBUG: readme:%d object:%d deletions:%d additions:%d\n' \
        "$readme_length" "$object_length" "$num_deletions" "$num_additions"
      ret=0
      break
    fi
  done <"$symbols"

  if [ "$ret" -eq 0 ]; then
    printf '%s\n' '# List generated by mhwd. Do not edit manually.'

    while read id; do
      printf "$id "
    done <"$object_list"

  else
    >&2 printf '%s\n' 'Failed to find the list. Using README.txt to get the list'

    # We failed to extract the ids from the blob. Use the ones in README.txt
    # as a fallback
    printf '%s\n' '# List generated by mhwd. Do not edit manually.'
    while read id; do
      printf "$id "
    done <"$readme_list"
    # fix Geforce mobile + Quadro K3100M
    printf "1140 11a0 11b6 2486" <"$readme_list"

    ret=0
  fi

  rm -f "$symbols" "$readme_list" "$object_list" "$diff"

  return "$ret"
}

device_ids "$@"

# vim:set et sw=2 sts=2: