svn commit: r363948 - in head/science: . sigrok-firmware-utils sigrok-firmware-utils/files

John Marino marino at FreeBSD.org
Sun Aug 3 22:09:10 UTC 2014


Author: marino
Date: Sun Aug  3 22:09:07 2014
New Revision: 363948
URL: http://svnweb.freebsd.org/changeset/ports/363948
QAT: https://qat.redports.org/buildarchive/r363948/

Log:
  Add new port: science/sigrok-firmware-utils
  
  PR:		188808
  Submitted by:	uffer
  
        ===============================================================
  
  The sigrok project aims at creating a portable, cross-platform,
  Free/Libre/Open-Source signal analysis software suite that supports
  various device types, such as logic analyzers, MSOs, oscilloscopes,
  multimeters, LCR meters, sound level meters, thermometers, hygrometers,
  anemometers, light meters, DAQs, dataloggers, function generators,
  spectrum analyzers, power supplies, GPIB interfaces, and more.

Added:
  head/science/sigrok-firmware-utils/
  head/science/sigrok-firmware-utils/Makefile   (contents, props changed)
  head/science/sigrok-firmware-utils/files/
  head/science/sigrok-firmware-utils/files/README.parsepe   (contents, props changed)
  head/science/sigrok-firmware-utils/files/parseelf.py   (contents, props changed)
  head/science/sigrok-firmware-utils/files/parsepe.py   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso.1   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16.1   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla   (contents, props changed)
  head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla.1   (contents, props changed)
  head/science/sigrok-firmware-utils/pkg-descr   (contents, props changed)
Modified:
  head/science/Makefile

Modified: head/science/Makefile
==============================================================================
--- head/science/Makefile	Sun Aug  3 22:04:34 2014	(r363947)
+++ head/science/Makefile	Sun Aug  3 22:09:07 2014	(r363948)
@@ -173,6 +173,7 @@
     SUBDIR += rubygem-ai4r
     SUBDIR += rubygem-netcdf
     SUBDIR += sigrok-cli
+    SUBDIR += sigrok-firmware-utils
     SUBDIR += silo
     SUBDIR += simlib
     SUBDIR += simsmith

Added: head/science/sigrok-firmware-utils/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/Makefile	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,43 @@
+# Created by: Uffe Jakobsen <uffe at uffe.org>
+# $FreeBSD$
+
+PORTNAME=	firmware
+PORTVERSION=	20140418
+CATEGORIES=	science
+MASTER_SITES=	#none
+PKGNAMEPREFIX=	sigrok-
+PKGNAMESUFFIX=	-utils
+DISTFILES=	#none
+
+MAINTAINER=	uffe at uffe.org
+COMMENT=	Sigrok firmware extraction utils
+
+LICENSE=	GPLv2
+
+USE_PYTHON=	3
+NO_BUILD=	yes
+
+PORTDOCS=	README.parsepe
+
+PY_FILES=	parsepe.py parseelf.py
+
+EX_FILES=	sigrok-fwextract-hantek-dso \
+		sigrok-fwextract-saleae-logic16 \
+		sigrok-fwextract-sysclk-lwla
+
+PLIST_FILES=	${PY_FILES:S,^,bin/,} \
+		${EX_FILES:S,^,bin/,} \
+		${EX_FILES:S,^,man/man1/,:S,$,.1.gz,}
+
+do-install:
+	@${MKDIR} ${STAGEDIR}${DOCSDIR}
+	${INSTALL_MAN} ${FILESDIR}/README.parsepe ${STAGEDIR}${DOCSDIR}
+.for fil in ${PY_FILES}
+	${INSTALL_SCRIPT} ${FILESDIR}/${fil} ${STAGEDIR}${PREFIX}/bin
+.endfor
+.for fil in ${EX_FILES}
+	${INSTALL_SCRIPT} ${FILESDIR}/${fil} ${STAGEDIR}${PREFIX}/bin
+	${INSTALL_MAN} ${FILESDIR}/${fil}.1 ${STAGEDIR}${MANDIRS}/man1
+.endfor
+
+.include <bsd.port.mk>

Added: head/science/sigrok-firmware-utils/files/README.parsepe
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/README.parsepe	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,11 @@
+The parsepe.py tool can list all sections and symbols from a PE (portable
+executable) binary file, and extract the contents of a symbol.
+
+usage:
+parsepe.py -l <filename>                list all sections and symbols in file
+parsepe.py -s <symbol> -x <filename>    extract symbol from file
+
+TODO:
+- currently only handles COFF symbol tables
+- can only extract external (global) symbols
+

