grub/include/grub/misc.h
Darren Kenny 8505f73003 gnulib: Provide abort() implementation for gnulib
The recent gnulib updates require an implementation of abort(), but the
current macro provided by changeset:

  cd37d3d3916c gnulib: Drop no-abort.patch

to config.h.in does not work with the clang compiler since it doesn't
provide a __builtin_trap() implementation, so this element of the
changeset needs to be reverted, and replaced.

After some discussion with Vladimir 'phcoder' Serbinenko and Daniel Kiper
it was suggested to bring back in the change from the changeset:

  db7337a3d353 * grub-core/gnulib/regcomp.c (regerror): ...

Which implements abort() as an inline call to grub_abort(), but since
that was made static by changeset:

  a8f15bceeafe * grub-core/kern/misc.c (grub_abort): Make static

it is also necessary to revert the specific part that makes it a static
function too.

Another implementation of abort() was found in grub-core/kern/compiler-rt.c
which needs to also be removed to be consistent.

Signed-off-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
2022-10-27 16:14:14 +02:00

532 lines
14 KiB
C

/* misc.h - prototypes for misc functions */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB 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.
*
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_MISC_HEADER
#define GRUB_MISC_HEADER 1
#include <stdarg.h>
#include <grub/types.h>
#include <grub/symbol.h>
#include <grub/err.h>
#include <grub/i18n.h>
#include <grub/compiler.h>
#define ALIGN_UP(addr, align) \
(((addr) + (typeof (addr)) (align) - 1) & ~((typeof (addr)) (align) - 1))
#define ALIGN_UP_OVERHEAD(addr, align) ((-(addr)) & ((typeof (addr)) (align) - 1))
#define ALIGN_DOWN(addr, align) \
((addr) & ~((typeof (addr)) (align) - 1))
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src);
static inline char *
grub_strncpy (char *dest, const char *src, int c)
{
char *p = dest;
while ((*p++ = *src++) != '\0' && --c)
;
return dest;
}
static inline char *
grub_stpcpy (char *dest, const char *src)
{
char *d = dest;
const char *s = src;
do
*d++ = *s;
while (*s++ != '\0');
return d - 1;
}
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
static inline void *
grub_memcpy (void *dest, const void *src, grub_size_t n)
{
return grub_memmove (dest, src, n);
}
#if defined(__x86_64__) && !defined (GRUB_UTIL)
#if defined (__MINGW32__) || defined (__CYGWIN__) || defined (__MINGW64__)
#define GRUB_ASM_ATTR __attribute__ ((sysv_abi))
#else
#define GRUB_ASM_ATTR
#endif
#endif
int EXPORT_FUNC(grub_memcmp) (const void *s1, const void *s2, grub_size_t n);
int EXPORT_FUNC(grub_strcmp) (const char *s1, const char *s2);
int EXPORT_FUNC(grub_strncmp) (const char *s1, const char *s2, grub_size_t n);
char *EXPORT_FUNC(grub_strchr) (const char *s, int c);
char *EXPORT_FUNC(grub_strrchr) (const char *s, int c);
int EXPORT_FUNC(grub_strword) (const char *s, const char *w);
/* Copied from gnulib.
Written by Bruno Haible <bruno@clisp.org>, 2005. */
static inline char *
grub_strstr (const char *haystack, const char *needle)
{
/* Be careful not to look at the entire extent of haystack or needle
until needed. This is useful because of these two cases:
- haystack may be very long, and a match of needle found early,
- needle may be very long, and not even a short initial segment of
needle may be found in haystack. */
if (*needle != '\0')
{
/* Speed up the following searches of needle by caching its first
character. */
char b = *needle++;
for (;; haystack++)
{
if (*haystack == '\0')
/* No match. */
return 0;
if (*haystack == b)
/* The first character matches. */
{
const char *rhaystack = haystack + 1;
const char *rneedle = needle;
for (;; rhaystack++, rneedle++)
{
if (*rneedle == '\0')
/* Found a match. */
return (char *) haystack;
if (*rhaystack == '\0')
/* No match. */
return 0;
if (*rhaystack != *rneedle)
/* Nothing in this round. */
break;
}
}
}
}
else
return (char *) haystack;
}
int EXPORT_FUNC(grub_isspace) (int c);
static inline int
grub_isprint (int c)
{
return (c >= ' ' && c <= '~');
}
static inline int
grub_iscntrl (int c)
{
return (c >= 0x00 && c <= 0x1F) || c == 0x7F;
}
static inline int
grub_isalpha (int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static inline int
grub_islower (int c)
{
return (c >= 'a' && c <= 'z');
}
static inline int
grub_isupper (int c)
{
return (c >= 'A' && c <= 'Z');
}
static inline int
grub_isgraph (int c)
{
return (c >= '!' && c <= '~');
}
static inline int
grub_isdigit (int c)
{
return (c >= '0' && c <= '9');
}
static inline int
grub_isxdigit (int c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
static inline int
grub_isalnum (int c)
{
return grub_isalpha (c) || grub_isdigit (c);
}
static inline int
grub_tolower (int c)
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}
static inline int
grub_toupper (int c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
return c;
}
static inline int
grub_strcasecmp (const char *s1, const char *s2)
{
while (*s1 && *s2)
{
if (grub_tolower ((grub_uint8_t) *s1)
!= grub_tolower ((grub_uint8_t) *s2))
break;
s1++;
s2++;
}
return (int) grub_tolower ((grub_uint8_t) *s1)
- (int) grub_tolower ((grub_uint8_t) *s2);
}
static inline int
grub_strncasecmp (const char *s1, const char *s2, grub_size_t n)
{
if (n == 0)
return 0;
while (*s1 && *s2 && --n)
{
if (grub_tolower ((grub_uint8_t) *s1)
!= grub_tolower ((grub_uint8_t) *s2))
break;
s1++;
s2++;
}
return (int) grub_tolower ((grub_uint8_t) *s1)
- (int) grub_tolower ((grub_uint8_t) *s2);
}
/*
* Do a case insensitive compare of two UUID strings by ignoring all dashes.
* Note that the parameter n, is the number of significant characters to
* compare, where significant characters are any except the dash.
*/
static inline int
grub_uuidcasecmp (const char *uuid1, const char *uuid2, grub_size_t n)
{
if (n == 0)
return 0;
while (*uuid1 && *uuid2 && --n)
{
/* Skip forward to non-dash on both UUIDs. */
while ('-' == *uuid1)
++uuid1;
while ('-' == *uuid2)
++uuid2;
if (grub_tolower ((grub_uint8_t) *uuid1) != grub_tolower ((grub_uint8_t) *uuid2))
break;
uuid1++;
uuid2++;
}
return (int) grub_tolower ((grub_uint8_t) *uuid1) - (int) grub_tolower ((grub_uint8_t) *uuid2);
}
/*
* Note that these differ from the C standard's definitions of strtol,
* strtoul(), and strtoull() by the addition of two const qualifiers on the end
* pointer, which make the declaration match the *semantic* requirements of
* their behavior. This means that instead of:
*
* char *s = "1234 abcd";
* char *end;
* unsigned long l;
*
* l = grub_strtoul(s, &end, 10);
*
* We must one of:
*
* const char *end;
* ... or ...
* l = grub_strtoul(s, (const char ** const)&end, 10);
*/
unsigned long EXPORT_FUNC(grub_strtoul) (const char * restrict str, const char ** const restrict end, int base);
unsigned long long EXPORT_FUNC(grub_strtoull) (const char * restrict str, const char ** const restrict end, int base);
static inline long
grub_strtol (const char * restrict str, const char ** const restrict end, int base)
{
int negative = 0;
unsigned long long magnitude;
while (*str && grub_isspace (*str))
str++;
if (*str == '-')
{
negative = 1;
str++;
}
magnitude = grub_strtoull (str, end, base);
if (negative)
{
if (magnitude > (unsigned long) GRUB_LONG_MAX + 1)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
return GRUB_LONG_MIN;
}
return -((long) magnitude);
}
else
{
if (magnitude > GRUB_LONG_MAX)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
return GRUB_LONG_MAX;
}
return (long) magnitude;
}
}
char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT;
char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) WARN_UNUSED_RESULT;
void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n);
grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) WARN_UNUSED_RESULT;
int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2)));
int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2)));
/* Replace all `ch' characters of `input' with `with' and copy the
result into `output'; return EOS address of `output'. */
static inline char *
grub_strchrsub (char *output, const char *input, char ch, const char *with)
{
while (*input)
{
if (*input == ch)
{
grub_strcpy (output, with);
output += grub_strlen (with);
input++;
continue;
}
*output++ = *input++;
}
*output = '\0';
return output;
}
extern void (*EXPORT_VAR (grub_xputs)) (const char *str);
static inline int
grub_puts (const char *s)
{
const char nl[2] = "\n";
grub_xputs (s);
grub_xputs (nl);
return 1; /* Cannot fail. */
}
int EXPORT_FUNC(grub_puts_) (const char *s);
int EXPORT_FUNC(grub_debug_enabled) (const char *condition);
void EXPORT_FUNC(grub_real_dprintf) (const char *file,
const int line,
const char *condition,
const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5)));
int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args);
int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...)
__attribute__ ((format (GNU_PRINTF, 3, 4)));
int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt,
va_list args);
char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...)
__attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT;
char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT;
void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn));
void EXPORT_FUNC(grub_abort) (void) __attribute__ ((noreturn));
grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t d,
grub_uint64_t *r);
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \
(defined(__riscv) && (__riscv_xlen == 32)))
#define GRUB_DIVISION_IN_SOFTWARE 1
#else
#define GRUB_DIVISION_IN_SOFTWARE 0
#endif
/* Some division functions need to be in kernel if compiler generates calls
to them. Otherwise we still need them for consistent tests but they go
into a separate module. */
#if GRUB_DIVISION_IN_SOFTWARE
#define EXPORT_FUNC_IF_SOFTDIV EXPORT_FUNC
#else
#define EXPORT_FUNC_IF_SOFTDIV(x) x
#endif
grub_int64_t
EXPORT_FUNC_IF_SOFTDIV(grub_divmod64s) (grub_int64_t n,
grub_int64_t d,
grub_int64_t *r);
grub_uint32_t
EXPORT_FUNC_IF_SOFTDIV (grub_divmod32) (grub_uint32_t n,
grub_uint32_t d,
grub_uint32_t *r);
grub_int32_t
EXPORT_FUNC_IF_SOFTDIV (grub_divmod32s) (grub_int32_t n,
grub_int32_t d,
grub_int32_t *r);
/* Inline functions. */
static inline char *
grub_memchr (const void *p, int c, grub_size_t len)
{
const char *s = (const char *) p;
const char *e = s + len;
for (; s < e; s++)
if (*s == c)
return (char *) s;
return 0;
}
static inline unsigned int
grub_abs (int x)
{
if (x < 0)
return (unsigned int) (-x);
else
return (unsigned int) x;
}
/* Reboot the machine. */
#if defined (GRUB_MACHINE_EMU) || defined (GRUB_MACHINE_QEMU_MIPS) || \
defined (GRUB_MACHINE_EFI)
void EXPORT_FUNC(grub_reboot) (void) __attribute__ ((noreturn));
#else
void grub_reboot (void) __attribute__ ((noreturn));
#endif
#ifdef GRUB_MACHINE_PCBIOS
/* Halt the system, using APM if possible. If NO_APM is true, don't
* use APM even if it is available. */
void grub_halt (int no_apm) __attribute__ ((noreturn));
#elif defined (__mips__) && !defined (GRUB_MACHINE_EMU)
void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn));
#else
void grub_halt (void) __attribute__ ((noreturn));
#endif
#ifdef GRUB_MACHINE_EMU
/* Flag to check if module loading is available. */
extern const int EXPORT_VAR(grub_no_modules);
#else
#define grub_no_modules 0
#endif
static inline void
grub_error_save (struct grub_error_saved *save)
{
grub_memcpy (save->errmsg, grub_errmsg, sizeof (save->errmsg));
save->grub_errno = grub_errno;
grub_errno = GRUB_ERR_NONE;
}
static inline void
grub_error_load (const struct grub_error_saved *save)
{
grub_memcpy (grub_errmsg, save->errmsg, sizeof (grub_errmsg));
grub_errno = save->grub_errno;
}
/*
* grub_printf_fmt_checks() a fmt string for printf() against an expected
* format. It is intended for cases where the fmt string could come from
* an outside source and cannot be trusted.
*
* While expected fmt accepts a printf() format string it should be kept
* as simple as possible. The printf() format strings with positional
* parameters are NOT accepted, neither for fmt nor for fmt_expected.
*
* The fmt is accepted if it has equal or less arguments than fmt_expected
* and if the type of all arguments match.
*
* Returns GRUB_ERR_NONE if fmt is acceptable.
*/
grub_err_t EXPORT_FUNC (grub_printf_fmt_check) (const char *fmt, const char *fmt_expected);
#if BOOT_TIME_STATS
struct grub_boot_time
{
struct grub_boot_time *next;
grub_uint64_t tp;
const char *file;
int line;
char *msg;
};
extern struct grub_boot_time *EXPORT_VAR(grub_boot_time_head);
void EXPORT_FUNC(grub_real_boot_time) (const char *file,
const int line,
const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4)));
#define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__)
#else
#define grub_boot_time(...)
#endif
#define grub_max(a, b) (((a) > (b)) ? (a) : (b))
#define grub_min(a, b) (((a) < (b)) ? (a) : (b))
#define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1)
#endif /* ! GRUB_MISC_HEADER */