Integrated support for Red Lizzard's "goanna" static analysis tool

Initial support (activate with "-o analyze"). Not working well with IAR
for now (partially because of a bug in goannac++ which was reported to
Red Lizzard).
pull/93/head
Bogdan Marinescu 2013-10-14 17:32:41 +03:00
parent 330e59fb85
commit 62f1ac097d
5 changed files with 68 additions and 16 deletions

View File

@ -35,6 +35,6 @@ def get_default_options_parser():
help="clean the build directory")
parser.add_option("-o", "--options", action="append",
help='Add a build option ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information)')
help='Add a build option ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run static code analyzer")')
return parser

View File

@ -26,6 +26,7 @@ from workspace_tools.patch import patch
from workspace_tools.settings import BUILD_OPTIONS
import workspace_tools.hooks as hooks
import re
def print_notify(event):
# Default command line notification
@ -141,7 +142,10 @@ class mbedToolchain:
"Cortex-M0+": ["__CORTEX_M0PLUS", "ARM_MATH_CM0"],
"Cortex-M4" : ["__CORTEX_M4", "ARM_MATH_CM4", "__FPU_PRESENT=1"],
}
GOANNA_FORMAT = "[Goanna] warning [%FILENAME%:%LINENO%] - [%CHECKNAME%(%SEVERITY%)] %MESSAGE%"
GOANNA_DIAGNOSTIC_PATTERN = re.compile(r'"\[Goanna\] (?P<severity>warning) \[(?P<file>[^:]+):(?P<line>\d+)\] \- (?P<message>.*)"')
def __init__(self, target, options=None, notify=None):
self.target = target
self.name = self.__class__.__name__
@ -168,6 +172,12 @@ class mbedToolchain:
self.labels = None
self.build_all = False
def goanna_parse_line(self, line):
if "analyze" in self.options:
return self.GOANNA_DIAGNOSTIC_PATTERN.match(line)
else:
return None
def get_symbols(self):
if self.symbols is None:

View File

@ -20,6 +20,7 @@ from os.path import join
from workspace_tools.toolchains import mbedToolchain
from workspace_tools.settings import ARM_BIN, ARM_INC, ARM_LIB, MY_ARM_CLIB, ARM_CPPLIB
from workspace_tools.hooks import hook_tool
from workspace_tools.settings import GOANNA_PATH
class ARM(mbedToolchain):
LINKER_EXT = '.sct'
@ -39,7 +40,8 @@ class ARM(mbedToolchain):
else:
cpu = target.core
common = [join(ARM_BIN, "armcc"), "-c",
main_cc = join(ARM_BIN, "armcc")
common = ["-c",
"--cpu=%s" % cpu, "--gnu",
"-Ospace", "--split_sections", "--apcs=interwork",
"--brief_diagnostics", "--restrict"
@ -56,9 +58,13 @@ class ARM(mbedToolchain):
'-I%s' % ARM_INC
]
self.asm = common
self.cc = common + common_c + ["--c99"]
self.cppc = common + common_c + ["--cpp", "--no_rtti"]
self.asm = [main_cc] + common
if not "analyze" in self.options:
self.cc = [main_cc] + common + common_c + ["--c99"]
self.cppc = [main_cc] + common + common_c + ["--cpp", "--no_rtti"]
else:
self.cc = [join(GOANNA_PATH, "goannacc"), "--with-cc=" + main_cc.replace('\\', '/'), "--dialect=armcc", '--output-format="%s"' % self.GOANNA_FORMAT] + common + common_c + ["--c99"]
self.cppc= [join(GOANNA_PATH, "goannac++"), "--with-cxx=" + main_cc.replace('\\', '/'), "--dialect=armcc", '--output-format="%s"' % self.GOANNA_FORMAT] + common + common_c + ["--cpp", "--no_rtti"]
self.ld = [join(ARM_BIN, "armlink")]
self.sys_libs = []
@ -92,7 +98,15 @@ class ARM(mbedToolchain):
match.group('line'),
match.group('message')
)
match = self.goanna_parse_line(line)
if match is not None:
self.cc_info(
match.group('severity').lower(),
match.group('file'),
match.group('line'),
match.group('message')
)
def archive(self, objects, lib_path):
self.default_cmd([self.ar, '-r', lib_path] + objects)

View File

