diff --git a/contrib/debian/source/lintian-overrides b/contrib/debian/source/lintian-overrides index c4627a3d8..70dcf426e 100644 --- a/contrib/debian/source/lintian-overrides +++ b/contrib/debian/source/lintian-overrides @@ -1,7 +1,2 @@ -#this isn't used in any of the binaries, only for fuzz testing -#the interface for libdfu -fwupd source: source-is-missing libdfu/fuzzing/firmware.elf -fwupd source: source-contains-prebuilt-binary libdfu/fuzzing/firmware.elf - #github doesn't have these fwupd source: debian-watch-may-check-gpg-signature diff --git a/libdfu/dfu-firmware.c b/libdfu/dfu-firmware.c index 43dad0996..8ddec1fd7 100644 --- a/libdfu/dfu-firmware.c +++ b/libdfu/dfu-firmware.c @@ -41,7 +41,6 @@ #include "dfu-common.h" #include "dfu-error.h" #include "dfu-firmware-private.h" -#include "dfu-format-elf.h" #include "dfu-format-dfu.h" #include "dfu-format-ihex.h" #include "dfu-format-raw.h" @@ -476,8 +475,6 @@ dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes, priv->format = dfu_firmware_detect_ihex (bytes); if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) priv->format = dfu_firmware_detect_dfu (bytes); - if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) - priv->format = dfu_firmware_detect_elf (bytes); if (priv->format == DFU_FIRMWARE_FORMAT_UNKNOWN) priv->format = dfu_firmware_detect_raw (bytes); @@ -487,10 +484,6 @@ dfu_firmware_parse_data (DfuFirmware *firmware, GBytes *bytes, if (!dfu_firmware_from_ihex (firmware, bytes, flags, error)) return FALSE; break; - case DFU_FIRMWARE_FORMAT_ELF: - if (!dfu_firmware_from_elf (firmware, bytes, flags, error)) - return FALSE; - break; case DFU_FIRMWARE_FORMAT_DFU: case DFU_FIRMWARE_FORMAT_DFUSE: if (!dfu_firmware_from_dfu (firmware, bytes, flags, error)) @@ -692,10 +685,6 @@ dfu_firmware_write_data (DfuFirmware *firmware, GError **error) if (priv->format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return dfu_firmware_to_ihex (firmware, error); - /* ELF */ - if (priv->format == DFU_FIRMWARE_FORMAT_ELF) - return dfu_firmware_to_elf (firmware, error); - /* invalid */ g_set_error (error, DFU_ERROR, @@ -828,8 +817,6 @@ dfu_firmware_format_to_string (DfuFirmwareFormat format) return "dfuse"; if (format == DFU_FIRMWARE_FORMAT_INTEL_HEX) return "ihex"; - if (format == DFU_FIRMWARE_FORMAT_ELF) - return "elf"; return NULL; } @@ -854,8 +841,6 @@ dfu_firmware_format_from_string (const gchar *format) return DFU_FIRMWARE_FORMAT_DFUSE; if (g_strcmp0 (format, "ihex") == 0) return DFU_FIRMWARE_FORMAT_INTEL_HEX; - if (g_strcmp0 (format, "elf") == 0) - return DFU_FIRMWARE_FORMAT_ELF; return DFU_FIRMWARE_FORMAT_UNKNOWN; } diff --git a/libdfu/dfu-firmware.h b/libdfu/dfu-firmware.h index 7552bcf4d..c9e00f26c 100644 --- a/libdfu/dfu-firmware.h +++ b/libdfu/dfu-firmware.h @@ -74,7 +74,6 @@ typedef enum { * @DFU_FIRMWARE_FORMAT_DFU: DFU footer * @DFU_FIRMWARE_FORMAT_DFUSE: DfuSe header * @DFU_FIRMWARE_FORMAT_INTEL_HEX: Intel HEX - * @DFU_FIRMWARE_FORMAT_ELF: ELF * * The known versions of the DFU standard in BCD format. **/ @@ -84,7 +83,6 @@ typedef enum { DFU_FIRMWARE_FORMAT_DFU, DFU_FIRMWARE_FORMAT_DFUSE, DFU_FIRMWARE_FORMAT_INTEL_HEX, - DFU_FIRMWARE_FORMAT_ELF, /*< private >*/ DFU_FIRMWARE_FORMAT_LAST } DfuFirmwareFormat; diff --git a/libdfu/dfu-format-elf.c b/libdfu/dfu-format-elf.c deleted file mode 100644 index 1e03c2696..000000000 --- a/libdfu/dfu-format-elf.c +++ /dev/null @@ -1,468 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- - * - * Copyright (C) 2015-2016 Richard Hughes - * - * Licensed under the GNU Lesser General Public License Version 2.1 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include -#include - -#ifdef HAVE_LIBELF -#include -#include -#include -#endif - -#include -#include - -#include "dfu-firmware-private.h" -#include "dfu-format-elf.h" -#include "dfu-error.h" - -/** - * dfu_firmware_detect_elf: (skip) - * @bytes: data to parse - * - * Attempts to sniff the data and work out the firmware format - * - * Returns: a #DfuFirmwareFormat, e.g. %DFU_FIRMWARE_FORMAT_ELF - **/ -DfuFirmwareFormat -dfu_firmware_detect_elf (GBytes *bytes) -{ - guint8 *data; - gsize len; - - /* check data size */ - data = (guint8 *) g_bytes_get_data (bytes, &len); - if (len < 16) - return DFU_FIRMWARE_FORMAT_UNKNOWN; - - /* sniff the signature bytes */ - if (memcmp (data + 1, "ELF", 3) != 0) - return DFU_FIRMWARE_FORMAT_UNKNOWN; - - /* success */ - return DFU_FIRMWARE_FORMAT_ELF; -} - -#ifdef HAVE_LIBELF -static DfuElement * -_get_element_from_section_name (Elf *e, const gchar *desired_name) -{ - DfuElement *element = NULL; - Elf_Scn *scn = NULL; - GElf_Shdr shdr; - const gchar *name; - size_t shstrndx; - - if (elf_getshdrstrndx (e, &shstrndx) != 0) - return NULL; - while ((scn = elf_nextscn (e, scn)) != NULL ) { - if (gelf_getshdr (scn, &shdr ) != & shdr) { - continue; - } - - /* not program data */ - if (shdr.sh_type != SHT_PROGBITS) - continue; - - /* not the same section name */ - if ((name = elf_strptr (e, shstrndx, shdr.sh_name)) == NULL) { - continue; - } - if (g_strcmp0 (name, desired_name) == 0) { - Elf_Data *data = elf_getdata (scn, NULL); - if (data != NULL && data->d_buf != NULL) { - g_autoptr(GBytes) bytes = NULL; - bytes = g_bytes_new (data->d_buf, data->d_size); - element = dfu_element_new (); - dfu_element_set_contents (element, bytes); - dfu_element_set_address (element, shdr.sh_addr); - } - break; - } - } - return element; -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end); - -static void -dfu_format_elf_symbols_from_symtab (DfuFirmware *firmware, Elf *e) -{ - Elf_Scn *scn = NULL; - gsize shstrndx; - - if (elf_getshdrstrndx (e, &shstrndx) != 0) - return; - while ((scn = elf_nextscn (e, scn)) != NULL ) { - Elf_Data *data; - GElf_Shdr shdr; - const gchar *name; - gssize ns; - if (gelf_getshdr (scn, &shdr) != &shdr) - continue; - - /* not program data */ - if (shdr.sh_type != SHT_SYMTAB) - continue; - - /* get symbols */ - data = elf_getdata (scn, NULL); - ns = shdr.sh_size / shdr.sh_entsize; - for (gint i = 0; i < ns; i++) { - GElf_Sym sym; - gelf_getsym (data, i, &sym); - if (sym.st_value == 0) - continue; - name = elf_strptr (e, shdr.sh_link, sym.st_name); - if (name == NULL) - continue; - dfu_firmware_add_symbol (firmware, name, sym.st_value); - } - } -} -#endif - -/** - * dfu_firmware_from_elf: (skip) - * @firmware: a #DfuFirmware - * @bytes: data to parse - * @flags: some #DfuFirmwareParseFlags - * @error: a #GError, or %NULL - * - * Unpacks into a firmware object from ELF data. - * - * Returns: %TRUE for success - **/ -gboolean -dfu_firmware_from_elf (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error) -{ -#ifdef HAVE_LIBELF - guint i; - guint sections_cnt = 0; - g_autoptr(Elf) e = NULL; - const gchar *section_names[] = { - ".interrupt", - ".text", - NULL }; - - /* load library */ - if (elf_version (EV_CURRENT) == EV_NONE) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "ELF library init failed: %s", - elf_errmsg (-1)); - return FALSE; - } - - /* parse data */ - e = elf_memory ((gchar *) g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes)); - if (e == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to load data as ELF: %s", - elf_errmsg (-1)); - return FALSE; - } - if (elf_kind (e) != ELF_K_ELF) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "not a supported ELF format: %s", - elf_errmsg (-1)); - return FALSE; - } - g_debug ("loading %ib ELF object" , - gelf_getclass (e) == ELFCLASS32 ? 32 : 64); - - /* add interesting sections as the image */ - for (i = 0; section_names[i] != NULL; i++) { - g_autoptr(DfuElement) element = NULL; - g_autoptr(DfuImage) image = NULL; - element = _get_element_from_section_name (e, section_names[i]); - if (element == NULL) - continue; - image = dfu_image_new (); - dfu_image_add_element (image, element); - dfu_image_set_name (image, section_names[i]); - dfu_firmware_add_image (firmware, image); - sections_cnt++; - } - - /* load symbol table */ - dfu_format_elf_symbols_from_symtab (firmware, e); - - /* nothing found */ - if (sections_cnt == 0) { - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "no firmware found in ELF file"); - return FALSE; - } - - /* success */ - return TRUE; -#else - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "compiled without libelf support"); - return FALSE; -#endif -} - -#ifdef HAVE_LIBELF -static int -_memfd_create (const char *name, unsigned int flags) -{ -#if defined (__NR_memfd_create) - return syscall (__NR_memfd_create, name, flags); -#else - return -1; -#endif -} - -static gboolean -dfu_format_elf_pack_element (Elf *e, DfuElement *element, GError **error) -{ - Elf32_Shdr *shdr; - Elf_Data *data; - Elf_Scn *scn; - GBytes *bytes = dfu_element_get_contents (element); - - /* create a section descriptor for the firmware */ - scn = elf_newscn (e); - if (scn == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create section descriptor: %s", - elf_errmsg (-1)); - return FALSE; - } - data = elf_newdata (scn); - data->d_align = 1; - data->d_off = 0; - data->d_buf = (gpointer) g_bytes_get_data (bytes, NULL); - data->d_type = ELF_T_BYTE; - data->d_size = g_bytes_get_size (bytes); - data->d_version = EV_CURRENT; - shdr = elf32_getshdr (scn); - if (shdr == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create XXX: %s", - elf_errmsg (-1)); - return FALSE; - } - shdr->sh_name = 1; - shdr->sh_type = SHT_PROGBITS; - shdr->sh_flags = SHF_ALLOC; - shdr->sh_entsize = 0; - return TRUE; -} - -static gboolean -dfu_format_elf_pack_image (Elf *e, DfuImage *image, GError **error) -{ - DfuElement *element; - - /* only works for one element */ - element = dfu_image_get_element_default (image); - if (element == NULL) { - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "no element to write"); - return FALSE; - } - return dfu_format_elf_pack_element (e, element, error); -} -#endif - -/** - * dfu_firmware_to_elf: (skip) - * @firmware: a #DfuFirmware - * @error: a #GError, or %NULL - * - * Packs elf firmware - * - * Returns: (transfer full): the packed data - **/ -GBytes * -dfu_firmware_to_elf (DfuFirmware *firmware, GError **error) -{ -#ifdef HAVE_LIBELF - DfuImage *image; - Elf32_Ehdr *ehdr; - Elf32_Shdr *shdr; - Elf_Data *data; - Elf_Scn *scn; - gint fd; - goffset fsize; - g_autoptr(Elf) e = NULL; - g_autoptr(GInputStream) stream = NULL; - gchar string_table2[] = - "\0" - ".text\0" // FIXME: use the name in the DfuImage? - ".shstrtab"; - - /* only works for one image */ - image = dfu_firmware_get_image_default (firmware); - if (image == NULL) { - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "no image to write"); - return NULL; - } - - /* load library */ - if (elf_version (EV_CURRENT) == EV_NONE) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "ELF library init failed: %s", - elf_errmsg (-1)); - return NULL; - } - - /* create from buffer */ - fd = _memfd_create ("elf", MFD_CLOEXEC); - if (fd < 0) { - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to open memfd"); - return NULL; - } - stream = g_unix_input_stream_new (fd, TRUE); - e = elf_begin (fd, ELF_C_WRITE, NULL); - if (e == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create ELF: %s", - elf_errmsg (-1)); - return NULL; - } - - /* add executable header */ - ehdr = elf32_newehdr (e); - if (ehdr == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create executable header: %s", - elf_errmsg (-1)); - return NULL; - } - ehdr->e_ident[EI_DATA] = ELFDATA2LSB; - ehdr->e_machine = EM_NONE; - ehdr->e_type = ET_NONE; - - /* pack the image */ - if (!dfu_format_elf_pack_image (e, image, error)) - return NULL; - - /* allocate section for holding the string table */ - scn = elf_newscn (e); - if (scn == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create section descriptor: %s", - elf_errmsg (-1)); - return NULL; - } - data = elf_newdata (scn); - data->d_align = 1; - data->d_off = 0; - data->d_buf = string_table2; - data->d_type = ELF_T_BYTE; - data->d_size = sizeof (string_table2); - data->d_version = EV_CURRENT; - shdr = elf32_getshdr (scn); - if (shdr == NULL) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to create XXX: %s", - elf_errmsg (-1)); - return NULL; - } - shdr->sh_name = 7; /* offset to table name */ - shdr->sh_type = SHT_STRTAB; - shdr->sh_flags = SHF_STRINGS | SHF_ALLOC; - shdr->sh_entsize = 0; - - /* set string table index field */ - ehdr->e_shstrndx = elf_ndxscn (scn); - - /* compute the layout of the object */ - if (elf_update (e, ELF_C_NULL) < 0) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to compute layout: %s", - elf_errmsg (-1)); - return NULL; - } - - /* write out the actual data */ - elf_flagphdr (e, ELF_C_SET, ELF_F_DIRTY ); - if (elf_update (e, ELF_C_WRITE ) < 0) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to write to fd: %s", - elf_errmsg (-1)); - return NULL; - } - - /* read out the blob of memory in one chunk */ - fsize = lseek(fd, 0, SEEK_END); - if (lseek (fd, 0, SEEK_SET) < 0) { - g_set_error (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "failed to seek to start"); - return NULL; - } - return g_input_stream_read_bytes (stream, fsize, NULL, error); -#else - g_set_error_literal (error, - DFU_ERROR, - DFU_ERROR_INTERNAL, - "compiled without libelf support"); - return NULL; -#endif -} diff --git a/libdfu/dfu-self-test.c b/libdfu/dfu-self-test.c index e3e2c51a1..bcec1f8e5 100644 --- a/libdfu/dfu-self-test.c +++ b/libdfu/dfu-self-test.c @@ -386,66 +386,6 @@ dfu_firmware_metadata_func (void) g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); } -static void -dfu_firmware_elf_func (void) -{ - DfuElement *element; - DfuImage *image; - GBytes *contents; - const gchar *data; - gboolean ret; - g_autofree gchar *filename = NULL; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GBytes) roundtrip_orig = NULL; - g_autoptr(GBytes) roundtrip = NULL; - g_autoptr(GError) error = NULL; - g_autoptr(GFile) file = NULL; - -#ifndef HAVE_LIBELF - g_test_skip ("compiled without libelf support"); - return; -#endif - - /* load a ELF firmware */ - filename = dfu_test_get_filename ("example.elf"); - g_assert (filename != NULL); - file = g_file_new_for_path (filename); - firmware = dfu_firmware_new (); - ret = dfu_firmware_parse_file (firmware, file, - DFU_FIRMWARE_PARSE_FLAG_NONE, - NULL, &error); - g_assert_no_error (error); - g_assert (ret); - g_assert_cmpint (dfu_firmware_get_vid (firmware), ==, 0xffff); - g_assert_cmpint (dfu_firmware_get_pid (firmware), ==, 0xffff); - g_assert_cmpint (dfu_firmware_get_release (firmware), ==, 0xffff); - g_assert_cmpint (dfu_firmware_get_format (firmware), ==, DFU_FIRMWARE_FORMAT_ELF); - g_assert_cmpint (dfu_firmware_get_size (firmware), ==, 0x0c); - g_assert_cmpint (dfu_firmware_get_cipher_kind (firmware), ==, DFU_CIPHER_KIND_NONE); - - /* check the data */ - image = dfu_firmware_get_image_default (firmware); - g_assert (image != NULL); - element = dfu_image_get_element_default (image); - g_assert (element != NULL); - contents = dfu_element_get_contents (element); - g_assert (contents != NULL); - g_assert_cmpint (g_bytes_get_size (contents), ==, 12); - data = g_bytes_get_data (contents, NULL); - g_assert (data != NULL); - g_assert (memcmp (data, "hello world\n", 12) == 0); - - /* can we roundtrip without loosing data */ - roundtrip_orig = dfu_self_test_get_bytes_for_file (file, &error); - g_assert_no_error (error); - g_assert (roundtrip_orig != NULL); - roundtrip = dfu_firmware_write_data (firmware, &error); - g_assert_no_error (error); - g_assert (roundtrip != NULL); - - g_assert_cmpstr (_g_bytes_compare_verbose (roundtrip, roundtrip_orig), ==, NULL); -} - static void dfu_firmware_intel_hex_func (void) { @@ -1017,7 +957,6 @@ main (int argc, char **argv) g_test_add_func ("/libdfu/firmware{metadata}", dfu_firmware_metadata_func); g_test_add_func ("/libdfu/firmware{intel-hex}", dfu_firmware_intel_hex_func); g_test_add_func ("/libdfu/firmware{intel-hex-signed}", dfu_firmware_intel_hex_signed_func); - g_test_add_func ("/libdfu/firmware{elf}", dfu_firmware_elf_func); g_test_add_func ("/libdfu/device", dfu_device_func); g_test_add_func ("/libdfu/colorhug+", dfu_colorhug_plus_func); return g_test_run (); diff --git a/libdfu/fuzzing/firmware.elf b/libdfu/fuzzing/firmware.elf deleted file mode 100644 index d45fd0bc4..000000000 Binary files a/libdfu/fuzzing/firmware.elf and /dev/null differ diff --git a/libdfu/meson.build b/libdfu/meson.build index d7effc3a9..6cb2cfd7e 100644 --- a/libdfu/meson.build +++ b/libdfu/meson.build @@ -2,17 +2,6 @@ cargs = [ '-DG_LOG_DOMAIN="Dfu"', ] -deps = [ - appstream_glib, - giounix, - libm, - gusb, -] - -if get_option('enable-libelf') - deps += libelf -endif - dfu = static_library( 'dfu', sources : [ @@ -26,7 +15,6 @@ dfu = static_library( 'dfu-firmware.c', 'dfu-format-dfu.c', 'dfu-format-dfuse.c', - 'dfu-format-elf.c', 'dfu-format-ihex.c', 'dfu-format-metadata.c', 'dfu-format-raw.c', @@ -35,7 +23,12 @@ dfu = static_library( 'dfu-sector.c', 'dfu-target.c', ], - dependencies : deps, + dependencies : [ + appstream_glib, + giounix, + libm, + gusb, + ], c_args : cargs, include_directories : include_directories('..'), ) @@ -49,7 +42,12 @@ executable( include_directories : [ include_directories('..'), ], - dependencies : deps, + dependencies : [ + appstream_glib, + giounix, + libm, + gusb, + ], link_with : dfu, c_args : cargs, install : true, diff --git a/libdfu/tests/example.elf b/libdfu/tests/example.elf deleted file mode 100644 index 30260fe7e..000000000 Binary files a/libdfu/tests/example.elf and /dev/null differ diff --git a/meson.build b/meson.build index c5877c14f..f96573254 100644 --- a/meson.build +++ b/meson.build @@ -179,9 +179,8 @@ if get_option('enable-colorhug') conf.set('HAVE_COLORHUG', '1') endif -if get_option('enable-libelf') +if get_option('enable-altos') libelf = dependency('libelf') - conf.set('HAVE_LIBELF', '1') endif if get_option('enable-uefi') diff --git a/meson_options.txt b/meson_options.txt index 7179de5c9..1ba3c631f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,7 +4,7 @@ option('enable-man', type : 'boolean', value : true, description : 'enable man p option('enable-tests', type : 'boolean', value : true, description : 'enable tests') option('enable-lvfs', type : 'boolean', value : true, description : 'enable LVFS remotes') option('enable-colorhug', type : 'boolean', value : true, description : 'enable ColorHug support') -option('enable-libelf', type : 'boolean', value : true, description : 'enable libelf support') +option('enable-altos', type : 'boolean', value : true, description : 'enable altos support') option('enable-usb-fallback', type : 'boolean', value : false, description : 'enable USB fallback support') option('enable-uefi', type : 'boolean', value : true, description : 'enable UEFI support') option('enable-uefi-labels', type : 'boolean', value : true, description : 'enable UEFI labels support') diff --git a/plugins/altos/fu-altos-firmware.c b/plugins/altos/fu-altos-firmware.c new file mode 100644 index 000000000..263a32bf6 --- /dev/null +++ b/plugins/altos/fu-altos-firmware.c @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2017 Richard Hughes + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include +#include +#include + +#include "fu-altos-firmware.h" +#include "fwupd-error.h" + +struct _FuAltosFirmware { + GObject parent_instance; + GBytes *data; + guint64 address; +}; + +G_DEFINE_TYPE (FuAltosFirmware, fu_altos_firmware, G_TYPE_OBJECT) + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf, elf_end); + +GBytes * +fu_altos_firmware_get_data (FuAltosFirmware *self) +{ + return self->data; +} + +guint64 +fu_altos_firmware_get_address (FuAltosFirmware *self) +{ + return self->address; +} + +gboolean +fu_altos_firmware_parse (FuAltosFirmware *self, GBytes *blob, GError **error) +{ + const gchar *name; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + size_t shstrndx; + g_autoptr(Elf) e = NULL; + + /* load library */ + if (elf_version (EV_CURRENT) == EV_NONE) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "ELF library init failed: %s", + elf_errmsg (-1)); + return FALSE; + } + + /* parse data */ + e = elf_memory ((gchar *) g_bytes_get_data (blob, NULL), + g_bytes_get_size (blob)); + if (e == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "failed to load data as ELF: %s", + elf_errmsg (-1)); + return FALSE; + } + if (elf_kind (e) != ELF_K_ELF) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "not a supported ELF format: %s", + elf_errmsg (-1)); + return FALSE; + } + + /* add interesting section */ + if (elf_getshdrstrndx (e, &shstrndx) != 0) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "invalid ELF file: %s", + elf_errmsg (-1)); + return FALSE; + } + while ((scn = elf_nextscn (e, scn)) != NULL ) { + if (gelf_getshdr (scn, &shdr) != & shdr) + continue; + + /* not program data with the same section name */ + if (shdr.sh_type != SHT_PROGBITS) + continue; + if ((name = elf_strptr (e, shstrndx, shdr.sh_name)) == NULL) + continue; + + if (g_strcmp0 (name, ".text") == 0) { + Elf_Data *data = elf_getdata (scn, NULL); + if (data != NULL && data->d_buf != NULL) { + self->data = g_bytes_new (data->d_buf, data->d_size); + self->address = shdr.sh_addr; + } + return TRUE; + } + } + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INTERNAL, + "no firmware found in ELF file"); + return FALSE; +} + +static void +fu_altos_firmware_finalize (GObject *object) +{ + FuAltosFirmware *self = FU_ALTOS_FIRMWARE (object); + + if (self->data != NULL) + g_bytes_unref (self->data); + + G_OBJECT_CLASS (fu_altos_firmware_parent_class)->finalize (object); +} + +static void +fu_altos_firmware_class_init (FuAltosFirmwareClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = fu_altos_firmware_finalize; +} + +static void +fu_altos_firmware_init (FuAltosFirmware *self) +{ +} + +FuAltosFirmware * +fu_altos_firmware_new (void) +{ + FuAltosFirmware *self; + self = g_object_new (FU_TYPE_ALTOS_FIRMWARE, NULL); + return FU_ALTOS_FIRMWARE (self); +} diff --git a/libdfu/dfu-format-elf.h b/plugins/altos/fu-altos-firmware.h similarity index 61% rename from libdfu/dfu-format-elf.h rename to plugins/altos/fu-altos-firmware.h index fceaac2ea..9864968a0 100644 --- a/libdfu/dfu-format-elf.h +++ b/plugins/altos/fu-altos-firmware.h @@ -1,6 +1,6 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * - * Copyright (C) 2015-2016 Richard Hughes + * Copyright (C) 2017 Richard Hughes * * Licensed under the GNU Lesser General Public License Version 2.1 * @@ -19,24 +19,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef __DFU_FORMAT_ELF_H -#define __DFU_FORMAT_ELF_H +#ifndef __FU_ALTOS_FIRMWARE_H +#define __FU_ALTOS_FIRMWARE_H #include -#include - -#include "dfu-firmware.h" G_BEGIN_DECLS -DfuFirmwareFormat dfu_firmware_detect_elf (GBytes *bytes); -GBytes *dfu_firmware_to_elf (DfuFirmware *firmware, - GError **error); -gboolean dfu_firmware_from_elf (DfuFirmware *firmware, - GBytes *bytes, - DfuFirmwareParseFlags flags, - GError **error); +#define FU_TYPE_ALTOS_FIRMWARE (fu_altos_firmware_get_type ()) + +G_DECLARE_FINAL_TYPE (FuAltosFirmware, fu_altos_firmware, FU, ALTOS_FIRMWARE, GObject) + +FuAltosFirmware *fu_altos_firmware_new (void); +GBytes *fu_altos_firmware_get_data (FuAltosFirmware *self); +guint64 fu_altos_firmware_get_address (FuAltosFirmware *self); +gboolean fu_altos_firmware_parse (FuAltosFirmware *self, + GBytes *blob, + GError **error); G_END_DECLS -#endif /* __DFU_FORMAT_ELF_H */ +#endif /* __FU_ALTOS_FIRMWARE_H */ diff --git a/plugins/altos/fu-device-altos.c b/plugins/altos/fu-device-altos.c index 8b7f5a5b4..7588fee33 100644 --- a/plugins/altos/fu-device-altos.c +++ b/plugins/altos/fu-device-altos.c @@ -29,8 +29,7 @@ #include #include -#include - +#include "fu-altos-firmware.h" #include "fu-device-altos.h" typedef struct @@ -432,49 +431,6 @@ fu_device_altos_write_page (FuDeviceAltos *device, return TRUE; } -static gboolean -fu_device_check_firmware (FuDeviceAltos *device, DfuFirmware *firmware, GError **error) -{ - FuDeviceAltosPrivate *priv = GET_PRIVATE (device); - DfuElement *dfu_element; - DfuImage *dfu_image; - - /* get default image */ - dfu_image = dfu_firmware_get_image_default (firmware); - if (dfu_image == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no firmware image"); - return FALSE; - } - - /* get default element */ - dfu_element = dfu_image_get_element_default (dfu_image); - if (dfu_element == NULL) { - g_set_error_literal (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "no firmware element"); - return FALSE; - } - - /* check the start address */ - if (dfu_element_get_address (dfu_element) != priv->addr_base) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "start address not correct %" G_GUINT32_FORMAT ":" - "%" G_GUINT64_FORMAT, - dfu_element_get_address (dfu_element), - priv->addr_base); - return FALSE; - } - - /* success */ - return TRUE; -} - gboolean fu_device_altos_write_firmware (FuDeviceAltos *device, GBytes *fw, @@ -484,11 +440,11 @@ fu_device_altos_write_firmware (FuDeviceAltos *device, GError **error) { FuDeviceAltosPrivate *priv = GET_PRIVATE (device); + GBytes *fw_blob; const gchar *data; const gsize data_len; guint flash_len; - g_autoptr(DfuFirmware) firmware = NULL; - g_autoptr(GBytes) fw_blob = NULL; + g_autoptr(FuAltosFirmware) altos_firmware = NULL; g_autoptr(GString) buf = g_string_new (NULL); /* check kind */ @@ -520,22 +476,24 @@ fu_device_altos_write_firmware (FuDeviceAltos *device, } /* load ihex blob */ - firmware = dfu_firmware_new (); - if (!dfu_firmware_parse_data (firmware, fw, - DFU_FIRMWARE_PARSE_FLAG_NONE, - error)) { + altos_firmware = fu_altos_firmware_new (); + if (!fu_altos_firmware_parse (altos_firmware, fw, error)) + return FALSE; + + /* check the start address */ + if (fu_altos_firmware_get_address (altos_firmware) != priv->addr_base) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "start address not correct %" G_GUINT64_FORMAT ":" + "%" G_GUINT64_FORMAT, + fu_altos_firmware_get_address (altos_firmware), + priv->addr_base); return FALSE; } - if (!fu_device_check_firmware (device, firmware, error)) - return FALSE; - - /* convert from ihex to a blob */ - dfu_firmware_set_format (firmware, DFU_FIRMWARE_FORMAT_RAW); - fw_blob = dfu_firmware_write_data (firmware, error); - if (fw_blob == NULL) - return FALSE; /* check firmware will fit */ + fw_blob = fu_altos_firmware_get_data (altos_firmware); data = g_bytes_get_data (fw_blob, (gsize *) &data_len); if (data_len > flash_len) { g_set_error (error, diff --git a/plugins/altos/meson.build b/plugins/altos/meson.build index 7fefdc184..7ac89b17e 100644 --- a/plugins/altos/meson.build +++ b/plugins/altos/meson.build @@ -2,6 +2,7 @@ cargs = ['-DG_LOG_DOMAIN="FuPluginAltos"'] shared_module('fu_plugin_altos', sources : [ + 'fu-altos-firmware.c', 'fu-plugin-altos.c', 'fu-device-altos.c', ], @@ -14,17 +15,16 @@ shared_module('fu_plugin_altos', install_dir: plugin_dir, c_args : cargs, dependencies : [ - plugin_deps, gudev, - ], - link_with : [ - dfu, + libelf, + plugin_deps, ], ) executable( 'fu-altos-tool', sources : [ + 'fu-altos-firmware.c', 'fu-altos-tool.c', 'fu-device-altos.c', ], @@ -34,11 +34,11 @@ executable( include_directories('../../src'), ], dependencies : [ - plugin_deps, gudev, + libelf, + plugin_deps, ], link_with : [ - dfu, fwupd, libfwupdprivate, ], diff --git a/plugins/meson.build b/plugins/meson.build index 953ca870b..6d8635b94 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,4 +1,3 @@ -subdir('altos') subdir('dfu') subdir('ebitdo') subdir('raspberrypi') @@ -8,6 +7,10 @@ subdir('udev') subdir('unifying') subdir('upower') +if get_option('enable-altos') +subdir('altos') +endif + if get_option('enable-amt') subdir('amt') endif