Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
5ab78ff6
Commit
5ab78ff6
authored
Oct 12, 2009
by
Paul Mundt
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'sh/dwarf-unwinder' of
git://github.com/mfleming/linux-2.6
into sh/dwarf-unwinder
parents
74db2479
c2d474d6
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
180 additions
and
47 deletions
+180
-47
arch/sh/include/asm/dwarf.h
arch/sh/include/asm/dwarf.h
+16
-0
arch/sh/kernel/dwarf.c
arch/sh/kernel/dwarf.c
+132
-47
arch/sh/kernel/module.c
arch/sh/kernel/module.c
+32
-0
No files found.
arch/sh/include/asm/dwarf.h
View file @
5ab78ff6
...
...
@@ -241,6 +241,12 @@ struct dwarf_cie {
unsigned
long
flags
;
#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 {
unsigned
char
*
instructions
;
unsigned
char
*
end
;
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)
extern
struct
dwarf_frame
*
dwarf_unwind_stack
(
unsigned
long
,
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__ */
#define CFI_STARTPROC .cfi_startproc
...
...
arch/sh/kernel/dwarf.c
View file @
5ab78ff6
...
...
@@ -530,7 +530,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
* @prev: struct dwarf_frame of the previous stackframe on the callstack
*
...
...
@@ -548,9 +559,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
unsigned
long
addr
;
/*
* If
this is the first invocation of this recursive function w
e
*
need get the contents of a physical register to get the CFA
*
in order to
begin the virtual unwinding of the stack.
* If
we're starting at the top of the stack we need get th
e
*
contents of a physical register to get the CFA in order to
* begin the virtual unwinding of the stack.
*
* NOTE: the return address is guaranteed to be setup by the
* time this function makes its first function call.
...
...
@@ -572,9 +583,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
fde
=
dwarf_lookup_fde
(
pc
);
if
(
!
fde
)
{
/*
* This is our normal exit path - the one that stops the
* recursion. There's two reasons why we might exit
* here,
* This is our normal exit path. There are two reasons
* why we might exit here,
*
* a) pc has no asscociated DWARF frame info and so
* we don't know how to unwind this frame. This is
...
...
@@ -616,10 +626,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
}
else
{
/*
* Again,
this is the first invocation of this
*
recurisve function. We need to physically
*
read the contents of a register in order to
*
get
the Canonical Frame Address for this
* Again,
we're starting from the top of the
*
stack. We need to physically read
*
the contents of a register in order to get
* the Canonical Frame Address for this
* function.
*/
frame
->
cfa
=
dwarf_read_arch_reg
(
frame
->
cfa_register
);
...
...
@@ -649,13 +659,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
return
frame
;
bail:
dwarf_frame_free_regs
(
frame
);
mempool_free
(
frame
,
dwarf_frame_pool
);
dwarf_free_frame
(
frame
);
return
NULL
;
}
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
;
unsigned
long
flags
;
...
...
@@ -751,6 +760,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
cie
->
initial_instructions
=
p
;
cie
->
instructions_end
=
end
;
cie
->
mod
=
mod
;
/* Add to list */
spin_lock_irqsave
(
&
dwarf_cie_lock
,
flags
);
list_add_tail
(
&
cie
->
link
,
&
dwarf_cie_list
);
...
...
@@ -761,7 +772,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len,
static
int
dwarf_parse_fde
(
void
*
entry
,
u32
entry_type
,
void
*
start
,
unsigned
long
len
,
unsigned
char
*
end
)
unsigned
char
*
end
,
struct
module
*
mod
)
{
struct
dwarf_fde
*
fde
;
struct
dwarf_cie
*
cie
;
...
...
@@ -810,6 +821,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type,
fde
->
instructions
=
p
;
fde
->
end
=
end
;
fde
->
mod
=
mod
;
/* Add to list. */
spin_lock_irqsave
(
&
dwarf_fde_lock
,
flags
);
list_add_tail
(
&
fde
->
link
,
&
dwarf_fde_list
);
...
...
@@ -833,10 +846,8 @@ static void dwarf_unwinder_dump(struct task_struct *task,
while
(
1
)
{
frame
=
dwarf_unwind_stack
(
return_addr
,
_frame
);
if
(
_frame
)
{
dwarf_frame_free_regs
(
_frame
);
mempool_free
(
_frame
,
dwarf_frame_pool
);
}
if
(
_frame
)
dwarf_free_frame
(
_frame
);
_frame
=
frame
;
...
...
@@ -846,6 +857,9 @@ static void dwarf_unwinder_dump(struct task_struct *task,
return_addr
=
frame
->
return_addr
;
ops
->
address
(
data
,
return_addr
,
1
);
}
if
(
frame
)
dwarf_free_frame
(
frame
);
}
static
struct
unwinder
dwarf_unwinder
=
{
...
...
@@ -875,15 +889,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
* 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.
* Parse the information in a .eh_frame section.
*/
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
;
void
*
p
,
*
entry
;
...
...
@@ -891,29 +905,12 @@ static int __init dwarf_unwinder_init(void)
unsigned
long
len
;
unsigned
int
c_entries
,
f_entries
;
unsigned
char
*
end
;
INIT_LIST_HEAD
(
&
dwarf_cie_list
);
INIT_LIST_HEAD
(
&
dwarf_fde_list
);
c_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
,
NULL
);
dwarf_reg_cachep
=
kmem_cache_create
(
"dwarf_regs"
,
sizeof
(
struct
dwarf_reg
),
0
,
SLAB_PANIC
,
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
);
while
((
char
*
)
entry
<
__stop_eh_frame
)
{
while
((
char
*
)
entry
<
eh_frame_end
)
{
p
=
entry
;
count
=
dwarf_entry_len
(
p
,
&
len
);
...
...
@@ -925,6 +922,7 @@ static int __init dwarf_unwinder_init(void)
* entry and move to the next one because 'len'
* tells us where our next entry is.
*/
err
=
-
EINVAL
;
goto
out
;
}
else
p
+=
count
;
...
...
@@ -936,13 +934,14 @@ static int __init dwarf_unwinder_init(void)
p
+=
4
;
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
)
goto
out
;
else
c_entries
++
;
}
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
)
goto
out
;
else
...
...
@@ -955,6 +954,92 @@ static int __init dwarf_unwinder_init(void)
printk
(
KERN_INFO
"DWARF unwinder initialised: read %u CIEs, %u FDEs
\n
"
,
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
,
NULL
);
dwarf_reg_cachep
=
kmem_cache_create
(
"dwarf_regs"
,
sizeof
(
struct
dwarf_reg
),
0
,
SLAB_PANIC
,
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
);
if
(
err
)
goto
out
;
...
...
arch/sh/kernel/module.c
View file @
5ab78ff6
...
...
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
#include <asm/dwarf.h>
void
*
module_alloc
(
unsigned
long
size
)
{
...
...
@@ -145,10 +146,41 @@ int module_finalize(const Elf_Ehdr *hdr,
const
Elf_Shdr
*
sechdrs
,
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
);
}
void
module_arch_cleanup
(
struct
module
*
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