@ -19,7 +19,7 @@ from os.path import join, basename, splitext
from workspace_tools.toolchains import mbedToolchain
from workspace_tools.settings import GCC_ARM_PATH, GCC_CR_PATH, GCC_CS_PATH, CW_EWL_PATH, CW_GCC_PATH
from workspace_tools.settings import GOANNA_PATH
class GCC(mbedToolchain):
LINKER_EXT = '.ld'
@ -59,11 +59,17 @@ class GCC(mbedToolchain):
if "debug-info" in self.options:
common_flags.append("-g")
self.asm = [join(tool_path, "arm-none-eabi-as")] + self.cpu
self.cc = [join(tool_path, "arm-none-eabi-gcc"), "-std=gnu99"] + common_flags
self.cppc =[join(tool_path, "arm-none-eabi-g++"), "-std=gnu++98"] + common_flags
main_cc = join(tool_path, "arm-none-eabi-gcc")
main_cppc = join(tool_path, "arm-none-eabi-g++")
if not "analyze" in self.options:
self.cc = [main_cc, "-std=gnu99"] + common_flags
self.cppc =[main_cppc, "-std=gnu++98"] + common_flags
else:
self.cc = [join(GOANNA_PATH, "goannacc"), "--with-cc=" + main_cc.replace('\\', '/'), "-std=gnu99", "--dialect=gnu", '--output-format="%s"' % self.GOANNA_FORMAT] + common_flags
self.cppc= [join(GOANNA_PATH, "goannac++"), "--with-cxx=" + main_cppc.replace('\\', '/'), "-std=gnu++98", "--dialect=gnu", '--output-format="%s"' % self.GOANNA_FORMAT] + common_flags
self.ld = [join(tool_path, "arm-none-eabi-gcc"), "-Wl,--gc-sections", "-Wl,--wrap,main"] + self.cpu
self.sys_libs = ["stdc++", "supc++", "m", "c", "gcc"]
@ -98,6 +104,16 @@ class GCC(mbedToolchain):
WHERE, WHAT = 0, 1
state, file, message = WHERE, None, None
for line in output.splitlines():
match = self.goanna_parse_line(line)
if match is not None:
self.cc_info(
match.group('severity').lower(),
match.group('file'),
match.group('line'),
match.group('message')
)
continue
# Each line should start with the file information: "filepath: ..."
# i should point past the file path ^
# avoid the first column in Windows (C:\)

View File

@ -20,7 +20,7 @@ from os.path import join, exists
from workspace_tools.toolchains import mbedToolchain
from workspace_tools.settings import IAR_PATH
from workspace_tools.settings import GOANNA_PATH
class IAR(mbedToolchain):
LIBRARY_EXT = '.a'
@ -49,10 +49,14 @@ class IAR(mbedToolchain):
c_flags.append("-r")
IAR_BIN = join(IAR_PATH, "bin")
main_cc = join(IAR_BIN, "iccarm")
self.asm = [join(IAR_BIN, "iasmarm")] + ["--cpu", target.core]
self.cc = [join(IAR_BIN, "iccarm")] + c_flags
self.cppc = [join(IAR_BIN, "iccarm"), "--c++", "--no_rtti", "--no_exceptions"] + c_flags
if not "analyze" in self.options:
self.cc = [main_cc] + c_flags
self.cppc = [main_cc, "--c++", "--no_rtti", "--no_exceptions"] + c_flags
else:
self.cc = [join(GOANNA_PATH, "goannacc"), '--with-cc="%s"' % main_cc.replace('\\', '/'), "--dialect=iar-arm", '--output-format="%s"' % self.GOANNA_FORMAT] + c_flags
self.cppc = [join(GOANNA_PATH, "goannac++"), '--with-cxx="%s"' % main_cc.replace('\\', '/'), "--dialect=iar-arm", '--output-format="%s"' % self.GOANNA_FORMAT] + ["--c++", "--no_rtti", "--no_exceptions"] + c_flags
self.ld = join(IAR_BIN, "ilinkarm")
self.ar = join(IAR_BIN, "iarchive")
self.elf2bin = join(IAR_BIN, "ielftool")
@ -67,6 +71,14 @@ class IAR(mbedToolchain):
match.group('line'),
match.group('message'),
)
match = self.goanna_parse_line(line)
if match is not None:
self.cc_info(
match.group('severity').lower(),
match.group('file'),
match.group('line'),
match.group('message')
)
def get_dep_opt(self, dep_path):
return ["--dependencies", dep_path]