Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
8ec006c5
Commit
8ec006c5
authored
Oct 12, 2009
by
Paul Mundt
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'sh/dwarf-unwinder'
Conflicts: arch/sh/kernel/dwarf.c
parents
3d4e0cfb
5ab78ff6
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
183 additions
and
50 deletions
+183
-50
arch/sh/include/asm/dwarf.h
arch/sh/include/asm/dwarf.h
+16
-0
arch/sh/kernel/dwarf.c
arch/sh/kernel/dwarf.c
+135
-50
arch/sh/kernel/module.c
arch/sh/kernel/module.c
+32
-0
No files found.
arch/sh/include/asm/dwarf.h
View file @
8ec006c5
...
@@ -241,6 +241,12 @@ struct dwarf_cie {
...
@@ -241,6 +241,12 @@ struct dwarf_cie {
unsigned
long
flags
;
unsigned
long
flags
;
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
/*
* 'mod' will be non-NULL if this CIE came from a module's
* .eh_frame section.
*/
struct
module
*
mod
;
};
};
/**
/**
...
@@ -255,6 +261,12 @@ struct dwarf_fde {
...
@@ -255,6 +261,12 @@ struct dwarf_fde {
unsigned
char
*
instructions
;
unsigned
char
*
instructions
;
unsigned
char
*
end
;
unsigned
char
*
end
;
struct
list_head
link
;
struct
list_head
link
;
/*
* 'mod' will be non-NULL if this FDE came from a module's
* .eh_frame section.
*/
struct
module
*
mod
;
};
};
/**
/**
...
@@ -364,6 +376,10 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
...
@@ -364,6 +376,10 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
extern
struct
dwarf_frame
*
dwarf_unwind_stack
(
unsigned
long
,
extern
struct
dwarf_frame
*
dwarf_unwind_stack
(
unsigned
long
,
struct
dwarf_frame
*
);
struct
dwarf_frame
*
);
extern
void
dwarf_free_frame
(
struct
dwarf_frame
*
);
extern
int
dwarf_parse_section
(
char
*
,
char
*
,
struct
module
*
);
extern
void
dwarf_module_unload
(
struct
module
*
);
#endif
/* !__ASSEMBLY__ */
#endif
/* !__ASSEMBLY__ */
#define CFI_STARTPROC .cfi_startproc
#define CFI_STARTPROC .cfi_startproc
...
...
arch/sh/kernel/dwarf.c
View file @
8ec006c5
...
@@ -529,7 +529,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
...
@@ -529,7 +529,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start,
}
}
/**
/**
* dwarf_unwind_stack - recursively unwind the stack
* dwarf_free_frame - free the memory allocated for @frame
* @frame: the frame to free
*/
void
dwarf_free_frame
(
struct
dwarf_frame
*
frame
)
{
dwarf_frame_free_regs
(
frame
);
mempool_free
(
frame
,
dwarf_frame_pool
);
}
/**
* dwarf_unwind_stack - unwind the stack
*
* @pc: address of the function to unwind
* @pc: address of the function to unwind
* @prev: struct dwarf_frame of the previous stackframe on the callstack
* @prev: struct dwarf_frame of the previous stackframe on the callstack
*
*
...
@@ -547,9 +558,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
...
@@ -547,9 +558,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
unsigned
long
addr
;
unsigned
long
addr
;
/*
/*
* If
this is the first invocation of this recursive function w
e
* If
we're starting at the top of the stack we need get th
e
*
need get the contents of a physical register to get the CFA
*
contents of a physical register to get the CFA in order to
*
in order to
begin the virtual unwinding of the stack.
* begin the virtual unwinding of the stack.
*
*
* NOTE: the return address is guaranteed to be setup by the
* NOTE: the return address is guaranteed to be setup by the
* time this function makes its first function call.
* time this function makes its first function call.
...
@@ -571,9 +582,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
...
@@ -571,9 +582,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
fde
=
dwarf_lookup_fde
(
pc
);
fde
=
dwarf_lookup_fde
(
pc
);
if
(
!
fde
)
{
if
(
!
fde
)
{
/*
/*
* This is our normal exit path - the one that stops the
* This is our normal exit path. There are two reasons
* recursion. There's two reasons why we might exit
* why we might exit here,
* here,
*
*
* a) pc has no asscociated DWARF frame info and so
* a) pc has no asscociated DWARF frame info and so
* we don't know how to unwind this frame. This is
* we don't know how to unwind this frame. This is
...
@@ -615,10 +625,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
...
@@ -615,10 +625,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
}
else
{
}
else
{
/*
/*
* Again,
this is the first invocation of this
* Again,
we're starting from the top of the
*
recurisve function. We need to physically
*
stack. We need to physically read
*
read the contents of a register in order to
*
the contents of a register in order to get
*
get
the Canonical Frame Address for this
* the Canonical Frame Address for this
* function.
* function.
*/
*/
frame
->
cfa
=
dwarf_read_arch_reg
(
frame
->
cfa_register
);
frame
->
cfa
=
dwarf_read_arch_reg
(
frame
->
cfa_register
);
...
@@ -648,13 +658,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
...
@@ -648,13 +658,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
return
frame
;
return
frame
;
bail:
bail:
dwarf_frame_free_regs
(
frame
);
dwarf_free_frame
(
frame
);
mempool_free
(
frame
,
dwarf_frame_pool
);
return
NULL
;
return
NULL
;
}
}
static
int
dwarf_parse_cie
(
void
*
entry
,
void
*
p
,
unsigned
long
len
,
static
int
dwarf_parse_cie
(
void
*
entry
,
void
*
p
,
unsigned
long
len
,
unsigned
char
*
end
)
unsigned
char
*
end
,
struct
module
*
mod
)
{
{
struct
dwarf_cie
*
cie
;
struct
dwarf_cie
*
cie
;
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -750,6 +759,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
...
@@ -750,6 +759,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
cie
->
initial_instructions
=
p
;
cie
->
initial_instructions
=
p
;
cie
->
instructions_end
=
end
;
cie
->
instructions_end
=
end
;
cie
->
mod
=
mod
;
/* Add to list */
/* Add to list */
spin_lock_irqsave
(
&
dwarf_cie_lock
,
flags
);
spin_lock_irqsave
(
&
dwarf_cie_lock
,
flags
);
list_add_tail
(
&
cie
->
link
,
&
dwarf_cie_list
);
list_add_tail
(
&
cie
->
link
,
&
dwarf_cie_list
);
...
@@ -760,7 +771,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
...
@@ -760,7 +771,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
static
int
dwarf_parse_fde
(
void
*
entry
,
u32
entry_type
,
static
int
dwarf_parse_fde
(
void
*
entry
,
u32
entry_type
,
void
*
start
,
unsigned
long
len
,
void
*
start
,
unsigned
long
len
,
unsigned
char
*
end
)
unsigned
char
*
end
,
struct
module
*
mod
)
{
{
struct
dwarf_fde
*
fde
;
struct
dwarf_fde
*
fde
;
struct
dwarf_cie
*
cie
;
struct
dwarf_cie
*
cie
;
...
@@ -809,6 +820,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
...
@@ -809,6 +820,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
fde
->
instructions
=
p
;
fde
->
instructions
=
p
;
fde
->
end
=
end
;
fde
->
end
=
end
;
fde
->
mod
=
mod
;
/* Add to list. */
/* Add to list. */
spin_lock_irqsave
(
&
dwarf_fde_lock
,
flags
);
spin_lock_irqsave
(
&
dwarf_fde_lock
,
flags
);
list_add_tail
(
&
fde
->
link
,
&
dwarf_fde_list
);
list_add_tail
(
&
fde
->
link
,
&
dwarf_fde_list
);
...
@@ -832,10 +845,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
...
@@ -832,10 +845,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
while
(
1
)
{
while
(
1
)
{
frame
=
dwarf_unwind_stack
(
return_addr
,
_frame
);
frame
=
dwarf_unwind_stack
(
return_addr
,
_frame
);
if
(
_frame
)
{
if
(
_frame
)
dwarf_frame_free_regs
(
_frame
);
dwarf_free_frame
(
_frame
);
mempool_free
(
_frame
,
dwarf_frame_pool
);
}
_frame
=
frame
;
_frame
=
frame
;
...
@@ -845,6 +856,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
...
@@ -845,6 +856,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
return_addr
=
frame
->
return_addr
;
return_addr
=
frame
->
return_addr
;
ops
->
address
(
data
,
return_addr
,
1
);
ops
->
address
(
data
,
return_addr
,
1
);
}
}
if
(
frame
)
dwarf_free_frame
(
frame
);
}
}
static
struct
unwinder
dwarf_unwinder
=
{
static
struct
unwinder
dwarf_unwinder
=
{
...
@@ -874,15 +888,15 @@ static void dwarf_unwinder_cleanup(void)
...
@@ -874,15 +888,15 @@ static void dwarf_unwinder_cleanup(void)
}
}
/**
/**
* dwarf_unwinder_init - initialise the dwarf unwinder
* dwarf_parse_section - parse DWARF section
* @eh_frame_start: start address of the .eh_frame section
* @eh_frame_end: end address of the .eh_frame section
* @mod: the kernel module containing the .eh_frame section
*
*
* Build the data structures describing the .dwarf_frame section to
* Parse the information in a .eh_frame section.
* make it easier to lookup CIE and FDE entries. Because the
* .eh_frame section is packed as tightly as possible it is not
* easy to lookup the FDE for a given PC, so we build a list of FDE
* and CIE entries that make it easier.
*/
*/
static
int
__init
dwarf_unwinder_init
(
void
)
int
dwarf_parse_section
(
char
*
eh_frame_start
,
char
*
eh_frame_end
,
struct
module
*
mod
)
{
{
u32
entry_type
;
u32
entry_type
;
void
*
p
,
*
entry
;
void
*
p
,
*
entry
;
...
@@ -890,32 +904,12 @@ static int __init dwarf_unwinder_init(void)
...
@@ -890,32 +904,12 @@ static int __init dwarf_unwinder_init(void)
unsigned
long
len
;
unsigned
long
len
;
unsigned
int
c_entries
,
f_entries
;
unsigned
int
c_entries
,
f_entries
;
unsigned
char
*
end
;
unsigned
char
*
end
;
INIT_LIST_HEAD
(
&
dwarf_cie_list
);
INIT_LIST_HEAD
(
&
dwarf_fde_list
);
c_entries
=
0
;
c_entries
=
0
;
f_entries
=
0
;
f_entries
=
0
;
entry
=
&
__start_eh_frame
;
entry
=
eh_frame_start
;
dwarf_frame_cachep
=
kmem_cache_create
(
"dwarf_frames"
,
sizeof
(
struct
dwarf_frame
),
0
,
SLAB_PANIC
|
SLAB_HWCACHE_ALIGN
|
SLAB_NOTRACK
,
NULL
);
dwarf_reg_cachep
=
kmem_cache_create
(
"dwarf_regs"
,
sizeof
(
struct
dwarf_reg
),
0
,
SLAB_PANIC
|
SLAB_HWCACHE_ALIGN
|
SLAB_NOTRACK
,
NULL
);
dwarf_frame_pool
=
mempool_create
(
DWARF_FRAME_MIN_REQ
,
mempool_alloc_slab
,
mempool_free_slab
,
dwarf_frame_cachep
);
dwarf_reg_pool
=
mempool_create
(
DWARF_REG_MIN_REQ
,
while
((
char
*
)
entry
<
eh_frame_end
)
{
mempool_alloc_slab
,
mempool_free_slab
,
dwarf_reg_cachep
);
while
((
char
*
)
entry
<
__stop_eh_frame
)
{
p
=
entry
;
p
=
entry
;
count
=
dwarf_entry_len
(
p
,
&
len
);
count
=
dwarf_entry_len
(
p
,
&
len
);
...
@@ -927,6 +921,7 @@ static int __init dwarf_unwinder_init(void)
...
@@ -927,6 +921,7 @@ static int __init dwarf_unwinder_init(void)
* entry and move to the next one because 'len'
* entry and move to the next one because 'len'
* tells us where our next entry is.
* tells us where our next entry is.
*/
*/
err
=
-
EINVAL
;
goto
out
;
goto
out
;
}
else
}
else
p
+=
count
;
p
+=
count
;
...
@@ -938,13 +933,14 @@ static int __init dwarf_unwinder_init(void)
...
@@ -938,13 +933,14 @@ static int __init dwarf_unwinder_init(void)
p
+=
4
;
p
+=
4
;
if
(
entry_type
==
DW_EH_FRAME_CIE
)
{
if
(
entry_type
==
DW_EH_FRAME_CIE
)
{
err
=
dwarf_parse_cie
(
entry
,
p
,
len
,
end
);
err
=
dwarf_parse_cie
(
entry
,
p
,
len
,
end
,
mod
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
out
;
goto
out
;
else
else
c_entries
++
;
c_entries
++
;
}
else
{
}
else
{
err
=
dwarf_parse_fde
(
entry
,
entry_type
,
p
,
len
,
end
);
err
=
dwarf_parse_fde
(
entry
,
entry_type
,
p
,
len
,
end
,
mod
);
if
(
err
<
0
)
if
(
err
<
0
)
goto
out
;
goto
out
;
else
else
...
@@ -957,6 +953,95 @@ static int __init dwarf_unwinder_init(void)
...
@@ -957,6 +953,95 @@ static int __init dwarf_unwinder_init(void)
printk
(
KERN_INFO
"DWARF unwinder initialised: read %u CIEs, %u FDEs
\n
"
,
printk
(
KERN_INFO
"DWARF unwinder initialised: read %u CIEs, %u FDEs
\n
"
,
c_entries
,
f_entries
);
c_entries
,
f_entries
);
return
0
;
out:
return
err
;
}
/**
* dwarf_module_unload - remove FDE/CIEs associated with @mod
* @mod: the module that is being unloaded
*
* Remove any FDEs and CIEs from the global lists that came from
* @mod's .eh_frame section because @mod is being unloaded.
*/
void
dwarf_module_unload
(
struct
module
*
mod
)
{
struct
dwarf_fde
*
fde
;
struct
dwarf_cie
*
cie
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
dwarf_cie_lock
,
flags
);
again_cie:
list_for_each_entry
(
cie
,
&
dwarf_cie_list
,
link
)
{
if
(
cie
->
mod
==
mod
)
break
;
}
if
(
&
cie
->
link
!=
&
dwarf_cie_list
)
{
list_del
(
&
cie
->
link
);
kfree
(
cie
);
goto
again_cie
;
}
spin_unlock_irqrestore
(
&
dwarf_cie_lock
,
flags
);
spin_lock_irqsave
(
&
dwarf_fde_lock
,
flags
);
again_fde:
list_for_each_entry
(
fde
,
&
dwarf_fde_list
,
link
)
{
if
(
fde
->
mod
==
mod
)
break
;
}
if
(
&
fde
->
link
!=
&
dwarf_fde_list
)
{
list_del
(
&
fde
->
link
);
kfree
(
fde
);
goto
again_fde
;
}
spin_unlock_irqrestore
(
&
dwarf_fde_lock
,
flags
);
}
/**
* dwarf_unwinder_init - initialise the dwarf unwinder
*
* Build the data structures describing the .dwarf_frame section to
* make it easier to lookup CIE and FDE entries. Because the
* .eh_frame section is packed as tightly as possible it is not
* easy to lookup the FDE for a given PC, so we build a list of FDE
* and CIE entries that make it easier.
*/
static
int
__init
dwarf_unwinder_init
(
void
)
{
int
err
;
INIT_LIST_HEAD
(
&
dwarf_cie_list
);
INIT_LIST_HEAD
(
&
dwarf_fde_list
);
dwarf_frame_cachep
=
kmem_cache_create
(
"dwarf_frames"
,
sizeof
(
struct
dwarf_frame
),
0
,
SLAB_PANIC
|
SLAB_HWCACHE_ALIGN
|
SLAB_NOTRACK
,
NULL
);
dwarf_reg_cachep
=
kmem_cache_create
(
"dwarf_regs"
,
sizeof
(
struct
dwarf_reg
),
0
,
SLAB_PANIC
|
SLAB_HWCACHE_ALIGN
|
SLAB_NOTRACK
,
NULL
);
dwarf_frame_pool
=
mempool_create
(
DWARF_FRAME_MIN_REQ
,
mempool_alloc_slab
,
mempool_free_slab
,
dwarf_frame_cachep
);
dwarf_reg_pool
=
mempool_create
(
DWARF_REG_MIN_REQ
,
mempool_alloc_slab
,
mempool_free_slab
,
dwarf_reg_cachep
);
err
=
dwarf_parse_section
(
__start_eh_frame
,
__stop_eh_frame
,
NULL
);
if
(
err
)
goto
out
;
err
=
unwinder_register
(
&
dwarf_unwinder
);
err
=
unwinder_register
(
&
dwarf_unwinder
);
if
(
err
)
if
(
err
)
goto
out
;
goto
out
;
...
...
arch/sh/kernel/module.c
View file @
8ec006c5
...
@@ -32,6 +32,7 @@
...
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
#include <asm/unaligned.h>
#include <asm/dwarf.h>
void
*
module_alloc
(
unsigned
long
size
)
void
*
module_alloc
(
unsigned
long
size
)
{
{
...
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr,
...
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr,
const
Elf_Shdr
*
sechdrs
,
const
Elf_Shdr
*
sechdrs
,
struct
module
*
me
)
struct
module
*
me
)
{
{
#ifdef CONFIG_DWARF_UNWINDER
unsigned
int
i
,
err
;
unsigned
long
start
,
end
;
char
*
secstrings
=
(
void
*
)
hdr
+
sechdrs
[
hdr
->
e_shstrndx
].
sh_offset
;
start
=
end
=
0
;
for
(
i
=
1
;
i
<
hdr
->
e_shnum
;
i
++
)
{
/* Alloc bit cleared means "ignore it." */
if
((
sechdrs
[
i
].
sh_flags
&
SHF_ALLOC
)
&&
!
strcmp
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".eh_frame"
))
{
start
=
sechdrs
[
i
].
sh_addr
;
end
=
start
+
sechdrs
[
i
].
sh_size
;
break
;
}
}
/* Did we find the .eh_frame section? */
if
(
i
!=
hdr
->
e_shnum
)
{
err
=
dwarf_parse_section
((
char
*
)
start
,
(
char
*
)
end
,
me
);
if
(
err
)
printk
(
KERN_WARNING
"%s: failed to parse DWARF info
\n
"
,
me
->
name
);
}
#endif
/* CONFIG_DWARF_UNWINDER */
return
module_bug_finalize
(
hdr
,
sechdrs
,
me
);
return
module_bug_finalize
(
hdr
,
sechdrs
,
me
);
}
}
void
module_arch_cleanup
(
struct
module
*
mod
)
void
module_arch_cleanup
(
struct
module
*
mod
)
{
{
module_bug_cleanup
(
mod
);
module_bug_cleanup
(
mod
);
#ifdef CONFIG_DWARF_UNWINDER
dwarf_module_unload
(
mod
);
#endif
/* CONFIG_DWARF_UNWINDER */
}
}
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