Dave,
On Thu, Oct 06, 2016 at 04:35:42PM -0400, Dave Anderson wrote:
Hi Akashi,
I was playing around with this, and noted that if a module's debuginfo data is not
loaded into a crash session with the "mod" command, branch instruction targets
that are within the module space are not translated. For example, note the handful
of "bl" instructions with module address targets are empty:
crash> dis dm_create | grep bl
0xfffffdfffc003814 <dm_create+60>: bl 0xfffffe0000226ce0
<kmem_cache_alloc_trace>
0xfffffdfffc003828 <dm_create+80>: bl 0xfffffe0000143754 <try_module_get>
0xfffffdfffc003850 <dm_create+120>: bl 0xfffffe00003c4f08 <idr_preload>
0xfffffdfffc00385c <dm_create+132>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003874 <dm_create+156>: bl 0xfffffe00003c5d90 <idr_alloc>
0xfffffdfffc00388c <dm_create+180>: bl 0xfffffe0000123044
<init_srcu_struct>
0xfffffdfffc0038b0 <dm_create+216>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc0038c0 <dm_create+232>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc0038d4 <dm_create+252>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc003918 <dm_create+320>: bl 0xfffffe00003968c4
<blk_alloc_queue>
0xfffffdfffc003948 <dm_create+368>: bl 0xfffffe00003ab298 <alloc_disk>
0xfffffdfffc003968 <dm_create+400>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc003994 <dm_create+444>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc0039a8 <dm_create+464>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc0039f8 <dm_create+544>: bl 0xfffffe00003d1224 <sprintf>
0xfffffdfffc003a00 <dm_create+552>: bl 0xfffffe00003aab08 <add_disk>
0xfffffdfffc003a1c <dm_create+580>: bl 0xfffffe00003d1224 <sprintf>
0xfffffdfffc003a34 <dm_create+604>: bl 0xfffffe00000e3acc
<__alloc_workqueue_key>
0xfffffdfffc003a48 <dm_create+624>: bl 0xfffffe00003a9a8c <bdget_disk>
0xfffffdfffc003a58 <dm_create+640>: bl 0xfffffe000038ea84 <bio_init>
0xfffffdfffc003a70 <dm_create+664>: bl 0xfffffdfffc00e418
0xfffffdfffc003a78 <dm_create+672>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003a88 <dm_create+688>: bl 0xfffffe00003c4e54 <idr_replace>
0xfffffdfffc003aa4 <dm_create+716>: bl 0xfffffdfffc00d270
0xfffffdfffc003ad8 <dm_create+768>: bl 0xfffffe0000143860 <module_put>
0xfffffdfffc003ae0 <dm_create+776>: bl 0xfffffe0000228464 <kfree>
0xfffffdfffc003b08 <dm_create+816>: bl 0xfffffe00003c4f08 <idr_preload>
0xfffffdfffc003b14 <dm_create+828>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003b2c <dm_create+852>: bl 0xfffffe00003c5d90 <idr_alloc>
0xfffffdfffc003b4c <dm_create+884>: bl 0xfffffdfffc001220
0xfffffdfffc003b54 <dm_create+892>: bl 0xfffffdfffc0012e0
0xfffffdfffc003b60 <dm_create+904>: bl 0xfffffe00001c4828 <printk>
crash>
With this patch:
--- a/arm64.c
+++ b/arm64.c
@@ -2977,6 +2977,16 @@ arm64_dis_filter(ulong vaddr, char *inbuf, unsigned int
output_radix)
sprintf(p1, "%s", buf1);
}
+ if (IS_MODULE_VADDR(vaddr)) {
+ p1 = &inbuf[strlen(inbuf)-1];
+ strcpy(buf1, inbuf);
+ argc = parse_line(buf1, argv);
+ if (STREQ(argv[argc-2], "bl") &&
+ extract_hex(argv[argc-1], &value, NULLCHAR, TRUE))
+ sprintf(p1, " <%s>\n",
+ value_to_symstr(value, buf2, output_radix));
+ }
+
console(" %s", inbuf);
return TRUE;
module addresses are translated without having to load the module's debuginfo:
crash> dis dm_create | grep bl
0xfffffdfffc003814 <dm_create+60>: bl 0xfffffe0000226ce0
<kmem_cache_alloc_trace>
0xfffffdfffc003828 <dm_create+80>: bl 0xfffffe0000143754 <try_module_get>
0xfffffdfffc003850 <dm_create+120>: bl 0xfffffe00003c4f08 <idr_preload>
0xfffffdfffc00385c <dm_create+132>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003874 <dm_create+156>: bl 0xfffffe00003c5d90 <idr_alloc>
0xfffffdfffc00388c <dm_create+180>: bl 0xfffffe0000123044
<init_srcu_struct>
0xfffffdfffc0038b0 <dm_create+216>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc0038c0 <dm_create+232>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc0038d4 <dm_create+252>: bl 0xfffffe000010f9d0 <__mutex_init>
0xfffffdfffc003918 <dm_create+320>: bl 0xfffffe00003968c4
<blk_alloc_queue>
0xfffffdfffc003948 <dm_create+368>: bl 0xfffffe00003ab298 <alloc_disk>
0xfffffdfffc003968 <dm_create+400>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc003994 <dm_create+444>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc0039a8 <dm_create+464>: bl 0xfffffe000010a878
<__init_waitqueue_head>
0xfffffdfffc0039f8 <dm_create+544>: bl 0xfffffe00003d1224 <sprintf>
0xfffffdfffc003a00 <dm_create+552>: bl 0xfffffe00003aab08 <add_disk>
0xfffffdfffc003a1c <dm_create+580>: bl 0xfffffe00003d1224 <sprintf>
0xfffffdfffc003a34 <dm_create+604>: bl 0xfffffe00000e3acc
<__alloc_workqueue_key>
0xfffffdfffc003a48 <dm_create+624>: bl 0xfffffe00003a9a8c <bdget_disk>
0xfffffdfffc003a58 <dm_create+640>: bl 0xfffffe000038ea84 <bio_init>
0xfffffdfffc003a70 <dm_create+664>: bl 0xfffffdfffc00e418 <dm_stats_init>
0xfffffdfffc003a78 <dm_create+672>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003a88 <dm_create+688>: bl 0xfffffe00003c4e54 <idr_replace>
0xfffffdfffc003aa4 <dm_create+716>: bl 0xfffffdfffc00d270 <dm_sysfs_init>
0xfffffdfffc003ad8 <dm_create+768>: bl 0xfffffe0000143860 <module_put>
0xfffffdfffc003ae0 <dm_create+776>: bl 0xfffffe0000228464 <kfree>
0xfffffdfffc003b08 <dm_create+816>: bl 0xfffffe00003c4f08 <idr_preload>
0xfffffdfffc003b14 <dm_create+828>: bl 0xfffffe000078241c <_raw_spin_lock>
0xfffffdfffc003b2c <dm_create+852>: bl 0xfffffe00003c5d90 <idr_alloc>
0xfffffdfffc003b4c <dm_create+884>: bl 0xfffffdfffc001220
<cleanup_mapped_device>
0xfffffdfffc003b54 <dm_create+892>: bl 0xfffffdfffc0012e0 <free_minor>
0xfffffdfffc003b60 <dm_create+904>: bl 0xfffffe00001c4828 <printk>
crash>
Now, this sample patch doesn't deal with branch instructions other than
"bl",
so perhaps it could just check whether the last argument in the instruction
line is a translatable address.
On the other hand, for the PLT veneer issue, it would have to:
(1) make sure it's a "bl", and
and other variants of "bl"
(2) instead of blindly doing a translation of the PLT veneer label
address,
it would first have to check whether it points to a 12-byte chunk of
kernel address construction, and if so, translate the reconstructed
address.
Actually, a veneer always consists of 4 instructions:
mov x16, #imm16
movk x16, #imm16, lsl #16
movk x16, #imm16, lsl #32
br x16
It would be safe to identify any veneers with this type of sequence,
but I'm wondering if there is any other trick of directly checking
if the label address is fit in PLT section of a module.
(On arm64, this section is dynamically allocated on module loading,
and so it's not trivial.)
So I'm thinking something along these lines, say, where "value" may or may
not be
modified by your new function:
if (IS_MODULE_VADDR(vaddr)) {
p1 = &inbuf[strlen(inbuf)-1];
strcpy(buf1, inbuf);
argc = parse_line(buf1, argv);
if (STREQ(argv[argc-2], "bl") &&
extract_hex(argv[argc-1], &value, NULLCHAR, TRUE)) {
+ value = PLT_veneer_to_kvaddr(value);
sprintf(p1, " <%s>\n",
value_to_symstr(value, buf2, output_radix));
}
}
Looks nice.
However, another thing to consider is what "dis" shows if
the "mod" command
has already loaded the debuginfo data. In that case, I'm guessing that gdb
would translate the address of the PLT veneer location?
Give that the output from "bt" command shows "testmod_init" which is
a module_init function of my sample module, I assume that the debug
data have already been loaded in my case.
The sample KASLR
vmcore you gave me doesn't have any modules, so I don't know.
I can give you my sample vmcore.
Please tell me a location where I can push the iamge.
Thanks,
-Takahiro AKASHI
Dave
--
Crash-utility mailing list
Crash-utility(a)redhat.com
https://www.redhat.com/mailman/listinfo/crash-utility