GCC 15 added a new `unterminated-string-initialization` warning. Even though crossgcc is still using GCC 14, some Linux distributions (e.g. Arch Linux) already started shipping GCC 15. Given that coreboot uses `-Werror` (warnings are errors), this new warning causes build errors for things built using the host toolchain, such as utilities. In this case, cbfstool is affected, which prevents building coreboot images. The nonstring attribute is used to tell the compiler whether or not a string is intentionally not null terminated. Since the attribute is only included in GCC 15 for multidimensional character arrays (and even later for clang) we need to check the GCC version before using the attribute. On GCC version prior to GCC 15 the nonstring attribute will not be used, but that is not a problem since the unterminated-string-initialization warning only exists since GCC 15. So you can still build on all GCC versions as before. This way it also works if your host toolchain is GCC 15 (which builds commonlib code for cbfstool) and your coreboot cross toolchain is GCC 14 (which builds commonlib code for coreboot). Clang is a diffent matter. According to the documentation, the nonstring attribute only exists in version 21 which is not yet released by LLVM. TEST=Build qemu/Q35 successfully Change-Id: I919d71cb2811e91869ba1ff493a0719ddcc86c36 Signed-off-by: Angel Pons <th3fanbus@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/87825 Reviewed-by: Benjamin Doron <benjamin.doron00@gmail.com> Reviewed-by: Nicholas Chin <nic.c3.14@gmail.com> Reviewed-by: Matt DeVillier <matt.devillier@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
208 lines
4.2 KiB
C
208 lines
4.2 KiB
C
/* common utility functions for cbfstool */
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <libgen.h>
|
|
#include "common.h"
|
|
#include "cbfs.h"
|
|
|
|
/* Utilities */
|
|
int verbose = 0;
|
|
|
|
static off_t get_file_size(FILE *f)
|
|
{
|
|
off_t fsize;
|
|
fseek(f, 0, SEEK_END);
|
|
fsize = ftell(f);
|
|
fseek(f, 0, SEEK_SET);
|
|
return fsize;
|
|
}
|
|
|
|
/* Buffer and file I/O */
|
|
int buffer_create(struct buffer *buffer, size_t size, const char *name)
|
|
{
|
|
buffer->name = strdup(name);
|
|
buffer->offset = 0;
|
|
buffer->size = size;
|
|
buffer->data = (char *)malloc(buffer->size);
|
|
if (!buffer->data) {
|
|
fprintf(stderr, "buffer_create: Insufficient memory (0x%zx).\n",
|
|
size);
|
|
if (buffer->name) {
|
|
free(buffer->name);
|
|
buffer->name = NULL;
|
|
}
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int buffer_from_file_aligned_size(struct buffer *buffer, const char *filename,
|
|
size_t size_granularity)
|
|
{
|
|
FILE *fp = fopen(filename, "rb");
|
|
if (!fp) {
|
|
perror(filename);
|
|
return -1;
|
|
}
|
|
off_t file_size = get_file_size(fp);
|
|
if (file_size < 0) {
|
|
fprintf(stderr, "could not determine size of %s\n", filename);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (buffer_create(buffer, ALIGN_UP(file_size, size_granularity), filename)) {
|
|
fprintf(stderr, "could not allocate buffer\n");
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (fread(buffer->data, 1, file_size, fp) != (size_t)file_size) {
|
|
fprintf(stderr, "incomplete read: %s\n", filename);
|
|
fclose(fp);
|
|
buffer_delete(buffer);
|
|
return -1;
|
|
}
|
|
fclose(fp);
|
|
|
|
if (buffer->size > (size_t)file_size)
|
|
memset(buffer->data + file_size, 0xff, buffer->size - file_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int buffer_from_file(struct buffer *buffer, const char *filename)
|
|
{
|
|
return buffer_from_file_aligned_size(buffer, filename, 1);
|
|
}
|
|
|
|
int buffer_write_file(struct buffer *buffer, const char *filename)
|
|
{
|
|
FILE *fp = fopen(filename, "wb");
|
|
if (!fp) {
|
|
perror(filename);
|
|
return -1;
|
|
}
|
|
assert(buffer && buffer->data);
|
|
if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
|
|
fprintf(stderr, "incomplete write: %s\n", filename);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
void buffer_delete(struct buffer *buffer)
|
|
{
|
|
assert(buffer);
|
|
if (buffer->name) {
|
|
free(buffer->name);
|
|
buffer->name = NULL;
|
|
}
|
|
if (buffer->data) {
|
|
free(buffer_get_original_backing(buffer));
|
|
buffer->data = NULL;
|
|
}
|
|
buffer->offset = 0;
|
|
buffer->size = 0;
|
|
}
|
|
|
|
static struct {
|
|
uint32_t arch;
|
|
const char *name;
|
|
} arch_names[] = {
|
|
{ CBFS_ARCHITECTURE_AARCH64, "arm64" },
|
|
{ CBFS_ARCHITECTURE_ARM, "arm" },
|
|
{ CBFS_ARCHITECTURE_MIPS, "mips" },
|
|
{ CBFS_ARCHITECTURE_PPC64, "ppc64" },
|
|
/* power8 is a reasonable alias */
|
|
{ CBFS_ARCHITECTURE_PPC64, "power8" },
|
|
{ CBFS_ARCHITECTURE_RISCV, "riscv" },
|
|
{ CBFS_ARCHITECTURE_X86, "x86" },
|
|
{ CBFS_ARCHITECTURE_UNKNOWN, "unknown" }
|
|
};
|
|
|
|
uint32_t string_to_arch(const char *arch_string)
|
|
{
|
|
size_t i;
|
|
uint32_t ret = CBFS_ARCHITECTURE_UNKNOWN;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
|
|
if (!strcasecmp(arch_string, arch_names[i].name)) {
|
|
ret = arch_names[i].arch;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
const char *arch_to_string(uint32_t a)
|
|
{
|
|
size_t i;
|
|
const char *ret = NULL;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
|
|
if (a == arch_names[i].arch) {
|
|
ret = arch_names[i].name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void print_supported_architectures(void)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(arch_names); i++) {
|
|
printf(i == 0? " ":", ");
|
|
printf("%s", arch_names[i].name);
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
void print_supported_filetypes(void)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; filetypes[i].name; i++) {
|
|
printf(" %s%c", filetypes[i].name, filetypes[i + 1].name ? ',' : '\n');
|
|
if ((i%8) == 7)
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
uint64_t intfiletype(const char *name)
|
|
{
|
|
size_t i;
|
|
for (i = 0; filetypes[i].name; i++)
|
|
if (strcmp(filetypes[i].name, name) == 0)
|
|
return filetypes[i].type;
|
|
return -1;
|
|
}
|
|
|
|
char *bintohex(uint8_t *data, size_t len)
|
|
{
|
|
static const char __nonstring translate[16] = "0123456789abcdef";
|
|
|
|
char *result = malloc(len * 2 + 1);
|
|
if (result == NULL)
|
|
return NULL;
|
|
|
|
result[len*2] = '\0';
|
|
unsigned int i;
|
|
for (i = 0; i < len; i++) {
|
|
result[i*2] = translate[(data[i] >> 4) & 0xf];
|
|
result[i*2+1] = translate[data[i] & 0xf];
|
|
}
|
|
return result;
|
|
}
|