Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
HugeYuan
delve
提交
d4364d04
D
delve
项目概览
HugeYuan
/
delve
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
delve
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
d4364d04
编写于
7月 20, 2017
作者:
A
Alessandro Arzilli
提交者:
Derek Parker
7月 20, 2017
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
proc/core: support floating point registers (#912)
Updates #794
上级
809bdca1
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
296 addition
and
151 deletion
+296
-151
_fixtures/fputest/fputest.go
_fixtures/fputest/fputest.go
+9
-2
pkg/proc/core/core.go
pkg/proc/core/core.go
+65
-8
pkg/proc/core/core_test.go
pkg/proc/core/core_test.go
+91
-8
pkg/proc/core/linux_amd64_core.go
pkg/proc/core/linux_amd64_core.go
+29
-61
pkg/proc/native/ptrace_linux.go
pkg/proc/native/ptrace_linux.go
+5
-24
pkg/proc/native/registers_linux_amd64.go
pkg/proc/native/registers_linux_amd64.go
+2
-48
pkg/proc/registers.go
pkg/proc/registers.go
+95
-0
未找到文件。
_fixtures/fputest/fputest.go
浏览文件 @
d4364d04
package
main
import
"runtime"
import
(
"os"
"runtime"
)
func
fputestsetup
(
f64a
,
f64b
,
f64c
,
f64d
float64
,
f32a
,
f32b
,
f32c
,
f32d
float32
)
...
...
@@ -15,5 +18,9 @@ func main() {
var
f32d
float32
=
1.8
fputestsetup
(
f64a
,
f64b
,
f64c
,
f64d
,
f32a
,
f32b
,
f32c
,
f32d
)
runtime
.
Breakpoint
()
if
len
(
os
.
Args
)
<
2
||
os
.
Args
[
1
]
!=
"panic"
{
runtime
.
Breakpoint
()
}
else
{
panic
(
"booom!"
)
}
}
pkg/proc/core/core.go
浏览文件 @
d4364d04
...
...
@@ -145,14 +145,15 @@ type Process struct {
bi
proc
.
BinaryInfo
core
*
Core
breakpoints
map
[
uint64
]
*
proc
.
Breakpoint
currentThread
*
LinuxPrStatus
currentThread
*
Thread
selectedGoroutine
*
proc
.
G
allGCache
[]
*
proc
.
G
}
type
Thread
struct
{
th
*
LinuxPrStatus
p
*
Process
th
*
LinuxPrStatus
fpregs
[]
proc
.
Register
p
*
Process
}
var
ErrWriteCore
=
errors
.
New
(
"can not to core process"
)
...
...
@@ -169,6 +170,9 @@ func OpenCore(corePath, exePath string) (*Process, error) {
breakpoints
:
make
(
map
[
uint64
]
*
proc
.
Breakpoint
),
bi
:
proc
.
NewBinaryInfo
(
"linux"
,
"amd64"
),
}
for
_
,
thread
:=
range
core
.
Threads
{
thread
.
p
=
p
}
var
wg
sync
.
WaitGroup
p
.
bi
.
LoadBinaryInfo
(
exePath
,
&
wg
)
...
...
@@ -221,8 +225,11 @@ func (t *Thread) ThreadID() int {
}
func
(
t
*
Thread
)
Registers
(
floatingPoint
bool
)
(
proc
.
Registers
,
error
)
{
//TODO(aarzilli): handle floating point registers
return
&
t
.
th
.
Reg
,
nil
r
:=
&
Registers
{
&
t
.
th
.
Reg
,
nil
}
if
floatingPoint
{
r
.
fpregs
=
t
.
fpregs
}
return
r
,
nil
}
func
(
t
*
Thread
)
Arch
()
proc
.
Arch
{
...
...
@@ -274,7 +281,7 @@ func (p *Process) ManualStopRequested() bool {
}
func
(
p
*
Process
)
CurrentThread
()
proc
.
Thread
{
return
&
Thread
{
p
.
currentThread
,
p
}
return
p
.
currentThread
}
func
(
p
*
Process
)
Detach
(
bool
)
error
{
...
...
@@ -340,12 +347,62 @@ func (p *Process) SwitchThread(tid int) error {
func
(
p
*
Process
)
ThreadList
()
[]
proc
.
Thread
{
r
:=
make
([]
proc
.
Thread
,
0
,
len
(
p
.
core
.
Threads
))
for
_
,
v
:=
range
p
.
core
.
Threads
{
r
=
append
(
r
,
&
Thread
{
v
,
p
}
)
r
=
append
(
r
,
v
)
}
return
r
}
func
(
p
*
Process
)
FindThread
(
threadID
int
)
(
proc
.
Thread
,
bool
)
{
t
,
ok
:=
p
.
core
.
Threads
[
threadID
]
return
&
Thread
{
t
,
p
},
ok
return
t
,
ok
}
type
Registers
struct
{
*
LinuxCoreRegisters
fpregs
[]
proc
.
Register
}
func
(
r
*
Registers
)
Slice
()
[]
proc
.
Register
{
var
regs
=
[]
struct
{
k
string
v
uint64
}{
{
"Rip"
,
r
.
Rip
},
{
"Rsp"
,
r
.
Rsp
},
{
"Rax"
,
r
.
Rax
},
{
"Rbx"
,
r
.
Rbx
},
{
"Rcx"
,
r
.
Rcx
},
{
"Rdx"
,
r
.
Rdx
},
{
"Rdi"
,
r
.
Rdi
},
{
"Rsi"
,
r
.
Rsi
},
{
"Rbp"
,
r
.
Rbp
},
{
"R8"
,
r
.
R8
},
{
"R9"
,
r
.
R9
},
{
"R10"
,
r
.
R10
},
{
"R11"
,
r
.
R11
},
{
"R12"
,
r
.
R12
},
{
"R13"
,
r
.
R13
},
{
"R14"
,
r
.
R14
},
{
"R15"
,
r
.
R15
},
{
"Orig_rax"
,
r
.
Orig_rax
},
{
"Cs"
,
r
.
Cs
},
{
"Eflags"
,
r
.
Eflags
},
{
"Ss"
,
r
.
Ss
},
{
"Fs_base"
,
r
.
Fs_base
},
{
"Gs_base"
,
r
.
Gs_base
},
{
"Ds"
,
r
.
Ds
},
{
"Es"
,
r
.
Es
},
{
"Fs"
,
r
.
Fs
},
{
"Gs"
,
r
.
Gs
},
}
out
:=
make
([]
proc
.
Register
,
0
,
len
(
regs
))
for
_
,
reg
:=
range
regs
{
if
reg
.
k
==
"Eflags"
{
out
=
proc
.
AppendEflagReg
(
out
,
reg
.
k
,
reg
.
v
)
}
else
{
out
=
proc
.
AppendQwordReg
(
out
,
reg
.
k
,
reg
.
v
)
}
}
out
=
append
(
out
,
r
.
fpregs
...
)
return
out
}
pkg/proc/core/core_test.go
浏览文件 @
d4364d04
...
...
@@ -125,26 +125,23 @@ func TestSplicedReader(t *testing.T) {
}
}
func
TestCore
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
!=
"linux"
||
runtime
.
GOARCH
!=
"amd64"
{
return
}
func
withCoreFile
(
t
*
testing
.
T
,
name
,
args
string
)
*
Process
{
// This is all very fragile and won't work on hosts with non-default core patterns.
// Might be better to check in the binary and core?
tempDir
,
err
:=
ioutil
.
TempDir
(
""
,
""
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
fix
:=
test
.
BuildFixture
(
"panic"
)
bashCmd
:=
fmt
.
Sprintf
(
"cd %v && ulimit -c unlimited && GOTRACEBACK=crash %v
"
,
tempDir
,
fix
.
Path
)
fix
:=
test
.
BuildFixture
(
name
)
bashCmd
:=
fmt
.
Sprintf
(
"cd %v && ulimit -c unlimited && GOTRACEBACK=crash %v
%s"
,
tempDir
,
fix
.
Path
,
args
)
exec
.
Command
(
"bash"
,
"-c"
,
bashCmd
)
.
Run
()
cores
,
err
:=
filepath
.
Glob
(
path
.
Join
(
tempDir
,
"core*"
))
switch
{
case
err
!=
nil
||
len
(
cores
)
>
1
:
t
.
Fatalf
(
"Got %v, wanted one file named core* in %v"
,
cores
,
tempDir
)
case
len
(
cores
)
==
0
:
t
.
Log
f
(
"core file was not produced, could not run test"
)
return
t
.
Skip
f
(
"core file was not produced, could not run test"
)
return
nil
}
corePath
:=
cores
[
0
]
...
...
@@ -156,6 +153,15 @@ func TestCore(t *testing.T) {
t
.
Errorf
(
"read apport log: %q, %v"
,
apport
,
err
)
t
.
Fatalf
(
"ReadCore() failed: %v"
,
err
)
}
return
p
}
func
TestCore
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
!=
"linux"
||
runtime
.
GOARCH
!=
"amd64"
{
return
}
p
:=
withCoreFile
(
t
,
"panic"
,
""
)
gs
,
err
:=
proc
.
GoroutinesInfo
(
p
)
if
err
!=
nil
||
len
(
gs
)
==
0
{
t
.
Fatalf
(
"GoroutinesInfo() = %v, %v; wanted at least one goroutine"
,
gs
,
err
)
...
...
@@ -207,3 +213,80 @@ func TestCore(t *testing.T) {
t
.
Logf
(
"%s = %s"
,
reg
.
Name
,
reg
.
Value
)
}
}
func
TestCoreFpRegisters
(
t
*
testing
.
T
)
{
if
runtime
.
GOOS
!=
"linux"
||
runtime
.
GOARCH
!=
"amd64"
{
return
}
p
:=
withCoreFile
(
t
,
"fputest/"
,
"panic"
)
gs
,
err
:=
proc
.
GoroutinesInfo
(
p
)
if
err
!=
nil
||
len
(
gs
)
==
0
{
t
.
Fatalf
(
"GoroutinesInfo() = %v, %v; wanted at least one goroutine"
,
gs
,
err
)
}
var
regs
proc
.
Registers
for
_
,
thread
:=
range
p
.
ThreadList
()
{
frames
,
err
:=
proc
.
ThreadStacktrace
(
thread
,
10
)
if
err
!=
nil
{
t
.
Errorf
(
"ThreadStacktrace for %x = %v"
,
thread
.
ThreadID
(),
err
)
continue
}
for
i
:=
range
frames
{
if
frames
[
i
]
.
Current
.
Fn
==
nil
{
continue
}
if
frames
[
i
]
.
Current
.
Fn
.
Name
==
"runtime.crash"
{
regs
,
err
=
thread
.
Registers
(
true
)
if
err
!=
nil
{
t
.
Fatalf
(
"Could not get registers for thread %x, %v"
,
thread
.
ThreadID
(),
err
)
}
break
}
}
if
regs
!=
nil
{
break
}
}
regtests
:=
[]
struct
{
name
,
value
string
}{
{
"ST(0)"
,
"0x3fffe666660000000000"
},
{
"ST(1)"
,
"0x3fffd9999a0000000000"
},
{
"ST(2)"
,
"0x3fffcccccd0000000000"
},
{
"ST(3)"
,
"0x3fffc000000000000000"
},
{
"ST(4)"
,
"0x3fffb333333333333000"
},
{
"ST(5)"
,
"0x3fffa666666666666800"
},
{
"ST(6)"
,
"0x3fff9999999999999800"
},
{
"ST(7)"
,
"0x3fff8cccccccccccd000"
},
// Unlike TestClientServer_FpRegisters in service/test/integration2_test
// we can not test the value of XMM0, it probably has been reused by
// something between the panic and the time we get the core dump.
{
"XMM1"
,
"0x3ff66666666666663ff4cccccccccccd"
},
{
"XMM2"
,
"0x3fe666663fd9999a3fcccccd3fc00000"
},
{
"XMM3"
,
"0x3ff199999999999a3ff3333333333333"
},
{
"XMM4"
,
"0x3ff4cccccccccccd3ff6666666666666"
},
{
"XMM5"
,
"0x3fcccccd3fc000003fe666663fd9999a"
},
{
"XMM6"
,
"0x4004cccccccccccc4003333333333334"
},
{
"XMM7"
,
"0x40026666666666664002666666666666"
},
{
"XMM8"
,
"0x4059999a404ccccd4059999a404ccccd"
},
}
for
_
,
reg
:=
range
regs
.
Slice
()
{
t
.
Logf
(
"%s = %s"
,
reg
.
Name
,
reg
.
Value
)
}
for
_
,
regtest
:=
range
regtests
{
found
:=
false
for
_
,
reg
:=
range
regs
.
Slice
()
{
if
reg
.
Name
==
regtest
.
name
{
found
=
true
if
!
strings
.
HasPrefix
(
reg
.
Value
,
regtest
.
value
)
{
t
.
Fatalf
(
"register %s expected %q got %q"
,
reg
.
Name
,
regtest
.
value
,
reg
.
Value
)
}
}
}
if
!
found
{
t
.
Fatalf
(
"register %s not found: %v"
,
regtest
.
name
,
regs
)
}
}
}
pkg/proc/core/linux_amd64_core.go
浏览文件 @
d4364d04
...
...
@@ -54,7 +54,8 @@ type LinuxCoreTimeval struct {
Usec
int64
}
const
NT_FILE
elf
.
NType
=
0x46494c45
// "FILE".
const
NT_FILE
elf
.
NType
=
0x46494c45
// "FILE".
const
NT_X86_XSTATE
elf
.
NType
=
0x202
// Note type for notes containing X86 XSAVE area.
func
(
r
*
LinuxCoreRegisters
)
PC
()
uint64
{
return
r
.
Rip
...
...
@@ -241,50 +242,6 @@ func (r *LinuxCoreRegisters) SetPC(proc.Thread, uint64) error {
return
errors
.
New
(
"not supported"
)
}
func
(
r
*
LinuxCoreRegisters
)
Slice
()
[]
proc
.
Register
{
var
regs
=
[]
struct
{
k
string
v
uint64
}{
{
"Rip"
,
r
.
Rip
},
{
"Rsp"
,
r
.
Rsp
},
{
"Rax"
,
r
.
Rax
},
{
"Rbx"
,
r
.
Rbx
},
{
"Rcx"
,
r
.
Rcx
},
{
"Rdx"
,
r
.
Rdx
},
{
"Rdi"
,
r
.
Rdi
},
{
"Rsi"
,
r
.
Rsi
},
{
"Rbp"
,
r
.
Rbp
},
{
"R8"
,
r
.
R8
},
{
"R9"
,
r
.
R9
},
{
"R10"
,
r
.
R10
},
{
"R11"
,
r
.
R11
},
{
"R12"
,
r
.
R12
},
{
"R13"
,
r
.
R13
},
{
"R14"
,
r
.
R14
},
{
"R15"
,
r
.
R15
},
{
"Orig_rax"
,
r
.
Orig_rax
},
{
"Cs"
,
r
.
Cs
},
{
"Eflags"
,
r
.
Eflags
},
{
"Ss"
,
r
.
Ss
},
{
"Fs_base"
,
r
.
Fs_base
},
{
"Gs_base"
,
r
.
Gs_base
},
{
"Ds"
,
r
.
Ds
},
{
"Es"
,
r
.
Es
},
{
"Fs"
,
r
.
Fs
},
{
"Gs"
,
r
.
Gs
},
}
out
:=
make
([]
proc
.
Register
,
0
,
len
(
regs
))
for
_
,
reg
:=
range
regs
{
if
reg
.
k
==
"Eflags"
{
out
=
proc
.
AppendEflagReg
(
out
,
reg
.
k
,
reg
.
v
)
}
else
{
out
=
proc
.
AppendQwordReg
(
out
,
reg
.
k
,
reg
.
v
)
}
}
return
out
}
// readCore reads a core file from corePath corresponding to the executable at
// exePath. For details on the Linux ELF core format, see:
// http://www.gabriel.urdhr.fr/2015/05/29/core-file/,
...
...
@@ -292,7 +249,7 @@ func (r *LinuxCoreRegisters) Slice() []proc.Register {
// elf_core_dump in http://lxr.free-electrons.com/source/fs/binfmt_elf.c,
// and, if absolutely desperate, readelf.c from the binutils source.
func
readCore
(
corePath
,
exePath
string
)
(
*
Core
,
error
)
{
core
,
err
:=
elf
.
Open
(
corePath
)
core
File
,
err
:=
elf
.
Open
(
corePath
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -301,37 +258,42 @@ func readCore(corePath, exePath string) (*Core, error) {
return
nil
,
err
}
if
core
.
Type
!=
elf
.
ET_CORE
{
return
nil
,
fmt
.
Errorf
(
"%v is not a core file"
,
core
)
if
core
File
.
Type
!=
elf
.
ET_CORE
{
return
nil
,
fmt
.
Errorf
(
"%v is not a core file"
,
core
File
)
}
notes
,
err
:=
readNotes
(
core
)
notes
,
err
:=
readNotes
(
core
File
)
if
err
!=
nil
{
return
nil
,
err
}
memory
:=
buildMemory
(
core
,
exe
,
notes
)
memory
:=
buildMemory
(
coreFile
,
exe
,
notes
)
core
:=
&
Core
{
MemoryReader
:
memory
,
Threads
:
map
[
int
]
*
Thread
{},
}
threads
:=
map
[
int
]
*
LinuxPrStatus
{}
pid
:=
0
var
lastThread
*
Thread
for
_
,
note
:=
range
notes
{
switch
note
.
Type
{
case
elf
.
NT_PRSTATUS
:
t
:=
note
.
Desc
.
(
*
LinuxPrStatus
)
threads
[
int
(
t
.
Pid
)]
=
t
lastThread
=
&
Thread
{
t
,
nil
,
nil
}
core
.
Threads
[
int
(
t
.
Pid
)]
=
lastThread
case
NT_X86_XSTATE
:
if
lastThread
!=
nil
{
lastThread
.
fpregs
=
note
.
Desc
.
(
*
proc
.
LinuxX86Xstate
)
.
Decode
()
}
case
elf
.
NT_PRPSINFO
:
p
id
=
int
(
note
.
Desc
.
(
*
LinuxPrPsInfo
)
.
Pid
)
core
.
P
id
=
int
(
note
.
Desc
.
(
*
LinuxPrPsInfo
)
.
Pid
)
}
}
return
&
Core
{
MemoryReader
:
memory
,
Threads
:
threads
,
Pid
:
pid
,
},
nil
return
core
,
nil
}
type
Core
struct
{
proc
.
MemoryReader
Threads
map
[
int
]
*
LinuxPrStatus
Threads
map
[
int
]
*
Thread
Pid
int
}
...
...
@@ -341,7 +303,7 @@ type Core struct {
// - NT_PRPSINFO: Information about a process, including PID and signal. Desc is a LinuxPrPsInfo.
// - NT_PRSTATUS: Information about a thread, including base registers, state, etc. Desc is a LinuxPrStatus.
// - NT_FPREGSET (Not implemented): x87 floating point registers.
// - NT_X86_XSTATE
(Not implemented)
: Other registers, including AVX and such.
// - NT_X86_XSTATE: Other registers, including AVX and such.
type
Note
struct
{
Type
elf
.
NType
Name
string
...
...
@@ -428,6 +390,12 @@ func readNote(r io.ReadSeeker) (*Note, error) {
data
.
entries
=
append
(
data
.
entries
,
entry
)
}
note
.
Desc
=
data
case
NT_X86_XSTATE
:
var
fpregs
proc
.
LinuxX86Xstate
if
err
:=
proc
.
LinuxX86XstateRead
(
desc
,
true
,
&
fpregs
);
err
!=
nil
{
return
nil
,
err
}
note
.
Desc
=
&
fpregs
}
if
err
:=
skipPadding
(
r
,
4
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"aligning after desc: %v"
,
err
)
...
...
pkg/proc/native/ptrace_linux.go
浏览文件 @
d4364d04
package
native
import
(
"encoding/binary"
"syscall"
"unsafe"
sys
"golang.org/x/sys/unix"
"github.com/derekparker/delve/pkg/proc"
)
// PtraceAttach executes the sys.PtraceAttach call.
...
...
@@ -56,7 +57,7 @@ func PtracePeekUser(tid int, off uintptr) (uintptr, error) {
// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html
// and amd64_supply_xsave in gdb/amd64-tdep.c.html
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture
func
PtraceGetRegset
(
tid
int
)
(
regset
PtraceXsav
e
,
err
error
)
{
func
PtraceGetRegset
(
tid
int
)
(
regset
proc
.
LinuxX86Xstat
e
,
err
error
)
{
_
,
_
,
err
=
syscall
.
Syscall6
(
syscall
.
SYS_PTRACE
,
sys
.
PTRACE_GETFPREGS
,
uintptr
(
tid
),
uintptr
(
0
),
uintptr
(
unsafe
.
Pointer
(
&
regset
.
PtraceFpRegs
)),
0
,
0
)
if
err
==
syscall
.
Errno
(
0
)
{
err
=
nil
...
...
@@ -71,26 +72,6 @@ func PtraceGetRegset(tid int) (regset PtraceXsave, err error) {
err
=
nil
}
if
_XSAVE_HEADER_START
+
_XSAVE_HEADER_LEN
>=
iov
.
Len
{
return
}
xsaveheader
:=
xstateargs
[
_XSAVE_HEADER_START
:
_XSAVE_HEADER_START
+
_XSAVE_HEADER_LEN
]
xstate_bv
:=
binary
.
LittleEndian
.
Uint64
(
xsaveheader
[
0
:
8
])
xcomp_bv
:=
binary
.
LittleEndian
.
Uint64
(
xsaveheader
[
8
:
16
])
if
xcomp_bv
&
(
1
<<
63
)
!=
0
{
// compact format not supported
return
}
if
xstate_bv
&
(
1
<<
2
)
==
0
{
// AVX state not present
return
}
avxstate
:=
xstateargs
[
_XSAVE_EXTENDED_REGION_START
:
iov
.
Len
]
regset
.
AvxState
=
true
copy
(
regset
.
YmmSpace
[
:
],
avxstate
[
:
len
(
regset
.
YmmSpace
)])
return
err
=
proc
.
LinuxX86XstateRead
(
xstateargs
[
:
iov
.
Len
],
false
,
&
regset
)
return
regset
,
err
}
pkg/proc/native/registers_linux_amd64.go
浏览文件 @
d4364d04
package
native
import
(
"fmt"
"golang.org/x/arch/x86/x86asm"
sys
"golang.org/x/sys/unix"
...
...
@@ -273,27 +271,6 @@ func registers(thread *Thread, floatingPoint bool) (proc.Registers, error) {
return
r
,
nil
}
// tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
type
PtraceFpRegs
struct
{
Cwd
uint16
Swd
uint16
Ftw
uint16
Fop
uint16
Rip
uint64
Rdp
uint64
Mxcsr
uint32
MxcrMask
uint32
StSpace
[
32
]
uint32
XmmSpace
[
256
]
byte
padding
[
24
]
uint32
}
type
PtraceXsave
struct
{
PtraceFpRegs
AvxState
bool
// contains AVX state
YmmSpace
[
256
]
byte
}
const
(
_X86_XSTATE_MAX_SIZE
=
2688
_NT_X86_XSTATE
=
0x202
...
...
@@ -305,31 +282,8 @@ const (
)
func
(
thread
*
Thread
)
fpRegisters
()
(
regs
[]
proc
.
Register
,
err
error
)
{
var
fpregs
PtraceXsav
e
var
fpregs
proc
.
LinuxX86Xstat
e
thread
.
dbp
.
execPtraceFunc
(
func
()
{
fpregs
,
err
=
PtraceGetRegset
(
thread
.
ID
)
})
// x87 registers
regs
=
proc
.
AppendWordReg
(
regs
,
"CW"
,
fpregs
.
Cwd
)
regs
=
proc
.
AppendWordReg
(
regs
,
"SW"
,
fpregs
.
Swd
)
regs
=
proc
.
AppendWordReg
(
regs
,
"TW"
,
fpregs
.
Ftw
)
regs
=
proc
.
AppendWordReg
(
regs
,
"FOP"
,
fpregs
.
Fop
)
regs
=
proc
.
AppendQwordReg
(
regs
,
"FIP"
,
fpregs
.
Rip
)
regs
=
proc
.
AppendQwordReg
(
regs
,
"FDP"
,
fpregs
.
Rdp
)
for
i
:=
0
;
i
<
len
(
fpregs
.
StSpace
);
i
+=
4
{
regs
=
proc
.
AppendX87Reg
(
regs
,
i
/
4
,
uint16
(
fpregs
.
StSpace
[
i
+
2
]),
uint64
(
fpregs
.
StSpace
[
i
+
1
])
<<
32
|
uint64
(
fpregs
.
StSpace
[
i
]))
}
// SSE registers
regs
=
proc
.
AppendMxcsrReg
(
regs
,
"MXCSR"
,
uint64
(
fpregs
.
Mxcsr
))
regs
=
proc
.
AppendDwordReg
(
regs
,
"MXCSR_MASK"
,
fpregs
.
MxcrMask
)
for
i
:=
0
;
i
<
len
(
fpregs
.
XmmSpace
);
i
+=
16
{
regs
=
proc
.
AppendSSEReg
(
regs
,
fmt
.
Sprintf
(
"XMM%d"
,
i
/
16
),
fpregs
.
XmmSpace
[
i
:
i
+
16
])
if
fpregs
.
AvxState
{
regs
=
proc
.
AppendSSEReg
(
regs
,
fmt
.
Sprintf
(
"YMM%d"
,
i
/
16
),
fpregs
.
YmmSpace
[
i
:
i
+
16
])
}
}
regs
=
fpregs
.
Decode
()
return
}
pkg/proc/registers.go
浏览文件 @
d4364d04
...
...
@@ -232,3 +232,98 @@ func (descr flagRegisterDescr) Describe(reg uint64, bitsize int) string {
}
return
fmt
.
Sprintf
(
"%#0*x
\t
[%s]"
,
bitsize
/
4
,
reg
,
strings
.
Join
(
r
,
" "
))
}
// tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
type
PtraceFpRegs
struct
{
Cwd
uint16
Swd
uint16
Ftw
uint16
Fop
uint16
Rip
uint64
Rdp
uint64
Mxcsr
uint32
MxcrMask
uint32
StSpace
[
32
]
uint32
XmmSpace
[
256
]
byte
Padding
[
24
]
uint32
}
// LinuxX86Xstate represents amd64 XSAVE area. See Section 13.1 (and
// following) of Intel® 64 and IA-32 Architectures Software Developer’s
// Manual, Volume 1: Basic Architecture.
type
LinuxX86Xstate
struct
{
PtraceFpRegs
AvxState
bool
// contains AVX state
YmmSpace
[
256
]
byte
}
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
func
(
xsave
*
LinuxX86Xstate
)
Decode
()
(
regs
[]
Register
)
{
// x87 registers
regs
=
AppendWordReg
(
regs
,
"CW"
,
xsave
.
Cwd
)
regs
=
AppendWordReg
(
regs
,
"SW"
,
xsave
.
Swd
)
regs
=
AppendWordReg
(
regs
,
"TW"
,
xsave
.
Ftw
)
regs
=
AppendWordReg
(
regs
,
"FOP"
,
xsave
.
Fop
)
regs
=
AppendQwordReg
(
regs
,
"FIP"
,
xsave
.
Rip
)
regs
=
AppendQwordReg
(
regs
,
"FDP"
,
xsave
.
Rdp
)
for
i
:=
0
;
i
<
len
(
xsave
.
StSpace
);
i
+=
4
{
regs
=
AppendX87Reg
(
regs
,
i
/
4
,
uint16
(
xsave
.
StSpace
[
i
+
2
]),
uint64
(
xsave
.
StSpace
[
i
+
1
])
<<
32
|
uint64
(
xsave
.
StSpace
[
i
]))
}
// SSE registers
regs
=
AppendMxcsrReg
(
regs
,
"MXCSR"
,
uint64
(
xsave
.
Mxcsr
))
regs
=
AppendDwordReg
(
regs
,
"MXCSR_MASK"
,
xsave
.
MxcrMask
)
for
i
:=
0
;
i
<
len
(
xsave
.
XmmSpace
);
i
+=
16
{
regs
=
AppendSSEReg
(
regs
,
fmt
.
Sprintf
(
"XMM%d"
,
i
/
16
),
xsave
.
XmmSpace
[
i
:
i
+
16
])
if
xsave
.
AvxState
{
regs
=
AppendSSEReg
(
regs
,
fmt
.
Sprintf
(
"YMM%d"
,
i
/
16
),
xsave
.
YmmSpace
[
i
:
i
+
16
])
}
}
return
}
const
(
_XSAVE_HEADER_START
=
512
_XSAVE_HEADER_LEN
=
64
_XSAVE_EXTENDED_REGION_START
=
576
_XSAVE_SSE_REGION_LEN
=
416
)
// LinuxX86XstateRead reads a byte array containing an XSAVE area into regset.
// If readLegacy is true regset.PtraceFpRegs will be filled with the
// contents of the legacy region of the XSAVE area.
// See Section 13.1 (and following) of Intel® 64 and IA-32 Architectures
// Software Developer’s Manual, Volume 1: Basic Architecture.
func
LinuxX86XstateRead
(
xstateargs
[]
byte
,
readLegacy
bool
,
regset
*
LinuxX86Xstate
)
error
{
if
_XSAVE_HEADER_START
+
_XSAVE_HEADER_LEN
>=
len
(
xstateargs
)
{
return
nil
}
if
readLegacy
{
rdr
:=
bytes
.
NewReader
(
xstateargs
[
:
_XSAVE_HEADER_START
])
if
err
:=
binary
.
Read
(
rdr
,
binary
.
LittleEndian
,
&
regset
.
PtraceFpRegs
);
err
!=
nil
{
return
err
}
}
xsaveheader
:=
xstateargs
[
_XSAVE_HEADER_START
:
_XSAVE_HEADER_START
+
_XSAVE_HEADER_LEN
]
xstate_bv
:=
binary
.
LittleEndian
.
Uint64
(
xsaveheader
[
0
:
8
])
xcomp_bv
:=
binary
.
LittleEndian
.
Uint64
(
xsaveheader
[
8
:
16
])
if
xcomp_bv
&
(
1
<<
63
)
!=
0
{
// compact format not supported
return
nil
}
if
xstate_bv
&
(
1
<<
2
)
==
0
{
// AVX state not present
return
nil
}
avxstate
:=
xstateargs
[
_XSAVE_EXTENDED_REGION_START
:
]
regset
.
AvxState
=
true
copy
(
regset
.
YmmSpace
[
:
],
avxstate
[
:
len
(
regset
.
YmmSpace
)])
return
nil
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录