Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
fe73b704
Unverified
Commit
fe73b704
authored
Aug 30, 2018
by
Dimitris Papastamos
Committed by
GitHub
Aug 30, 2018
Browse files
Merge pull request #1535 from antonio-nino-diaz-arm/an/backtrace
Introduce backtrace function
parents
0682291a
3e530d8e
Changes
9
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
fe73b704
...
...
@@ -100,6 +100,13 @@ else
LOG_LEVEL
:=
20
endif
# Enable backtrace by default in DEBUG AArch64 builds
ifeq
(${ARCH},aarch32)
ENABLE_BACKTRACE
:=
0
else
ENABLE_BACKTRACE
:=
${DEBUG}
endif
# Default build string (git branch and commit)
ifeq
(${BUILD_STRING},)
BUILD_STRING
:=
$(
shell
git describe
--always
--dirty
--tags
2> /dev/null
)
...
...
@@ -166,6 +173,14 @@ TF_CFLAGS_aarch64 = -march=armv8-a
LD
=
$(LINKER)
endif
ifeq
(${AARCH32_INSTRUCTION_SET},A32)
TF_CFLAGS_aarch32
+=
-marm
else
ifeq
(${AARCH32_INSTRUCTION_SET},T32)
TF_CFLAGS_aarch32
+=
-mthumb
else
$(error Error
:
Unknown AArch32 instruction set ${AARCH32_INSTRUCTION_SET})
endif
TF_CFLAGS_aarch32
+=
-mno-unaligned-access
TF_CFLAGS_aarch64
+=
-mgeneral-regs-only
-mstrict-align
...
...
@@ -188,6 +203,11 @@ ifneq ($(PIE_FOUND),)
TF_CFLAGS
+=
-fno-PIE
endif
# Force the compiler to include the frame pointer
ifeq
(${ENABLE_BACKTRACE},1)
TF_CFLAGS
+=
-fno-omit-frame-pointer
endif
TF_LDFLAGS
+=
--fatal-warnings
-O1
TF_LDFLAGS
+=
--gc-sections
TF_LDFLAGS
+=
$
(
TF_LDFLAGS_
$(ARCH)
)
...
...
@@ -215,6 +235,10 @@ ifeq ($(notdir $(CC)),armclang)
BL_COMMON_SOURCES
+=
lib/
${ARCH}
/armclang_printf.S
endif
ifeq
(${ENABLE_BACKTRACE},1)
BL_COMMON_SOURCES
+=
common/backtrace.c
endif
INCLUDES
+=
-Iinclude
\
-Iinclude
/bl1
\
-Iinclude
/bl2
\
...
...
@@ -345,6 +369,15 @@ endif
# Check incompatible options
################################################################################
ifeq
(${ARCH},aarch32)
ifeq
(${ENABLE_BACKTRACE},1)
ifneq
(${AARCH32_INSTRUCTION_SET},A32)
$(error Error
:
AARCH32_INSTRUCTION_SET=A32 is needed
\
for ENABLE_BACKTRACE when compiling for AArch32.)
endif
endif
endif
ifdef
EL3_PAYLOAD_BASE
ifdef
PRELOADED_BL33_BASE
$(warning
"PRELOADED_BL33_BASE
and
EL3_PAYLOAD_BASE
are
\
...
...
@@ -551,6 +584,7 @@ $(eval $(call assert_boolean,DYN_DISABLE_AUTH))
$(eval
$(call
assert_boolean,EL3_EXCEPTION_HANDLING))
$(eval
$(call
assert_boolean,ENABLE_AMU))
$(eval
$(call
assert_boolean,ENABLE_ASSERTIONS))
$(eval
$(call
assert_boolean,ENABLE_BACKTRACE))
$(eval
$(call
assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS))
$(eval
$(call
assert_boolean,ENABLE_PLAT_COMPAT))
$(eval
$(call
assert_boolean,ENABLE_PMF))
...
...
@@ -603,6 +637,7 @@ $(eval $(call add_define,CTX_INCLUDE_FPREGS))
$(eval
$(call
add_define,EL3_EXCEPTION_HANDLING))
$(eval
$(call
add_define,ENABLE_AMU))
$(eval
$(call
add_define,ENABLE_ASSERTIONS))
$(eval
$(call
add_define,ENABLE_BACKTRACE))
$(eval
$(call
add_define,ENABLE_MPAM_FOR_LOWER_ELS))
$(eval
$(call
add_define,ENABLE_PLAT_COMPAT))
$(eval
$(call
add_define,ENABLE_PMF))
...
...
common/backtrace.c
0 → 100644
View file @
fe73b704
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <console.h>
#include <debug.h>
#include <stdbool.h>
#include <stdint.h>
/* Maximum number of entries in the backtrace to display */
#define UNWIND_LIMIT 20U
/*
* If -fno-omit-frame-pointer is used:
*
* - AArch64: The AAPCS defines the format of the frame records and mandates the
* usage of r29 as frame pointer.
*
* - AArch32: The format of the frame records is not defined in the AAPCS.
* However, at least GCC and Clang use the same format. When they are forced
* to only generate A32 code (with -marm), they use r11 as frame pointer and a
* similar format as in AArch64. If interworking with T32 is enabled, the
* frame pointer is r7 and the format is different. This is not supported by
* this implementation of backtrace, so it is needed to use -marm.
*/
/* Frame records form a linked list in the stack */
struct
frame_record
{
/* Previous frame record in the list */
struct
frame_record
*
parent
;
/* Return address of the function at this level */
uintptr_t
return_addr
;
};
static
const
char
*
get_el_str
(
unsigned
int
el
)
{
if
(
el
==
3U
)
{
return
"EL3"
;
}
else
if
(
el
==
2U
)
{
return
"EL2"
;
}
else
{
return
"S-EL1"
;
}
}
/*
* Returns true if the address points to a virtual address that can be read at
* the current EL, false otherwise.
*/
#ifdef AARCH64
static
bool
is_address_readable
(
uintptr_t
addr
)
{
unsigned
int
el
=
get_current_el
();
if
(
el
==
3U
)
{
ats1e3r
(
addr
);
}
else
if
(
el
==
2U
)
{
ats1e2r
(
addr
);
}
else
{
ats1e1r
(
addr
);
}
isb
();
/* If PAR.F == 1 the address translation was aborted. */
if
((
read_par_el1
()
&
PAR_F_MASK
)
!=
0U
)
return
false
;
return
true
;
}
#else
/* if AARCH32 */
static
bool
is_address_readable
(
uintptr_t
addr
)
{
unsigned
int
el
=
get_current_el
();
if
(
el
==
3U
)
{
write_ats1cpr
(
addr
);
}
else
if
(
el
==
2U
)
{
write_ats1hr
(
addr
);
}
else
{
write_ats1cpr
(
addr
);
}
isb
();
/* If PAR.F == 1 the address translation was aborted. */
if
((
read64_par
()
&
PAR_F_MASK
)
!=
0U
)
return
false
;
return
true
;
}
#endif
/*
* Returns true if all the bytes in a given object are in mapped memory and an
* LDR using this pointer would succeed, false otherwise.
*/
static
bool
is_valid_object
(
uintptr_t
addr
,
size_t
size
)
{
assert
(
size
>
0U
);
if
(
addr
==
0U
)
return
false
;
/* Detect overflows */
if
((
addr
+
size
)
<
addr
)
return
false
;
/* A pointer not aligned properly could trigger an alignment fault. */
if
((
addr
&
(
sizeof
(
uintptr_t
)
-
1U
))
!=
0U
)
return
false
;
/* Check that all the object is readable */
for
(
size_t
i
=
0
;
i
<
size
;
i
++
)
{
if
(
!
is_address_readable
(
addr
+
i
))
return
false
;
}
return
true
;
}
/*
* Returns true if the specified address is correctly aligned and points to a
* valid memory region.
*/
static
bool
is_valid_jump_address
(
uintptr_t
addr
)
{
if
(
addr
==
0U
)
return
false
;
/* Check alignment. Both A64 and A32 use 32-bit opcodes */
if
((
addr
&
(
sizeof
(
uint32_t
)
-
1U
))
!=
0U
)
return
false
;
if
(
!
is_address_readable
(
addr
))
return
false
;
return
true
;
}
/*
* Returns true if the pointer points at a valid frame record, false otherwise.
*/
static
bool
is_valid_frame_record
(
struct
frame_record
*
fr
)
{
return
is_valid_object
((
uintptr_t
)
fr
,
sizeof
(
struct
frame_record
));
}
/*
* Adjust the frame-pointer-register value by 4 bytes on AArch32 to have the
* same layout as AArch64.
*/
static
struct
frame_record
*
adjust_frame_record
(
struct
frame_record
*
fr
)
{
#ifdef AARCH64
return
fr
;
#else
return
(
struct
frame_record
*
)((
uintptr_t
)
fr
-
4U
);
#endif
}
static
void
unwind_stack
(
struct
frame_record
*
fr
,
uintptr_t
current_pc
,
uintptr_t
link_register
)
{
uintptr_t
call_site
;
static
const
char
*
backtrace_str
=
"%u: %s: 0x%lx
\n
"
;
const
char
*
el_str
=
get_el_str
(
get_current_el
());
if
(
!
is_valid_frame_record
(
fr
))
{
printf
(
"ERROR: Corrupted frame pointer (frame record address = %p)
\n
"
,
fr
);
return
;
}
if
(
fr
->
return_addr
!=
link_register
)
{
printf
(
"ERROR: Corrupted stack (frame record address = %p)
\n
"
,
fr
);
return
;
}
/* The level 0 of the backtrace is the current backtrace function */
printf
(
backtrace_str
,
0U
,
el_str
,
current_pc
);
/*
* The last frame record pointer in the linked list at the beginning of
* the stack should be NULL unless stack is corrupted.
*/
for
(
unsigned
int
i
=
1U
;
i
<
UNWIND_LIMIT
;
i
++
)
{
/* If an invalid frame record is found, exit. */
if
(
!
is_valid_frame_record
(
fr
))
return
;
/*
* A32 and A64 are fixed length so the address from where the
* call was made is the instruction before the return address,
* which is always 4 bytes before it.
*/
call_site
=
fr
->
return_addr
-
4U
;
/*
* If the address is invalid it means that the frame record is
* probably corrupted.
*/
if
(
!
is_valid_jump_address
(
call_site
))
return
;
printf
(
backtrace_str
,
i
,
el_str
,
call_site
);
fr
=
adjust_frame_record
(
fr
->
parent
);
}
printf
(
"ERROR: Max backtrace depth reached
\n
"
);
}
/*
* Display a backtrace. The cookie string parameter is displayed along the
* trace to help filter the log messages.
*
* Many things can prevent displaying the expected backtrace. For example,
* compiler optimizations can use a branch instead of branch with link when it
* detects a tail call. The backtrace level for this caller will not be
* displayed, as it does not appear in the call stack anymore. Also, assembly
* functions will not be displayed unless they setup AAPCS compliant frame
* records on AArch64 and compliant with GCC-specific frame record format on
* AArch32.
*
* Usage of the trace: addr2line can be used to map the addresses to function
* and source code location when given the ELF file compiled with debug
* information. The "-i" flag is highly recommended to improve display of
* inlined function. The *.dump files generated when buildidng each image can
* also be used.
*
* WARNING: In case of corrupted stack, this function could display security
* sensitive information past the beginning of the stack so it must not be used
* in production build. This function is only compiled in when ENABLE_BACKTRACE
* is set to 1.
*/
void
backtrace
(
const
char
*
cookie
)
{
uintptr_t
return_address
=
(
uintptr_t
)
__builtin_return_address
(
0U
);
struct
frame_record
*
fr
=
__builtin_frame_address
(
0U
);
/* Printing the backtrace may crash the system, flush before starting */
(
void
)
console_flush
();
fr
=
adjust_frame_record
(
fr
);
printf
(
"BACKTRACE: START: %s
\n
"
,
cookie
);
unwind_stack
(
fr
,
(
uintptr_t
)
&
backtrace
,
return_address
);
printf
(
"BACKTRACE: END: %s
\n
"
,
cookie
);
}
docs/user-guide.rst
View file @
fe73b704
...
...
@@ -75,7 +75,7 @@ In addition, the following optional packages and tools may be needed:
-
To
create
and
modify
the
diagram
files
included
in
the
documentation
,
`
Dia
`
_
.
This
tool
can
be
found
in
most
Linux
distributions
.
Inkscape
is
needed
to
generate
the
actual
*.
png
files
.
generate
the
actual
\
*.
png
files
.
Getting
the
TF
-
A
source
code
----------------------------
...
...
@@ -212,6 +212,10 @@ performed.
Common build options
^^^^^^^^^^^^^^^^^^^^
- ``AARCH32_INSTRUCTION_SET``: Choose the AArch32 instruction set that the
compiler should use. Valid values are T32 and A32. It defaults to T32 due to
code having a smaller resulting size.
- ``AARCH32_SP`` : Choose the AArch32 Secure Payload component to be built as
as the BL32 image when ``ARCH=aarch32``. The value should be the path to the
directory containing the SP source, relative to the ``bl32/``; the directory
...
...
@@ -351,6 +355,16 @@ Common build options
that
is
only
required
for
the
assertion
and
does
not
fit
in
the
assertion
itself
.
-
``
ENABLE_BACKTRACE
``:
This
option
controls
whether
to
enables
backtrace
dumps
or
not
.
It
is
supported
in
both
AArch64
and
AArch32
.
However
,
in
AArch32
the
format
of
the
frame
records
are
not
defined
in
the
AAPCS
and
they
are
defined
by
the
implementation
.
This
implementation
of
backtrace
only
supports
the
format
used
by
GCC
when
T32
interworking
is
disabled
.
For
this
reason
enabling
this
option
in
AArch32
will
force
the
compiler
to
only
generate
A32
code
.
This
option
is
enabled
by
default
only
in
AArch64
debug
builds
,
but
this
behaviour
can
be
overriden
in
each
platform
's Makefile or in
the build command line.
- ``ENABLE_MPAM_FOR_LOWER_ELS``: Boolean option to enable lower ELs to use MPAM
feature. MPAM is an optional Armv8.4 extension that enables various memory
system components and resources to define partitions; software running at
...
...
include/common/debug.h
View file @
fe73b704
...
...
@@ -27,7 +27,9 @@
#ifndef __ASSEMBLY__
#include <cdefs.h>
#include <console.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
/*
...
...
@@ -83,8 +85,20 @@
# define VERBOSE(...) no_tf_log(LOG_MARKER_VERBOSE __VA_ARGS__)
#endif
#if ENABLE_BACKTRACE
void
backtrace
(
const
char
*
cookie
);
#else
#define backtrace(x)
#endif
void
__dead2
do_panic
(
void
);
#define panic() do_panic()
#define panic() \
do { \
backtrace(__func__); \
(void)console_flush(); \
do_panic(); \
} while (false)
/* Function called when stack protection check code detects a corrupted stack */
void
__dead2
__stack_chk_fail
(
void
);
...
...
include/lib/aarch32/arch.h
View file @
fe73b704
...
...
@@ -473,6 +473,8 @@
#define CCSIDR p15, 1, c0, c0, 0
#define HTCR p15, 4, c2, c0, 2
#define HMAIR0 p15, 4, c10, c2, 0
#define ATS1CPR p15, 0, c7, c8, 0
#define ATS1HR p15, 4, c7, c8, 0
#define DBGOSDLR p14, 0, c1, c3, 4
/* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */
...
...
@@ -513,6 +515,7 @@
#define VTTBR_64 p15, 6, c2
#define CNTPCT_64 p15, 0, c14
#define HTTBR_64 p15, 4, c2
#define PAR_64 p15, 0, c7
/* 64 bit GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRm */
#define ICC_SGI1R_EL1_64 p15, 0, c12
...
...
@@ -569,6 +572,12 @@
#define MAKE_MAIR_NORMAL_MEMORY(inner, outer) \
((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT))
/* PAR fields */
#define PAR_F_SHIFT U(0)
#define PAR_F_MASK ULL(0x1)
#define PAR_ADDR_SHIFT U(12)
#define PAR_ADDR_MASK (BIT(40) - ULL(1))
/* 40-bits-wide page address */
/*******************************************************************************
* Definitions for system register interface to AMU for ARMv8.4 onwards
******************************************************************************/
...
...
include/lib/aarch32/arch_helpers.h
View file @
fe73b704
...
...
@@ -276,6 +276,10 @@ DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR)
DEFINE_COPROCR_RW_FUNCS
(
cnthp_ctl
,
CNTHP_CTL
)
DEFINE_COPROCR_READ_FUNC
(
pmcr
,
PMCR
)
DEFINE_COPROCR_RW_FUNCS
(
ats1cpr
,
ATS1CPR
)
DEFINE_COPROCR_RW_FUNCS
(
ats1hr
,
ATS1HR
)
DEFINE_COPROCR_RW_FUNCS_64
(
par
,
PAR_64
)
DEFINE_COPROCR_RW_FUNCS
(
nsacr
,
NSACR
)
/* AArch32 coproc registers for 32bit MMU descriptor support */
...
...
@@ -333,6 +337,17 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
((GET_M32(read_cpsr()) == MODE32_mon) || \
(IS_IN_SECURE() && (GET_M32(read_cpsr()) != MODE32_usr)))
static
inline
unsigned
int
get_current_el
(
void
)
{
if
(
IS_IN_EL3
())
{
return
3U
;
}
else
if
(
IS_IN_EL2
())
{
return
2U
;
}
else
{
return
1U
;
}
}
/* Macros for compatibility with AArch64 system registers */
#define read_mpidr_el1() read_mpidr()
...
...
include/lib/aarch64/arch_helpers.h
View file @
fe73b704
...
...
@@ -155,7 +155,9 @@ DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s12e1w
)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s12e0r
)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s12e0w
)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s1e1r
)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s1e2r
)
DEFINE_SYSOP_TYPE_PARAM_FUNC
(
at
,
s1e3r
)
void
flush_dcache_range
(
uintptr_t
addr
,
size_t
size
);
void
clean_dcache_range
(
uintptr_t
addr
,
size_t
size
);
...
...
@@ -353,6 +355,12 @@ DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
#define IS_IN_EL1() IS_IN_EL(1)
#define IS_IN_EL3() IS_IN_EL(3)
#define IS_IN_EL3() IS_IN_EL(3)
static
inline
unsigned
int
get_current_el
(
void
)
{
return
GET_EL
(
read_CurrentEl
());
}
/*
* Check if an EL is implemented from AA64PFR0 register fields. 'el' argument
...
...
lib/libc/assert.c
View file @
fe73b704
...
...
@@ -20,19 +20,23 @@
void
__assert
(
const
char
*
file
,
unsigned
int
line
,
const
char
*
assertion
)
{
printf
(
"ASSERT: %s:%d:%s
\n
"
,
file
,
line
,
assertion
);
console_flush
();
backtrace
(
"assert"
);
(
void
)
console_flush
();
plat_panic_handler
();
}
#elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO
void
__assert
(
const
char
*
file
,
unsigned
int
line
)
{
printf
(
"ASSERT: %s:%d
\n
"
,
file
,
line
);
console_flush
();
backtrace
(
"assert"
);
(
void
)
console_flush
();
plat_panic_handler
();
}
#else
void
__assert
(
void
)
{
backtrace
(
"assert"
);
(
void
)
console_flush
();
plat_panic_handler
();
}
#endif
make_helpers/defaults.mk
View file @
fe73b704
...
...
@@ -10,6 +10,9 @@
# poised to handle dependencies, as all build variables would have a default
# value by then.
# Use T32 by default
AARCH32_INSTRUCTION_SET
:=
T32
# The AArch32 Secure Payload to be built as BL32 image
AARCH32_SP
:=
none
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment