Skip to content

Commit 82e080d

Browse files
committed
GDBserver: Fix "Cond. jump or move depends on uninit value" in x87 code
Running gdbserver under Valgrind I get: ==26925== Conditional jump or move depends on uninitialised value(s) ==26925== at 0x473E7F: i387_cache_to_xsave(regcache*, void*) (i387-fp.c:579) ==26925== by 0x46E3ED: x86_fill_xstateregset(regcache*, void*) (linux-x86-low.c:418) ==26925== by 0x45E747: regsets_store_inferior_registers(regsets_info*, regcache*) (linux-low.c:5456) ==26925== by 0x45EEF8: linux_store_registers(regcache*, int) (linux-low.c:5731) ==26925== by 0x426441: regcache_invalidate_thread(thread_info*) (regcache.c:89) ==26925== by 0x45CCAF: linux_resume_one_lwp_throw(lwp_info*, int, int, siginfo_t*) (linux-low.c:4447) ==26925== by 0x45CE2A: linux_resume_one_lwp(lwp_info*, int, int, siginfo_t*) (linux-low.c:4519) ==26925== by 0x45E17C: proceed_one_lwp(thread_info*, lwp_info*) (linux-low.c:5216) ==26925== by 0x45DC81: linux_resume_one_thread(thread_info*, bool) (linux-low.c:5031) ==26925== by 0x45DD34: linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}::operator()(thread_info*) const (linux-low.c:5095) ==26925== by 0x462907: void for_each_thread<linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}>(linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}) (gdbthread.h:150) ==26925== by 0x45DE62: linux_resume(thread_resume*, unsigned long) (linux-low.c:5093) ==26925== ==26925== Conditional jump or move depends on uninitialised value(s) ==26925== at 0x473EBD: i387_cache_to_xsave(regcache*, void*) (i387-fp.c:586) ==26925== by 0x46E3ED: x86_fill_xstateregset(regcache*, void*) (linux-x86-low.c:418) ==26925== by 0x45E747: regsets_store_inferior_registers(regsets_info*, regcache*) (linux-low.c:5456) ==26925== by 0x45EEF8: linux_store_registers(regcache*, int) (linux-low.c:5731) ==26925== by 0x426441: regcache_invalidate_thread(thread_info*) (regcache.c:89) ==26925== by 0x45CCAF: linux_resume_one_lwp_throw(lwp_info*, int, int, siginfo_t*) (linux-low.c:4447) ==26925== by 0x45CE2A: linux_resume_one_lwp(lwp_info*, int, int, siginfo_t*) (linux-low.c:4519) ==26925== by 0x45E17C: proceed_one_lwp(thread_info*, lwp_info*) (linux-low.c:5216) ==26925== by 0x45DC81: linux_resume_one_thread(thread_info*, bool) (linux-low.c:5031) ==26925== by 0x45DD34: linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}::operator()(thread_info*) const (linux-low.c:5095) ==26925== by 0x462907: void for_each_thread<linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}>(linux_resume(thread_resume*, unsigned long)::{lambda(thread_info*)#2}) (gdbthread.h:150) ==26925== by 0x45DE62: linux_resume(thread_resume*, unsigned long) (linux-low.c:5093) The problem is a type/width mismatch in code like this, in gdbserver/i387-fp.c: /* Some registers are 16-bit. */ collect_register_by_name (regcache, "fctrl", &val); fp->fctrl = val; In the above code: #1 - 'val' is a 64-bit unsigned long. #2 - "fctrl" is 32-bit in the register cache, thus half of 'val' is left uninitialized by collect_register_by_name, which works with an untyped raw buffer output (i.e., void*). #3 - fp->fctrl is an unsigned short (16-bit). For some such registers we're masking off the uninitialized bits with 0xffff, but not in all cases. We end up in such a fragile situation because collect_registers_by_name works with an untyped output buffer pointer, making it easy to pass a pointer to a variable of the wrong size. Fix this by using regcache_raw_get_unsigned instead (actually a new regcache_raw_get_unsigned_by_name wrapper), which always returns a zero-extended ULONGEST register value. It ends up simplifying the i387-tdep.c code a bit, even. gdb/gdbserver/ChangeLog: 2018-07-11 Pedro Alves <[email protected]> * i387-fp.c (i387_cache_to_fsave, cache_to_fxsave) (i387_cache_to_xsave): Use regcache_raw_get_unsigned_by_name instead of collect_register_by_name. * regcache.c (regcache_raw_get_unsigned_by_name): New. * regcache.h (regcache_raw_get_unsigned_by_name): New.
1 parent ad3c631 commit 82e080d

File tree

4 files changed

+50
-46
lines changed

4 files changed

+50
-46
lines changed

gdb/gdbserver/ChangeLog

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2018-07-11 Pedro Alves <[email protected]>
2+
3+
* i387-fp.c (i387_cache_to_fsave, cache_to_fxsave)
4+
(i387_cache_to_xsave): Use regcache_raw_get_unsigned_by_name
5+
instead of collect_register_by_name.
6+
* regcache.c (regcache_raw_get_unsigned_by_name): New.
7+
* regcache.h (regcache_raw_get_unsigned_by_name): New.
8+
19
2018-07-04 Vyacheslav Barinov <[email protected]>
210
Pedro Alves <[email protected]>
311

gdb/gdbserver/i387-fp.c

+25-46
Original file line numberDiff line numberDiff line change
@@ -149,38 +149,25 @@ i387_cache_to_fsave (struct regcache *regcache, void *buf)
149149
struct i387_fsave *fp = (struct i387_fsave *) buf;
150150
int i;
151151
int st0_regnum = find_regno (regcache->tdesc, "st0");
152-
unsigned long val, val2;
152+
unsigned long val2;
153153

154154
for (i = 0; i < 8; i++)
155155
collect_register (regcache, i + st0_regnum,
156156
((char *) &fp->st_space[0]) + i * 10);
157157

158-
collect_register_by_name (regcache, "fioff", &fp->fioff);
159-
collect_register_by_name (regcache, "fooff", &fp->fooff);
160-
158+
fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff");
159+
fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff");
160+
161161
/* This one's 11 bits... */
162-
collect_register_by_name (regcache, "fop", &val2);
162+
val2 = regcache_raw_get_unsigned_by_name (regcache, "fop");
163163
fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
164164

165165
/* Some registers are 16-bit. */
166-
collect_register_by_name (regcache, "fctrl", &val);
167-
fp->fctrl = val;
168-
169-
collect_register_by_name (regcache, "fstat", &val);
170-
val &= 0xFFFF;
171-
fp->fstat = val;
172-
173-
collect_register_by_name (regcache, "ftag", &val);
174-
val &= 0xFFFF;
175-
fp->ftag = val;
176-
177-
collect_register_by_name (regcache, "fiseg", &val);
178-
val &= 0xFFFF;
179-
fp->fiseg = val;
180-
181-
collect_register_by_name (regcache, "foseg", &val);
182-
val &= 0xFFFF;
183-
fp->foseg = val;
166+
fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl");
167+
fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat");
168+
fp->ftag = regcache_raw_get_unsigned_by_name (regcache, "ftag");
169+
fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg");
170+
fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg");
184171
}
185172

186173
void
@@ -237,24 +224,20 @@ i387_cache_to_fxsave (struct regcache *regcache, void *buf)
237224
collect_register (regcache, i + xmm0_regnum,
238225
((char *) &fp->xmm_space[0]) + i * 16);
239226

240-
collect_register_by_name (regcache, "fioff", &fp->fioff);
241-
collect_register_by_name (regcache, "fooff", &fp->fooff);
242-
collect_register_by_name (regcache, "mxcsr", &fp->mxcsr);
227+
fp->fioff = regcache_raw_get_unsigned_by_name (regcache, "fioff");
228+
fp->fooff = regcache_raw_get_unsigned_by_name (regcache, "fooff");
229+
fp->mxcsr = regcache_raw_get_unsigned_by_name (regcache, "mxcsr");
243230

244231
/* This one's 11 bits... */
245-
collect_register_by_name (regcache, "fop", &val2);
232+
val2 = regcache_raw_get_unsigned_by_name (regcache, "fop");
246233
fp->fop = (val2 & 0x7FF) | (fp->fop & 0xF800);
247234

248235
/* Some registers are 16-bit. */
249-
collect_register_by_name (regcache, "fctrl", &val);
250-
fp->fctrl = val;
251-
252-
collect_register_by_name (regcache, "fstat", &val);
253-
fp->fstat = val;
236+
fp->fctrl = regcache_raw_get_unsigned_by_name (regcache, "fctrl");
237+
fp->fstat = regcache_raw_get_unsigned_by_name (regcache, "fstat");
254238

255239
/* Convert to the simplifed tag form stored in fxsave data. */
256-
collect_register_by_name (regcache, "ftag", &val);
257-
val &= 0xFFFF;
240+
val = regcache_raw_get_unsigned_by_name (regcache, "ftag");
258241
val2 = 0;
259242
for (i = 7; i >= 0; i--)
260243
{
@@ -265,11 +248,8 @@ i387_cache_to_fxsave (struct regcache *regcache, void *buf)
265248
}
266249
fp->ftag = val2;
267250

268-
collect_register_by_name (regcache, "fiseg", &val);
269-
fp->fiseg = val;
270-
271-
collect_register_by_name (regcache, "foseg", &val);
272-
fp->foseg = val;
251+
fp->fiseg = regcache_raw_get_unsigned_by_name (regcache, "fiseg");
252+
fp->foseg = regcache_raw_get_unsigned_by_name (regcache, "foseg");
273253
}
274254

275255
void
@@ -566,7 +546,7 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
566546
}
567547

568548
/* This one's 11 bits... */
569-
collect_register_by_name (regcache, "fop", &val2);
549+
val2 = regcache_raw_get_unsigned_by_name (regcache, "fop");
570550
val2 = (val2 & 0x7FF) | (fp->fop & 0xF800);
571551
if (fp->fop != val2)
572552
{
@@ -575,23 +555,22 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
575555
}
576556

577557
/* Some registers are 16-bit. */
578-
collect_register_by_name (regcache, "fctrl", &val);
558+
val = regcache_raw_get_unsigned_by_name (regcache, "fctrl");
579559
if (fp->fctrl != val)
580560
{
581561
xstate_bv |= X86_XSTATE_X87;
582562
fp->fctrl = val;
583563
}
584564

585-
collect_register_by_name (regcache, "fstat", &val);
565+
val = regcache_raw_get_unsigned_by_name (regcache, "fstat");
586566
if (fp->fstat != val)
587567
{
588568
xstate_bv |= X86_XSTATE_X87;
589569
fp->fstat = val;
590570
}
591571

592572
/* Convert to the simplifed tag form stored in fxsave data. */
593-
collect_register_by_name (regcache, "ftag", &val);
594-
val &= 0xFFFF;
573+
val = regcache_raw_get_unsigned_by_name (regcache, "ftag");
595574
val2 = 0;
596575
for (i = 7; i >= 0; i--)
597576
{
@@ -606,14 +585,14 @@ i387_cache_to_xsave (struct regcache *regcache, void *buf)
606585
fp->ftag = val2;
607586
}
608587