Added: head/science/sigrok-firmware-utils/files/parseelf.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/parseelf.py	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,172 @@
+#!/usr/bin/env python3
+##
+## This file is part of the sigrok-util project.
+##
+## Copyright (C) 2013 Marcus Comstedt <marcus at mc.pp.se>
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+import struct
+
+class elf:
+
+    def read_struct(this, struct_fmt, struct_fields):
+        fmt = this.elf_endianprefix+str.translate(struct_fmt, this.elf_format);
+        fields = struct.unpack(fmt, this.file.read(struct.calcsize(fmt)))
+        return dict(zip(struct_fields, fields))
+
+    def read_ehdr(this):
+        return this.read_struct('16sHHWNNNWHHHHHH',
+                                ('e_ident', 'e_type', 'e_machine', 'e_version',
+                                 'e_entry', 'e_phoff', 'e_shoff', 'e_flags',
+                                 'e_ehsize', 'e_phentsize', 'e_phnum',
+                                 'e_shentsize', 'e_shnum', 'e_shstrndx'))
+
+    def read_shdr(this):
+        return this.read_struct('WWNNNNWWNN',
+                                ('sh_name', 'sh_type', 'sh_flags', 'sh_addr',
+                                 'sh_offset', 'sh_size', 'sh_link', 'sh_info',
+                                 'sh_addralign', 'sh_entsize'))
+
+    def read_section(this, shdr):
+        this.file.seek(shdr['sh_offset'])
+        return this.file.read(shdr['sh_size'])
+
+    def get_name(this, name, strtab=None):
+        strtab = strtab or this.strtab
+        nul = strtab.find(b'\0', name)
+        if nul < 0:
+            return bytes.decode(strtab[name:])
+        else:
+            return bytes.decode(strtab[name:nul])
+
+    def find_section(this, name):
+        for section in this.shdrs:
+            if this.get_name(section['sh_name']) == name:
+                return section
+        raise KeyError(name)
+
+    def parse_symbol(this):
+        if this.elf_wordsize == 64:
+            return this.read_struct('WBBHNX',
+                                    ('st_name', 'st_info', 'st_other',
+                                     'st_shndx', 'st_value', 'st_size'))
+        else:
+            return this.read_struct('WNWBBH',
+                                    ('st_name', 'st_value', 'st_size',
+                                     'st_info', 'st_other', 'st_shndx'))
+
+    def parse_rela(this):
+        return this.read_struct('NNn', ('r_offset', 'r_info', 'r_addend'))
+
+    def parse_rel(this):
+        return this.read_struct('NN', ('r_offset', 'r_info'))
+
+    def fixup_reloc(this, reloc):
+        if not 'r_addend' in reloc:
+            reloc['r_addend'] = 0
+        if this.elf_wordsize == 64:
+            reloc['r_sym'] = reloc['r_info'] >> 32
+            reloc['r_type'] = reloc['r_info'] & 0xffffffff
+        else:
+            reloc['r_sym'] = reloc['r_info'] >> 8
+            reloc['r_type'] = reloc['r_info'] & 0xff
+        return reloc
+
+    def parse_symbols(this, symsecname, strsecname):
+        try:
+            symsechdr = this.find_section(symsecname)
+            strsechdr = this.find_section(strsecname)
+        except KeyError:
+            return {}
+        strsec = this.read_section(strsechdr)
+        this.file.seek(symsechdr['sh_offset'])
+        syms = [dict(this.parse_symbol(),number=i) for i in
+                range(0, symsechdr['sh_size'] // symsechdr['sh_entsize'])]
+        return {this.get_name(sym['st_name'], strsec): sym for sym in syms}
+
+    def parse_relocs(this, section):
+        this.file.seek(section['sh_offset'])
+        if section['sh_type'] == 4:
+            relocs = [this.fixup_reloc(this.parse_rela()) for i in
+                      range(0, section['sh_size'] // section['sh_entsize'])]
+        else:
+            relocs = [this.fixup_reloc(this.parse_rel()) for i in
+                      range(0, section['sh_size'] // section['sh_entsize'])]
+        return relocs
+
+    def address_to_offset(this, addr):
+        for section in this.shdrs:
+            if (section['sh_addr'] <= addr and
+                section['sh_addr']+section['sh_size'] > addr):
+                return section['sh_offset']+(addr-section['sh_addr'])
+        raise IndexError('address out of range')
+
+    def load_symbol(this, sym):
+        this.file.seek(this.address_to_offset(sym['st_value']))
+        return this.file.read(sym['st_size'])
+
+    def __init__(this, filename):
+        this.file = open(filename, 'rb')
+        magic = this.file.read(16)
+
+        if magic[:4] != b'\x7fELF':
+            raise Exception("ELF signature not found")
+
+        if magic[4] == 1:
+            this.elf_wordsize = 32
+            nativeint = 'Ii'
+        elif magic[4] == 2:
+            this.elf_wordsize = 64
+            nativeint = 'Qq'
+        else:
+            raise Exception("Invalid ELF file class")
+
+        if magic[5] == 1:
+            this.elf_endianprefix = '<'
+        elif magic[5] == 2:
+            this.elf_endianprefix = '>'
+        else:
+            raise Exception("Invalid ELF data encoding")
+
+        this.elf_format = str.maketrans('HWwXxNn', 'HIiQq'+nativeint)
+
+        this.file.seek(0)
+        this.ehdr = this.read_ehdr()
+        this.file.seek(this.ehdr['e_shoff'])
+        this.shdrs = [this.read_shdr() for i in range(this.ehdr['e_shnum'])]
+
+        this.strtab = this.read_section(this.shdrs[this.ehdr['e_shstrndx']])
+
+        this.symtab = this.parse_symbols('.symtab', '.strtab')
+        this.dynsym = this.parse_symbols('.dynsym', '.dynstr')
+
+        this.relocs = {}
+        for section in this.shdrs:
+            if section['sh_type'] == 4 or section['sh_type'] == 9:
+                rels = {}
+                symsec = this.shdrs[section['sh_link']]
+                if this.get_name(symsec['sh_name']) == '.symtab':
+                    rels['symbols'] = this.symtab
+                elif this.get_name(symsec['sh_name']) == '.dynsym':
+                    rels['symbols'] = this.dynsym
+                rels['relocs'] = this.parse_relocs(section)
+                this.relocs[this.get_name(section['sh_name'])] = rels
+
+    def __del__(this):
+        try:
+            this.file.close()
+        except AttributeError:
+            pass

Added: head/science/sigrok-firmware-utils/files/parsepe.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/parsepe.py	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,183 @@
+#!/usr/bin/env python3
+##
+## This file is part of the sigrok-util project.
+##
+## Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import os
+from getopt import getopt
+import struct
+
+
+def parse(filename):
+	f = open(filename, 'rb')
+	if f.read(2) != b'MZ':
+		raise Exception("MZ signature not found.")
+
+	sections = []
+	# long e_lfanew
+	f.seek(0x3c)
+	pe_ptr = struct.unpack("<L", f.read(4))[0]
+	f.seek(pe_ptr)
+	if f.read(4) != b'\x50\x45\x00\x00':
+		raise Exception("PE signature not found.")
+	# skip Machine
+	f.seek(f.tell() + 2)
+	sections.append(['header', 324, 0])
+	num_sections = struct.unpack("<H", f.read(2))[0]
+	# skip TimeDateStamp
+	f.seek(f.tell() + 4)
+	symboltable_address = struct.unpack("<L", f.read(4))[0]
+	num_symbols = struct.unpack("<L", f.read(4))[0]
+	optheader_size = struct.unpack("<H", f.read(2))[0]
+	# skip past PE header and PE optional header
+	f.seek(f.tell() + 2 + optheader_size)
+
+	for i in range(num_sections):
+		name = f.read(8).decode('ascii', errors='ignore').strip('\x00')
+		# skip past Misc and VirtualAddress
+		f.seek(f.tell() + 8)
+		# SizeOfRawData
+		size = struct.unpack("<L", f.read(4))[0]
+		# PointerToRawData
+		ptr = struct.unpack("<L", f.read(4))[0]
+		# skip to next section header
+		f.seek(f.tell() + 16)
+		sections.append([name, size, ptr])
+
+	symbols = []
+	addr = symboltable_address
+	stringtable_address = symboltable_address + num_symbols * 18
+	for i in range(num_symbols):
+		f.seek(addr)
+		tmp = f.read(8)
+		symaddr = struct.unpack("<L", f.read(4))[0]
+		# skip SectionNumber and Type
+		symtype = struct.unpack("B", f.read(1))[0]
+		f.seek(f.tell() + 4)
+		if tmp[:4] == b'\x00\x00\x00\x00':
+			# symbol name is in the string table
+			straddr = stringtable_address + struct.unpack("<l", tmp[4:])[0]
+			f.seek(straddr)
+			tmpname = f.read(64)
+			name = tmpname[:tmpname.find(b'\x00')]
+		else:
+			name = tmp
+		name = name.decode('ascii', errors='ignore').strip('\x00')
+		# need IMAGE_SYM_CLASS_EXTERNAL
+		if symtype == 0x02:
+			size = 0
+		else:
+			size = None
+		if i != 0 and symbols[-1][2] is not None and symaddr > symbols[-1][1]:
+			symbols[-1][2] = symaddr - symbols[-1][1]
+		symbols.append([name, symaddr, size])
+		addr += 18
+
+	f.close()
+
+	return sections, symbols
+
+
+def list_all(filename):
+	sections, symbols = parse(filename)
+	if sections:
+		print("Sections:\n    Name         Size\t  Position")
+		cnt = 0
+		for name, size, address in sections:
+			print("%-3d %-8s    %5d\t  0x%.8x" % (cnt, name, size, address))
+			cnt += 1
+	if symbols:
+		print("\nSymbol table:\n   Address     Size    Symbol")
+		for symbol, address, size in symbols:
+			if size is not None:
+				sizestr = "%5d" % size
+			else:
+				sizestr = "     "
+			print("0x%.8x  %s    %-8s" % (address, sizestr, symbol))
+		print()
+
+
+def extract_symbol(filename, symbol):
+	sections, symbols = parse(filename)
+	if not symbols:
+		return None
+	data = None
+	for symbolname, address, size in symbols:
+		if symbolname == symbol:
+			if size is None:
+				raise Exception("symbol %s found, but has unknown size")
+			f = open(filename, 'rb')
+			f.seek(address)
+			data = f.read(size)
+			f.close()
+			if len(data) != size:
+				raise Exception("short file")
+			break
+
+	if data is None:
+		raise Exception("symbol %s not found" % symbol)
+
+	return data
+
+
+
+def usage():
+	print("usage: parsepe.py [-s <symbol>] <-l|-x> <filename>")
+	print("  -l   list all sections and symbols in file")
+	print("  -x   extract symbol from file (specify symbol name with -s)")
+	sys.exit()
+
+
+#
+# main
+#
+
+if __name__ == '__main__':
+	filename = symbol = mode = None
+	opts, args = getopt(sys.argv[1:], 's:lx')
+	for opt, arg in opts:
+		if opt == '-s':
+			symbol = arg
+		elif opt == '-l':
+			mode = 'list'
+		elif opt == '-x':
+			mode = 'extract'
+
+	if len(args) != 1:
+		usage()
+	if mode is None and symbol is None:
+		usage()
+
+	try:
+		filename = args[0]
+		if mode == 'list':
+			list_all(filename)
+		elif mode == 'extract':
+			if symbol is None:
+				raise Exception("specify a symbol to extract")
+			data = extract_symbol(filename, symbol)
+			outfile = os.path.splitext(filename)[0] + symbol
+			open(outfile, 'wb').write(data)
+			print("saved %d bytes to %s" % (len(data), outfile))
+		else:
+			raise Exception("specify -l or -x")
+	except Exception as e:
+		print("Error: %s" % str(e))
+
+

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+##
+## This file is part of the sigrok-util project.
+##
+## Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import os
+import re
+import struct
+from array import array
+
+import parsepe
+
+
+def find_model(filename):
+	filename = os.path.split(filename)[-1]
+	m = re.search('^dso([a-z0-9]+)1.sys$', filename, re.I)
+	if m:
+		model = m.group(1).upper()
+		model = model.replace('X86', '').replace('AMD64', '').replace('IA64', '')
+		if model == '520A':
+			model = '5200A'
+	else:
+		model = 'unknown'
+
+	return model
+
+
+def unsparse(data):
+	p = 0
+	maxaddr = 0
+	blob = array('B', [0] * 0x4000)
+	while p <= len(data) and data[p+4] == 0:
+		num_bytes = struct.unpack("<H", data[p:p+2])[0]
+		address = struct.unpack("<H", data[p+2:p+4])[0]
+		chunk = array('B')
+		chunk.frombytes(data[p+5:p+5+num_bytes])
+		p += 22
+
+		if address > 0x4000:
+			# the FX2 only has 16K RAM. other writes are to registers
+			# in the 0xe000 region, skip those
+			continue
+
+		blob[address:address+num_bytes] = chunk
+
+		if address + num_bytes > maxaddr:
+			maxaddr = address + num_bytes
+
+	return blob[:maxaddr].tostring()
+
+
+def usage():
+	print("sigrok-fwextract-hantek-dso <driverfile>")
+	sys.exit()
+
+
+#
+# main
+#
+
+if len(sys.argv) != 2:
+	usage()
+
+try:
+	filename = sys.argv[1]
+	binihx = parsepe.extract_symbol(filename, '_firmware')
+	if binihx is None:
+		raise Exception("no firmware found")
+	blob = unsparse(binihx)
+	outfile = 'hantek-dso-' + find_model(filename) + '.fw'
+	open(outfile, 'wb').write(blob)
+	print("saved %d bytes to %s" % (len(blob), outfile))
+except Exception as e:
+	print("Error: %s" % str(e))

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso.1
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-hantek-dso.1	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,39 @@
+.TH SIGROK\-FWEXTRACT\-HANTEK\-DSO 1 "Aug 08, 2013"
+.SH "NAME"
+sigrok\-fwextract\-hantek\-dso \- Extract Hantek DSO-2xxx/52xx firmware
+.SH "SYNOPSIS"
+.B sigrok\-fwextract\-hantek\-dso [FILE]
+.SH "DESCRIPTION"
+This tool extracts firmware from the driver that comes with the
+Hantek DSO-2xxx/52xx series USB oscilloscopes. Find the 32-bit
+driver installed on the Windows system -- typically called
+.B DSOxxxx1.sys
+or
+.BR DsoxxxxX861.sys ,
+where xxxx is your device's model.
+.PP
+Use it like this:
+.PP
+.B "  $ sigrok-fwextract-hantek-dso Dso2090X861.sys"
+.br
+.RB "  saved 4730 bytes to hantek-dso-2090.fw"
+.PP
+Copy the resulting file over to the location where libsigrok expects
+to find its firmware files. By default this is
+.BR /usr/local/share/sigrok-firmware .
+.SH OPTIONS
+None.
+.SH "EXIT STATUS"
+Exits with 0 on success, 1 on most failures.
+.SH "SEE ALSO"
+\fBsigrok\-fwextract\-saleae\-logic16\fP(1)
+.SH "BUGS"
+Please report any bugs via Bugzilla
+.RB "(" http://sigrok.org/bugzilla ")"
+or on the sigrok\-devel mailing list
+.RB "(" sigrok\-devel at lists.souceforge.net ")."
+.SH "LICENSE"
+This program is covered by the GNU General Public License (GPL),
+version 3 or later.
+.SH "AUTHORS"
+Please see the individual source code files.

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,329 @@
+#!/usr/bin/env python3
+##
+## This file is part of the sigrok-util project.
+##
+## Copyright (C) 2013 Marcus Comstedt <marcus at mc.pp.se>
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+import sys
+import struct
+import parseelf
+
+class searcher:
+
+    def reset(this, offs=0):
+        if offs < 0 or offs > this.length:
+            raise Exception('Reset past end of section')
+        this.address = this.baseaddr + offs
+        this.offset = offs
+
+    def skip(this, cnt):
+        if this.offset + cnt > this.length:
+            raise Exception('Skip past end of section')
+        this.address += cnt
+        this.offset += cnt
+
+    def peek(this, cnt, offs=0):
+        if this.offset + offs + cnt > this.length:
+            raise Exception('Peek past end of section')
+        return this.data[this.offset + offs : this.offset + offs + cnt]
+
+    def look_for(this, needle):
+        pos = this.data.find(needle, this.offset)
+        if pos < 0:
+            raise Exception('Needle not found in haystack')
+        this.skip(pos - this.offset)
+
+    def look_for_either(this, needle1, needle2):
+        pos1 = this.data.find(needle1, this.offset)
+        pos2 = this.data.find(needle2, this.offset)
+        if pos1 < 0 and pos2 < 0:
+            raise Exception('Needle not found in haystack')
+        if pos1 < 0 or pos2 < pos1:
+            pos1 = pos2
+        this.skip(pos1 - this.offset)
+
+    def __init__(this, data, addr):
+        this.data = data
+        this.baseaddr = addr
+        this.length = len(data)
+        this.reset()
+
+def search_plt_32(plt, addr):
+    plt.reset()
+    plt.look_for(struct.pack('<BBI', 0xff, 0x25, addr))	# jmp *addr32
+    return plt.address
+
+def search_plt_64(plt, addr):
+    plt.reset()
+    while True:
+        plt.look_for(b'\xff\x25')		# jmpq *offs32(%rip)
+        offs = struct.unpack('<i', plt.peek(4, 2))[0]
+        if plt.address + offs + 6 == addr:
+            return plt.address
+        plt.skip(2)
+
+def find_hex_file_lines_constructor_32(text, hex_file_lines_got, got_plt):
+    while True:
+        text.look_for_either(b'\x8b\xbb', b'\x8b\xb3')	# mov offs32(%ebx),{%edi,%esi}
+        offs = struct.unpack('<i', text.peek(4, 2))[0]
+        if got_plt + offs == hex_file_lines_got:
+            text.skip(6)
+            return
+        text.skip(2)
+
+def find_hex_file_lines_constructor_64(text, hex_file_lines_got):
+    while True:
+        text.look_for(b'\x48\x8b\x2d')		# mov offs32(%rip),%rbp
+        offs = struct.unpack('<i', text.peek(4, 3))[0]
+        if text.address + offs + 7 == hex_file_lines_got:
+            text.skip(7)
+            return
+        text.skip(3)
+
+def parse_hex_file_lines_constructor_32(text, basic_string_plt, got_plt, lines):
+    text.skip(-5)
+    esi = (text.peek(1) == b'\xb3')
+    text.skip(5)
+    cnt = len(lines)
+    while cnt > 0:
+        if text.peek(2) == b'\x8d\x45':		# lea offs8(%ebp),%eax
+            text.skip(3)
+        elif text.peek(2) == b'\x8d\x85':	# lea offs32(%ebp),%eax
+            text.skip(6)
+        if text.peek(1) == (b'\xbf' if esi else b'\xbe'):	# mov $imm32,%esi
+            text.skip(5)
+        elif text.peek(2) == (b'\x31\xff' if esi else b'\x31\xf6'):	# xor %esi,%esi
+            text.skip(2)
+        if text.peek(4) == b'\x89\x44\x24\x08':	# mov %eax,0x8(%esp)
+            text.skip(4)
+        if text.peek(2) == b'\x8d\x83':		# lea offs32(%ebx),%eax
+            straddr = struct.unpack('<i', text.peek(4, 2))[0]
+            text.skip(6)
+            straddr += got_plt
+        else:
+            raise Exception('Expected lea offs32(%ebx),%eax @ ' +
+                            ('0x%x' % text.address))
+        if text.peek(4) == b'\x89\x44\x24\x04':	# mov %eax,0x4(%esp)
+            text.skip(4)
+        if text.peek(3) == (b'\x89\x34\x24' if esi else b'\x89\x3c\x24'):	# mov %edi,(%esp)
+            offs = 0
+            text.skip(3)
+        elif text.peek(2) == (b'\x8d\x46' if esi else b'\x8d\x47'):	# lea offs8(%edi),%eax
+            offs = struct.unpack('<b', text.peek(1, 2))[0]
+            text.skip(3)
+        elif text.peek(2) == (b'\x8d\x86' if esi else b'\x8d\x87'):	# lea offs32(%edi),%eax
+            offs = struct.unpack('<i', text.peek(4, 2))[0]
+            text.skip(6)
+        else:
+            raise Exception('Expected lea offs(%e'+('s' if esi else 'd')+'i),%eax @ ' +
+                            ('0x%x' % text.address))
+        if offs < 0 or offs > (len(lines) << 2) or (offs & 3) != 0:
+            raise Exception('Invalid offset %d' % offs)
+        index = offs >> 2
+        if lines[index] != 0:
+            raise Exception('Line %d filled multiple times' % index)
+        if text.peek(3) == b'\x89\x04\x24':	# mov %eax,(%esp)
+            text.skip(3)
+        if text.peek(1) == b'\xe8':		# call offs32
+            offs = struct.unpack('<i', text.peek(4, 1))[0]
+            text.skip(5)
+            if text.address + offs != basic_string_plt:
+                raise Exception('Expected call ZNSsC1EPKcRKSaIcE at plt @ ' +
+                                ('0x%x' % text.address))
+        else:
+            raise Exception('Expected call ZNSsC1EPKcRKSaIcE at plt @ ' +
+                            ('0x%x' % text.address))
+        if straddr == 0:
+            raise Exception('NULL pointer stored to index %d' % index)
+        lines[index] = straddr
+        cnt -= 1
+
+def parse_hex_file_lines_constructor_64(text, basic_string_plt, lines):
+    cnt = len(lines)
+    while cnt > 0:
+        if text.peek(1) == b'\xbb':		# mov $imm32,%ebx
+            text.skip(5)
+        elif text.peek(2) == b'\x31\xdb':	# xor %ebx,%ebx
+            text.skip(2)
+        if text.peek(4) == b'\x48\x8d\x54\x24':	# lea offs8(%rsp),%rdx
+            text.skip(5)
+        elif text.peek(4) == b'\x48\x8d\x94\x24': # lea offs32(%rsp),%rdx
+            text.skip(8)
+        if text.peek(3) == b'\x48\x8d\x35':	# lea offs32(%rip),%rsi
+            straddr = struct.unpack('<i', text.peek(4, 3))[0]
+            text.skip(7)
+            straddr += text.address
+        else:
+            raise Exception('Expected lea offs(%rip),%rsi @ ' +
+                            ('0x%x' % text.address))
+        if text.peek(3) == b'\x48\x89\xef':	# mov %rbp,%rdi
+            offs = 0
+            text.skip(3)
+        elif text.peek(3) == b'\x48\x8d\x7d':	# lea offs8(%rbp),%rdi
+            offs = struct.unpack('<b', text.peek(1, 3))[0]
+            text.skip(4)
+        elif text.peek(3) == b'\x48\x8d\xbd':	# lea offs32(%rbp),%rdi
+            offs = struct.unpack('<i', text.peek(4, 3))[0]
+            text.skip(7)
+        else:
+            raise Exception('Expected lea offs(%rbp),%rdi @ ' +
+                            ('0x%x' % text.address))
+        if text.peek(1) == b'\xbb':		# mov $imm32,%ebx
+            text.skip(5)
+        elif text.peek(2) == b'\x31\xdb':	# xor %ebx,%ebx
+            text.skip(2)
+        if offs < 0 or offs > (len(lines) << 3) or (offs & 7) != 0:
+            raise Exception('Invalid offset %d' % offs)
+        index = offs >> 3
+        if lines[index] != 0:
+            raise Exception('Line %d filled multiple times' % index)
+        if text.peek(1) == b'\xe8':		# callq offs32
+            offs = struct.unpack('<i', text.peek(4, 1))[0]
+            text.skip(5)
+            if text.address + offs != basic_string_plt:
+                raise Exception('Expected callq ZNSsC1EPKcRKSaIcE at plt @ ' +
+                                ('0x%x' % text.address))
+        else:
+            raise Exception('Expected callq ZNSsC1EPKcRKSaIcE at plt @ ' +
+                            ('0x%x' % text.address))
+        if straddr == 0:
+            raise Exception('NULL pointer stored to index %d' % index)
+        lines[index] = straddr
+        cnt -= 1
+
+def find_reloc(elf, symname):
+    for section, relocs in elf.relocs.items():
+        if 'symbols' in relocs and symname in relocs['symbols']:
+            symnum = relocs['symbols'][symname]['number']
+            for reloc in relocs['relocs']:
+                if reloc['r_sym'] == symnum:
+                    return reloc
+    raise Exception('Unable to find a relocation against ' + symname)
+
+def ihex_to_binary(lines):
+    chunks = {}
+    for line in lines:
+        if line[0] != ':':
+            raise Exception('ihex line does not start with ":"')
+        line = bytes.fromhex(line[1:])
+        if (sum(bytearray(line)) & 0xff) != 0:
+            raise Exception('Invalid checksum in ihex')
+        (byte_count, address, rectype) = struct.unpack('>BHB', line[:4])
+        (data, checksum) = struct.unpack('>%dsB' % (byte_count), line[4:])
+        if rectype == 1 and byte_count == 0:
+            pass
+        elif rectype != 0 or byte_count == 0:
+            raise Exception('Unexpected rectype %d with bytecount %d' %
+                            (rectype, byte_count))
+        elif address in chunks:
+            raise Exception('Multiple ihex lines with address 0x%x' % address)
+        else:
+            chunks[address] = data
+    blob = b''
+    for address in sorted(iter(chunks)):
+        if address < len(blob):
+            raise Exception('Overlapping ihex chunks')
+        elif address > len(blob):
+            blob += b'\x00' * (address - len(blob))
+        blob += chunks[address]
+    return blob
+
+def extract_fx2_firmware(elf, symname, filename):
+    blob = elf.load_symbol(elf.dynsym[symname + 'Count'])
+    count = struct.unpack('<I', blob)[0]
+    got_plt = elf.find_section('.got.plt')['sh_addr']
+    hex_file_lines_got = find_reloc(elf, symname)['r_offset']
+    basic_string_got = find_reloc(elf, '_ZNSsC1EPKcRKSaIcE')['r_offset']
+    pltsec = elf.find_section('.plt')
+    plt = searcher(elf.read_section(pltsec), pltsec['sh_addr'])
+    try:
+        if elf.elf_wordsize == 64:
+            basic_string_plt = search_plt_64(plt, basic_string_got)
+        else:
+            basic_string_plt = search_plt_32(plt, basic_string_got)
+    except:
+        raise Exception('Unable to find a PLT entry for _ZNSsC1EPKcRKSaIcE')
+    textsec = elf.find_section('.text')
+    text = searcher(elf.read_section(textsec), textsec['sh_addr'])
+    while True:
+        try:
+            if elf.elf_wordsize == 64:
+                find_hex_file_lines_constructor_64(text, hex_file_lines_got)
+            else:
+                find_hex_file_lines_constructor_32(text, hex_file_lines_got,
+                                                   got_plt)
+        except:
+            raise Exception('Unable to find constructor for ' + symname)
+        oldoffs = text.offset
+        l = [0]*count
+        try:
+            if elf.elf_wordsize == 64:
+                parse_hex_file_lines_constructor_64(text, basic_string_plt, l)
+            else:
+                parse_hex_file_lines_constructor_32(text, basic_string_plt,
+                                                    got_plt, l)
+            break
+        except KeyError:
+            text.reset(oldoffs)
+    rodatasec = elf.find_section('.rodata')
+    rodata = elf.read_section(rodatasec)
+    lo = rodatasec['sh_addr']
+    hi = lo + rodatasec['sh_size']
+    for i in range(count):
+        addr = l[i]
+        if addr < lo or addr >= hi:
+            raise Exception('Address 0x%x outside of .rodata section' % addr)
+        l[i] = elf.get_name(addr - lo, rodata)
+    blob = ihex_to_binary(l)
+    f = open(filename, 'wb')
+    f.write(blob)
+    f.close()
+    print("saved %d bytes to %s" % (len(blob), filename))
+
+def extract_symbol(elf, symname, filename):
+    blob = elf.load_symbol(elf.dynsym[symname])
+    f = open(filename, 'wb')
+    f.write(blob)
+    f.close()
+    print("saved %d bytes to %s" % (len(blob), filename))
+
+def extract_bitstream(elf, lv):
+    extract_symbol(elf, 'gLogic16Lv' + lv + 'CompressedBitstream',
+                   'saleae-logic16-fpga-' + lv + '.bitstream')
+
+def usage():
+    print("sigrok-fwextract-saleae-logic16 <programfile>")
+    sys.exit()
+
+
+#
+# main
+#
+
+if len(sys.argv) != 2:
+    usage()
+
+try:
+    filename = sys.argv[1]
+    elf = parseelf.elf(filename)
+    if elf.ehdr['e_machine'] != 3 and elf.ehdr['e_machine'] != 62:
+        raise Exception('Unsupported e_machine')
+    extract_fx2_firmware(elf, 'gLogic16HexFileLines', 'saleae-logic16-fx2.fw')
+    extract_bitstream(elf, '18')
+    extract_bitstream(elf, '33')
+except Exception as e:
+    print("Error: %s" % str(e))

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16.1
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-saleae-logic16.1	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,40 @@
+.TH SIGROK\-FWEXTRACT\-SALEAE\-LOGIC16 1 "Aug 08, 2013"
+.SH "NAME"
+sigrok\-fwextract\-saleae\-logic16 \- Extract Saleae Logic16 firmware
+.SH "SYNOPSIS"
+.B sigrok\-fwextract\-saleae\-logic16 [FILE]
+.SH "DESCRIPTION"
+This tool extracts FX2 firmware and FPGA bitstreams from the vendor
+software for the Saleae Logic16 USB logic analyzer. Download the Linux
+version (either 32-bit or 64-bit will do), and unpack it to find the
+main binary called "Logic".
+.PP
+In order to extract the firmware/bitstreams, run the following command:
+.PP
+.B "  $ sigrok-fwextract-saleae-logic16 Logic"
+.br
+.RB "  saved 5214 bytes to saleae-logic16-fx2.fw"
+.br
+.RB "  saved 149516 bytes to saleae-logic16-fpga-18.bitstream"
+.br
+.RB "  saved 149516 bytes to saleae-logic16-fpga-33.bitstream"
+.PP
+Copy the resulting files over to the location where libsigrok expects
+to find its firmware files. By default this is
+.BR /usr/local/share/sigrok-firmware .
+.SH OPTIONS
+None.
+.SH "EXIT STATUS"
+Exits with 0 on success, 1 on most failures.
+.SH "SEE ALSO"
+\fBsigrok\-fwextract\-hantek\-dso\fP(1)
+.SH "BUGS"
+Please report any bugs via Bugzilla
+.RB "(" http://sigrok.org/bugzilla ")"
+or on the sigrok\-devel mailing list
+.RB "(" sigrok\-devel at lists.souceforge.net ")."
+.SH "LICENSE"
+This program is covered by the GNU General Public License (GPL),
+version 3 or later.
+.SH "AUTHORS"
+Please see the individual source code files.

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,41 @@
+#! /bin/sh -e
+##
+## This file is part of the sigrok-util project.
+##
+## Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+infile=$1
+if [ -z "$infile" ]; then
+    echo "Usage: $0 SETUP-EXE" >&2
+    exit 1
+fi
+
+# Verify the checksum to make sure this is the right binary file
+expectsum=f2a9333329200ad1d939d051257f914200cf0c765ff4962b2907dcf30716f455
+set '' $(sha256sum -b "$infile")
+
+if [ "$2" != "$expectsum" ]; then
+    echo "$0: checksum mismatch for '$infile'" >&2
+    echo "$0: make sure you picked the right file (lwla1034_EN_setup.exe on the CD-ROM)" >&2
+    exit 1
+fi
+
+# Extract the firmware binaries from the executable
+dd bs=1 skip=34110338 count=78398 if="$infile" of=sysclk-lwla1034-int.bitstream
+dd bs=1 skip=34266237 count=78247 if="$infile" of=sysclk-lwla1034-extpos.bitstream
+dd bs=1 skip=34344484 count=79145 if="$infile" of=sysclk-lwla1034-extneg.bitstream
+dd bs=1 skip=34578631 count=48525 if="$infile" of=sysclk-lwla1034-off.bitstream

Added: head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla.1
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/science/sigrok-firmware-utils/files/sigrok-fwextract-sysclk-lwla.1	Sun Aug  3 22:09:07 2014	(r363948)
@@ -0,0 +1,33 @@
+.TH SIGROK\-FWEXTRACT\-SYSCLK\-LWLA 1 "Jan 04, 2014"
+.SH "NAME"
+sigrok\-fwextract\-sysclk\-lwla \- Extract SysClk LWLA* firmware
+.SH "SYNOPSIS"
+.B sigrok\-fwextract\-sysclk\-lwla SETUP-EXE
+.SH "DESCRIPTION"
+This tool extracts FPGA bitstreams from the vendor software for the SysClk
+LWLA1034 USB logic analyzer. Insert the CD-ROM that ships with the device,
+and locate the Windows installer executable "lwla1034_EN_setup.exe".
+.PP
+In order to extract the bitstreams, run the following command:
+.PP

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-ports-all mailing list