All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Bara <bbara93@gmail.com>
To: openembedded-core@lists.openembedded.org
Cc: Benjamin Bara <benjamin.bara@skidata.com>
Subject: [PATCH] insane.bbclass: introduce SIGILL finder
Date: Thu, 31 Aug 2023 11:16:18 +0200	[thread overview]
Message-ID: <20230831091618.3715995-1-bbara93@gmail.com> (raw)

From: Benjamin Bara <benjamin.bara@skidata.com>

This commit should look for unsupported instructions depending on the
active tune features. For now, it checks for vfpv3d16 and other non-neon
machines, but it can be easily extended for other architectures/checks.

Reason for this check is that a couple of packages assume neon support
for armv7, but it is actually optional.

Signed-off-by: Benjamin Bara <benjamin.bara@skidata.com>
---
Hi,

as I lately played a little bit around with a vfpv3d16 machine and some
multimedia packages, I stumbled across a couple of illegal instructions
during runtime. Therefore I decided to hack a QA job which should find
these during package time. Not sure if this is the correct location to
do such a check and if this is something needed at all...

Regards,
Benjamin
---
 meta/classes-global/insane.bbclass | 78 +++++++++++++++++++++++++++++-
 meta/lib/oe/qa.py                  | 34 +++++++++++++
 2 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/meta/classes-global/insane.bbclass b/meta/classes-global/insane.bbclass
index 2e53778934..5b9112d05c 100644
--- a/meta/classes-global/insane.bbclass
+++ b/meta/classes-global/insane.bbclass
@@ -44,7 +44,7 @@ ERROR_QA ?= "dev-so debug-deps dev-deps debug-files arch pkgconfig la \
             configure-gettext perllocalpod shebang-size \
             already-stripped installed-vs-shipped ldflags compile-host-path \
             install-host-path pn-overrides unknown-configure-option \
-            useless-rpaths rpaths staticdev empty-dirs \
+            useless-rpaths rpaths staticdev empty-dirs sigill \
             patch-fuzz \
             "
 # Add usrmerge QA check based on distro feature
@@ -635,6 +635,82 @@ def check_32bit_symbols(path, packagename, d, elf, messages):
                     'Suppress with INSANE_SKIP = "32bit-time"'
                 )
 
