2016-06-03 06:33:17 +03:00
# include "unwind.h"
# include "thread.h"
2016-06-03 06:33:19 +03:00
# include "session.h"
# include "debug.h"
# include "arch/common.h"
2016-06-03 06:33:17 +03:00
struct unwind_libunwind_ops __weak * local_unwind_libunwind_ops ;
2016-06-03 06:33:22 +03:00
struct unwind_libunwind_ops __weak * x86_32_unwind_libunwind_ops ;
2016-06-03 06:33:23 +03:00
struct unwind_libunwind_ops __weak * arm64_unwind_libunwind_ops ;
2016-06-03 06:33:17 +03:00
static void unwind__register_ops ( struct thread * thread ,
struct unwind_libunwind_ops * ops )
{
thread - > unwind_libunwind_ops = ops ;
}
2016-07-04 15:16:22 +03:00
int unwind__prepare_access ( struct thread * thread , struct map * map ,
bool * initialized )
2016-06-03 06:33:17 +03:00
{
2016-06-03 06:33:19 +03:00
const char * arch ;
enum dso_type dso_type ;
2016-06-03 06:33:22 +03:00
struct unwind_libunwind_ops * ops = local_unwind_libunwind_ops ;
2016-07-04 15:16:22 +03:00
int err ;
2016-06-03 06:33:19 +03:00
if ( thread - > addr_space ) {
pr_debug ( " unwind: thread map already set, dso=%s \n " ,
map - > dso - > name ) ;
2016-07-04 15:16:22 +03:00
if ( initialized )
* initialized = true ;
2016-06-03 06:33:19 +03:00
return 0 ;
}
/* env->arch is NULL for live-mode (i.e. perf top) */
if ( ! thread - > mg - > machine - > env | | ! thread - > mg - > machine - > env - > arch )
goto out_register ;
dso_type = dso__type ( map - > dso , thread - > mg - > machine ) ;
if ( dso_type = = DSO__TYPE_UNKNOWN )
return 0 ;
arch = normalize_arch ( thread - > mg - > machine - > env - > arch ) ;
2016-06-03 06:33:22 +03:00
if ( ! strcmp ( arch , " x86 " ) ) {
if ( dso_type ! = DSO__TYPE_64BIT )
ops = x86_32_unwind_libunwind_ops ;
2016-06-03 06:33:23 +03:00
} else if ( ! strcmp ( arch , " arm64 " ) | | ! strcmp ( arch , " arm " ) ) {
if ( dso_type = = DSO__TYPE_64BIT )
ops = arm64_unwind_libunwind_ops ;
2016-06-03 06:33:22 +03:00
}
if ( ! ops ) {
pr_err ( " unwind: target platform=%s is not supported \n " , arch ) ;
return - 1 ;
}
2016-06-03 06:33:19 +03:00
out_register :
2016-06-03 06:33:22 +03:00
unwind__register_ops ( thread , ops ) ;
2016-06-03 06:33:17 +03:00
2016-07-04 15:16:22 +03:00
err = thread - > unwind_libunwind_ops - > prepare_access ( thread ) ;
if ( initialized )
* initialized = err ? false : true ;
return err ;
2016-06-03 06:33:17 +03:00
}
void unwind__flush_access ( struct thread * thread )
{
if ( thread - > unwind_libunwind_ops )
thread - > unwind_libunwind_ops - > flush_access ( thread ) ;
}
void unwind__finish_access ( struct thread * thread )
{
if ( thread - > unwind_libunwind_ops )
thread - > unwind_libunwind_ops - > finish_access ( thread ) ;
}
int unwind__get_entries ( unwind_entry_cb_t cb , void * arg ,
struct thread * thread ,
struct perf_sample * data , int max_stack )
{
if ( thread - > unwind_libunwind_ops )
return thread - > unwind_libunwind_ops - > get_entries ( cb , arg , thread , data , max_stack ) ;
return 0 ;
}