609-
collect_register_by_name (regcache, "fiseg", &val);
588+
val = regcache_raw_get_unsigned_by_name (regcache, "fiseg");
610589
if (fp->fiseg != val)
611590
{
612591
xstate_bv |= X86_XSTATE_X87;
613592
fp->fiseg = val;
614593
}
615594

616-
collect_register_by_name (regcache, "foseg", &val);
595+
val = regcache_raw_get_unsigned_by_name (regcache, "foseg");
617596
if (fp->foseg != val)
618597
{
619598
xstate_bv |= X86_XSTATE_X87;

gdb/gdbserver/regcache.c

+10
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,16 @@ regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
448448

449449
#ifndef IN_PROCESS_AGENT
450450

451+
/* See regcache.h. */
452+
453+
ULONGEST
454+
regcache_raw_get_unsigned_by_name (struct regcache *regcache,
455+
const char *name)
456+
{
457+
return regcache_raw_get_unsigned (regcache,
458+
find_regno (regcache->tdesc, name));
459+
}
460+
451461
void
452462
collect_register_as_string (struct regcache *regcache, int n, char *buf)
453463
{

gdb/gdbserver/regcache.h

+7
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,11 @@ void collect_register_as_string (struct regcache *regcache, int n, char *buf);
131131
void collect_register_by_name (struct regcache *regcache,
132132
const char *name, void *buf);
133133

134+
/* Read a raw register as an unsigned integer. Convenience wrapper
135+
around regcache_raw_get_unsigned that takes a register name instead
136+
of a register number. */
137+
138+
ULONGEST regcache_raw_get_unsigned_by_name (struct regcache *regcache,
139+
const char *name);
140+
134141
#endif /* REGCACHE_H */

0 commit comments

Comments
 (0)