+QAPATHTEST[sigill] = "package_qa_check_sigill"
+def package_qa_check_sigill(path, name, d, elf, messages):
+    """
+    Check that the package doesn't contain unsupported instructions.
+    """
+    import re
+
+    if not elf:
+        return
+
+    if os.path.islink(path):
+        return
+
+    def test_skeleton(grep, test):
+        dump = elf.run_filtered_objdump_unstripped("-d", grep, d, name)
+        if dump == 'stripped':
+            # stripped binaries might give false positives
+            return
+
+        # get all instructions and registers from the disassembled binary
+        instr_list = []
+        regs_list = []
+        for line in dump.split("\\n"):
+            splitted = dump.split("\\t")
+            if len(splitted) < 3:
+                continue
+            # 0 is just empty, as line starts with \t
+            instr_list.append(splitted[1])
+            regs_list.append(splitted[2])
+
+        # loop through instr+regs list and apply the given test function
+        uniques = set()
+        for index, regs in enumerate(regs_list):
+            instr = instr_list[index]
+            affected = test(instr, regs)
+            if affected:
+                uniques.add(f"{instr} {regs}")
+
+        for instr_regs in uniques:
+            oe.qa.add_message(messages, "sigill", "%s contains %s" % (path, instr_regs))
+
+    features = d.getVar('TUNE_FEATURES')
+    if "vfpv3d16" in features:
+        # grep for d16-d31, d0-d15 are valid for f64 instructions
+        vfpv3d16_grep = "f64\s+(d1|d2|d3)"
+
+        def vfpv3d16_test(instr, regs):
+            for reg in re.findall(r'd(\d+)', regs):
+                return int(reg) >= 16
+
+        test_skeleton(vfpv3d16_grep, vfpv3d16_test)
+
+    if "armv7a" in features and "neon" not in features:
+        # https://developer.arm.com/documentation/den0018/a/NEON-and-VFP-Instruction-Summary/List-of-all-NEON-and-VFP-instructions
+        neon_instrs = ["vq?r?shl", "vq?abs", "vq?add", "vq?movn", "vq?sub",
+                       "vr?addhn", "vr?hadd", "vr?shrn?", "vr?sra", "vr?subhn",
+                       "vabal?", "vabdl?", "vacge", "vacgt", "vacle", "vaclt",
+                       "vaddl", "vaddw", "vand", "vbic", "vbif", "vbit", "vceq",
+                       "vcge", "vcgt", "vcle", "vcls", "vclt", "vclz", "vcnt",
+                       "vdup", "veor", "vext", "vhsub", "vmax", "vmin", "vmlal",
+                       "vmlsl", "vmov2", "vmovl", "vmull", "vmvn", "vqneg",
+                       "vorn", "vorr", "vpadal", "vpaddl?", "vpmax", "vpmin",
+                       "vqr?dmulh", "vqr?shru?n", "vqdmlal", "vqdmlsl",
+                       "vqdmull", "vqmovun", "vqshl", "vqshlu", "vcrecpe",
+                       "vcrecps", "vrev", "vrsqrte", "vrsqrts", "vshl", "vshll",
+                       "vsli", "vsri", "vsubl", "vsubw", "vswp", "vtbl", "vtbx",
+                       "vtrn", "vtst", "vuzp", "vzip"]
+        # most of them are only NEON when the used data type isn't floating-point
+        neon_grep = "\s(" + "|".join(neon_instrs) + ")\.(s|u|p)"
+
+        def neon_test(instr, regs):
+            # if something is found by the grep, the package is affected
+            return True
+
+        test_skeleton(neon_grep, neon_test)
+
 # Check license variables
 do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
 python populate_lic_qa_checksum() {
diff --git a/meta/lib/oe/qa.py b/meta/lib/oe/qa.py
index de980638c4..075622c98f 100644
--- a/meta/lib/oe/qa.py
+++ b/meta/lib/oe/qa.py
@@ -157,6 +157,40 @@ class ELFFile:
             bb.note("%s %s %s failed: %s" % (objdump, cmd, self.name, e))
             return ""
 
+    def run_filtered_objdump_unstripped(self, cmd, filter, d, pn):
+        import bb.process
+        import sys
+
+        objdump = d.getVar('OBJDUMP')
+
+        # we require the unstripped binary here, as objdump might have problems
+        # detecting the correct instruction format, which leads to false positives
+        name = self.name.replace(d.getVar('PKGDEST') + '/' + pn, d.getVar('D'))
+
+        env = os.environ.copy()
+        env["LC_ALL"] = "C"
+        env["PATH"] = d.getVar('PATH')
+
+        # ensure that binary is unstripped
+        try:
+            bb.note("file %s" % (name))
+            output = bb.process.run(["file", name], env=env, shell=False)[0]
+            if ", stripped" in output:
+                return "stripped"
+        except Exception as e:
+            bb.note("file %s failed: %s" % (name, e))
+            return ""
+
+        try:
+            bb.note("%s %s %s | grep -E %s" % (objdump, cmd, name, filter))
+            objdump_proc = bb.process.Popen([objdump, cmd, "--no-addresses", "--no-show-raw-insn", name], env=env, shell=False)
+            grep_proc = bb.process.Popen(["grep", "-E", filter], env=env, shell=False, stdin=objdump_proc.stdout)
+            objdump_proc.stdout.close()
+            return str(grep_proc.communicate()[0])
+        except Exception as e:
+            bb.note("%s %s %s failed: %s" % (objdump, cmd, name, e))
+            return ""
+
 def elf_machine_to_string(machine):
     """
     Return the name of a given ELF e_machine field or the hex value as a string
-- 
2.34.1



             reply	other threads:[~2023-08-31  9:16 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-08-31  9:16 Benjamin Bara [this message]
2023-08-31  9:24 ` [OE-core] [PATCH] insane.bbclass: introduce SIGILL finder Alexander Kanavin
2023-08-31 10:22   ` Benjamin Bara
2023-09-01 10:19 ` Ross Burton
2023-09-04  7:39   ` Benjamin Bara

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230831091618.3715995-1-bbara93@gmail.com \
    --to=bbara93@gmail.com \
    --cc=benjamin.bara@skidata.com \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.