* ARM and virtual/raw registers
@ 2002-05-09 7:31 Richard Earnshaw
2002-05-09 9:45 ` Andrew Cagney
2002-05-09 10:08 ` Andrew Cagney
0 siblings, 2 replies; 30+ messages in thread
From: Richard Earnshaw @ 2002-05-09 7:31 UTC (permalink / raw)
To: gdb; +Cc: Richard.Earnshaw, Andrew Cagney
Ok, so it's clear that the current ARM code for handling virtual and raw
registers is wrong...
So the question is, what does it need to be?
The answer is that I'm not quite sure, since there are a number of factors
involved here.
1) FPA registers are multi-precision -- that is, they are modal, holding
information about the type of result in the register at any particular
time. The extra information is used to enable correct support of type
conversions with signalling NaNs.
2) The format of that information can depend on the hardware present, or,
if absent, on the emulator being used (different emulators handle this in
different ways).
3) Some of the emulators use three words to hold the raw information, some
use four. RDP returns uses four words.
4) When a floating point value is stored in memory the format of that
memory may depend on the instruction used to store it. For example, the
sfmfd instruction used in a prologue sequence will store three words (as
would stfe), but there may be information in the unused bits that
indicates the type of the value in the register. The format of this
memory may, or may not, be the same as the three-word register information
mentioned in 3) above.
5) All of the above is poorly documented ;-(
6) Selecting the correct conversion routine may involve some inspired
guess-work :-)
In addition to the above, we also have the case of the CPSR register. On
old ARM chips (or on non-thumb chips up to armv4), this register is, or
can be mimicked as being, part of the PC. This suggests to me that the
current decoding shenanigans that are currently hidden in some of the
back-end code should probably be moved into the virtual-raw conversion
layer. That is, register_convirt_{to,from}_virtual(CPSR) (or whatever
it's really called) should be responsible for the updating of raw-PC or
raw-CPSR as appropriate.
Comments?
R.
^ permalink raw reply [flat|nested] 30+ messages in thread* Re: ARM and virtual/raw registers 2002-05-09 7:31 ARM and virtual/raw registers Richard Earnshaw @ 2002-05-09 9:45 ` Andrew Cagney 2002-05-09 10:01 ` Richard Earnshaw 2002-05-09 10:08 ` Andrew Cagney 1 sibling, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-09 9:45 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > In addition to the above, we also have the case of the CPSR register. On > old ARM chips (or on non-thumb chips up to armv4), this register is, or > can be mimicked as being, part of the PC. This suggests to me that the > current decoding shenanigans that are currently hidden in some of the > back-end code should probably be moved into the virtual-raw conversion > layer. That is, register_convirt_{to,from}_virtual(CPSR) (or whatever > it's really called) should be responsible for the updating of raw-PC or > raw-CPSR as appropriate. Hmm, what exactly do you mean by mimicked? Can the entire register contents be constructed from information found in the other raw/hardware registers? If that is the case then making it a pseudo-register and using register_{read,write} should do the trick. (notice - convert-to-virtual free zone). enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 9:45 ` Andrew Cagney @ 2002-05-09 10:01 ` Richard Earnshaw 2002-05-09 11:52 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-09 10:01 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > > > In addition to the above, we also have the case of the CPSR register. On > > old ARM chips (or on non-thumb chips up to armv4), this register is, or > > can be mimicked as being, part of the PC. This suggests to me that the > > current decoding shenanigans that are currently hidden in some of the > > back-end code should probably be moved into the virtual-raw conversion > > layer. That is, register_convirt_{to,from}_virtual(CPSR) (or whatever > > it's really called) should be responsible for the updating of raw-PC or > > raw-CPSR as appropriate. > > Hmm, what exactly do you mean by mimicked? Can the entire register > contents be constructed from information found in the other raw/hardware > registers? If that is the case then making it a pseudo-register and > using register_{read,write} should do the trick. > > (notice - convert-to-virtual free zone). In the case where the real register does not exist (arm2, arm3), or when the register doesn't exist in the current operating mode (arm6, arm7 -- though not arm7tdmi, arm8 and sa1 when running in apcs-26 mode), then the CPSR is part of the PC and we mimic its existence within GDB; so yes, in that case it is a virtual register. But when we are running in pure apcs-32 mode, then CPSR is a separate register (with additional bits defined). The more I think about it, the more I think that the raw<->virtual translation is in the wrong part of GDB. Shouldn't this be part of the Target interface? Then conversion to/from virtual format would happen as data is passed to/from the inferior, and the rest of GDB would only use the virtual format. As I understand it, this would clean up the MIPS issue entirely -- when talking to a target that supplies additional bits for a register, the target layer would strip these off/add them back, and the rest of gdb wouldn't have to worry about it. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 10:01 ` Richard Earnshaw @ 2002-05-09 11:52 ` Andrew Cagney 2002-05-10 3:45 ` Richard Earnshaw 2002-05-10 9:29 ` Richard Earnshaw 0 siblings, 2 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-09 11:52 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb >> Hmm, what exactly do you mean by mimicked? Can the entire register >> contents be constructed from information found in the other raw/hardware >> registers? If that is the case then making it a pseudo-register and >> using register_{read,write} should do the trick. >> >> (notice - convert-to-virtual free zone). (and how I'm quietly eliminating it :-) > In the case where the real register does not exist (arm2, arm3), or when > the register doesn't exist in the current operating mode (arm6, arm7 -- > though not arm7tdmi, arm8 and sa1 when running in apcs-26 mode), then the > CPSR is part of the PC and we mimic its existence within GDB; so yes, in > that case it is a virtual register. > But when we are running in pure apcs-32 mode, then CPSR is a separate > register (with additional bits defined). In APCS-32 mode, is there any overlap of information between it and the PC? > The more I think about it, the more I think that the raw<->virtual > translation is in the wrong part of GDB. Shouldn't this be part of the > Target interface? Then conversion to/from virtual format would happen as > data is passed to/from the inferior, and the rest of GDB would only use > the virtual format. Yes, I agree that raw<->virtual is wrong; but no, it shouldn't be pushed down below the target. > As I understand it, this would clean up the MIPS issue entirely -- when > talking to a target that supplies additional bits for a register, the > target layer would strip these off/add them back, and the rest of gdb > wouldn't have to worry about it. Have a look at the SH5 patch. I think this gets it right. The first cut at all this had the target using supply_register() to fill in missing values in from below the cache - turns out this makes coherency hard. The current revision uses register_{read,write} above the cache to do this, thus eliminating redundant information in the cache. For the SH5, the raw register cache contains SHmedia (32/64 bit?) registers (as that is what the raw hardware has). Pseudo-registers, and register_{read,write} are then used to map SHcompact (16/32?) registers onto the corresponding raw registers. For instance, the SHcompact PC (I'm going from memory) is constructed from two SHmedia registers. This is implemented by having register_{read,write} scatter/gather the relvant value. Other SHcompact registers are sub registers of SHmedia and they are implemented using similar techniques. When it comes to a frame, a custom get_saved_register() handles the related problem of SHmedia X SHcompact frame vs request for SHmedia X SHcompact register from the next outer frame (I suspect with a few lingering edge cases :-). Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 11:52 ` Andrew Cagney @ 2002-05-10 3:45 ` Richard Earnshaw 2002-05-10 7:48 ` Andrew Cagney 2002-05-10 9:29 ` Richard Earnshaw 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-10 3:45 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb (notice - convert-to-virtual free zone). > > (and how I'm quietly eliminating it :-) > :-) > > In the case where the real register does not exist (arm2, arm3), or when > > the register doesn't exist in the current operating mode (arm6, arm7 -- > > though not arm7tdmi, arm8 and sa1 when running in apcs-26 mode), then the > > CPSR is part of the PC and we mimic its existence within GDB; so yes, in > > that case it is a virtual register. > > > But when we are running in pure apcs-32 mode, then CPSR is a separate > > register (with additional bits defined). > > In APCS-32 mode, is there any overlap of information between it and the PC? No, the bits in the PC that were used for the CPSR are now used for addressing the full 4Mb of memory. However, I agree that this should somehow be done with the pseudo mechanism if the physical register doesn't exist. > > > The more I think about it, the more I think that the raw<->virtual > > translation is in the wrong part of GDB. Shouldn't this be part of the > > Target interface? Then conversion to/from virtual format would happen as > > data is passed to/from the inferior, and the rest of GDB would only use > > the virtual format. > > Yes, I agree that raw<->virtual is wrong; but no, it shouldn't be pushed > down below the target. > > > As I understand it, this would clean up the MIPS issue entirely -- when > > talking to a target that supplies additional bits for a register, the > > target layer would strip these off/add them back, and the rest of gdb > > wouldn't have to worry about it. > > Have a look at the SH5 patch. I think this gets it right. > > The first cut at all this had the target using supply_register() to fill > in missing values in from below the cache - turns out this makes > coherency hard. The current revision uses register_{read,write} above > the cache to do this, thus eliminating redundant information in the cache. > > For the SH5, the raw register cache contains SHmedia (32/64 bit?) > registers (as that is what the raw hardware has). Pseudo-registers, and > register_{read,write} are then used to map SHcompact (16/32?) registers > onto the corresponding raw registers. OK, I'll buy the argument that the cache should contain exactly the physical registers and nothing else (ie no pseudos). That is, there is a one-one mapping between the registers in the cache and the registers in the machine. The issue is what the format of those registers in the cache should be. My feeling is that they should be normalized (I deliberately use a different word from virtualized), so that regardless of the access mechanism used in the target vector -- again note, not the gdbarch vector-- (eg, does the protocol transfer four words, or only three), the format of the values in the cache are the same. Now obviously for this to work, then there must exist mapping functions f() and f'() that convert between the two formats with no loss of information for the useful domain of the register. With the above constraints, I can't see how that would lead to any coherency issues. Now, ideally, this normalized format would be the same as the virtualized format (so that no further conversion was needed), and that would also match the memory format used by a register save to the stack frame. However, on the ARM, we can't really predict what that format will be -- it could well depend on the instructions used to generate the frame (STFE or SFM). Further, we probably also need to know the type of FPE/FPA in use by the target to understand that format, and that can only be done by interrogating the FPSR (floating point status register). So, I think we also need additional conversion routines, say g() and g'() that convert to and from memory format -- we may even need multiple such functions, since if we are reading from a memory location created with stfe we may need a different conversion from when a memory location was created with sfm. These conversions ARE part of the arch vector, but for most targets will be identity operations. Now obviously, in order to do all this correctly the stack-frame groveller will have to record the information as it unwinds the stack in some private data; but creating this information is part of the stack-unwinding process. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 3:45 ` Richard Earnshaw @ 2002-05-10 7:48 ` Andrew Cagney 2002-05-10 12:07 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-10 7:48 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > Now obviously, in order to do all this correctly the stack-frame groveller > will have to record the information as it unwinds the stack in some > private data; but creating this information is part of the stack-unwinding > process. Yes. The arm would need to implement a custom get_saved_register() architecture method. Rather than normalize the registers on the way in. Consider normalizing them them on the way out via a pseudo. Doing this would mean that the raw register wouldn't be directly visible and the layer below regcache wouldn't need to normalize anything. Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 7:48 ` Andrew Cagney @ 2002-05-10 12:07 ` Andrew Cagney 2002-05-11 7:05 ` Richard Earnshaw 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-10 12:07 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb >> Now obviously, in order to do all this correctly the stack-frame groveller will have to record the information as it unwinds the stack in some private data; but creating this information is part of the stack-unwinding process. > > Yes. The arm would need to implement a custom get_saved_register() architecture method. > > Rather than normalize the registers on the way in. Consider normalizing them them on the way out via a pseudo. Doing this would mean that the raw register wouldn't be directly visible and the layer below regcache wouldn't need to normalize anything. [to expand a little] Two target side interfaces (at least) don't have mechanisms for re-aranging (normalizing) registers on the way in: - sim - remote I suspect that at least short term, doing everything on the gdb-core side will be easier. Having the very raw data in the cache may also prove better for debugging - both the raw (in cache) and the normalized (via register read/write) formats are available. Perhaphs also look at the i387 which normalizes things on the way in (and its bug count). enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 12:07 ` Andrew Cagney @ 2002-05-11 7:05 ` Richard Earnshaw 2002-05-11 14:52 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-11 7:05 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > >> Now obviously, in order to do all this correctly the stack-frame groveller will have to record the information as it unwinds the stack in some private data; but creating this information is part of the stack-unwinding process. > > > > > Yes. The arm would need to implement a custom get_saved_register() architecture method. > > > > Rather than normalize the registers on the way in. Consider normalizing them them on the way out via a pseudo. Doing this would mean that the raw register wouldn't be directly visible and the layer below regcache wouldn't need to normalize anything. > > [to expand a little] > > Two target side interfaces (at least) don't have mechanisms for > re-aranging (normalizing) registers on the way in: > - sim > - remote > I suspect that at least short term, doing everything on the gdb-core > side will be easier. No, it wouldn't. Because then the gdb-core side would have to know *how* the target was connected. That is, the normalization function becomes f(value,target-vector); which complicates things vastly. > Having the very raw data in the cache may also prove better for > debugging - both the raw (in cache) and the normalized (via register > read/write) formats are available. Perhaphs also look at the i387 which > normalizes things on the way in (and its bug count). Let me try and clarify the model that I think we have in gdb; maybe that will help to explain why I think doing it on the gdb-core side is incorrect. GDB has three main vectors, but only two are interesting in this case (the third being the UI). The target vector is the lowest level, it provides a virtual abstraction of the processor -- registers, memory etc and methods for recovering/changing their contents and generally manipulating the machine (stepping, breakpoints, etc). The target vector should present a substantially uniform view of the processor regardless of the method used to connect to it. Putting it another way, the target vector presents substantially the basic programmers' model of the CPU to the debugger. The gdbarch vector is, effectively, the ABI model applied to that virtual machine; it covers the mapping rules that were used by the compiler when it produced the machine code for the user's program: procedure call standards, layout of record types, symbolic information etc. It knows, for example, when a double for the variable X is in register F0: it doesn't want to have to worry about how F0 is being recovered from the physical machine -- in particular it doesn't want to know about how that might vary across the various target connections -- that's the responsibility of the target vector. As to whether the sim or remote targets can be made to support this model cleanly, I'm not to worried about sim -- we can always fix this in sim/arm/wrapper.c, the layer that interfaces between gdb and the simulator so that it presents the virtual CPU model directly. I don't know enough about remote.c at this time to know what the problems are there, but I suspect that this one will be the least of my worries when I want to start adding support for the banked registers as well. However, if these targets can't present the processor abstraction cleanly, then they are technically broken ;-) R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-11 7:05 ` Richard Earnshaw @ 2002-05-11 14:52 ` Andrew Cagney 2002-05-12 7:20 ` Richard Earnshaw 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-11 14:52 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > GDB has three main vectors, but only two are interesting in this case (the > third being the UI). The target vector is the lowest level, it provides a > virtual abstraction of the processor -- registers, memory etc and methods > for recovering/changing their contents and generally manipulating the > machine (stepping, breakpoints, etc). The target vector should present a > substantially uniform view of the processor regardless of the method used > to connect to it. Putting it another way, the target vector presents > substantially the basic programmers' model of the CPU to the debugger. > > The gdbarch vector is, effectively, the ABI model applied to that virtual > machine; it covers the mapping rules that were used by the compiler when > it produced the machine code for the user's program: procedure call > standards, layout of record types, symbolic information etc. It knows, > for example, when a double for the variable X is in register F0: it > doesn't want to have to worry about how F0 is being recovered from the > physical machine -- in particular it doesn't want to know about how that > might vary across the various target connections -- that's the > responsibility of the target vector. For registers things are currently closest to: debug register -> gdbarch_register_{read,write} -> regcache_{read,write} register-cache In a sense gdbarch_register_{read,write} serve double duty - both mapping an ABI onto an ISA and handling target/ISA variation. I think you're proposing that the ISA variant part be separated out with: -> target representation target below the register cache. I'm assuming that the ABI->ISA part remain and that there still be several ``ISAs'' - 32 / 64 bit MIPS, 26/32 Arm, ... > As to whether the sim or remote targets can be made to support this model > cleanly, I'm not to worried about sim -- we can always fix this in > sim/arm/wrapper.c, the layer that interfaces between gdb and the simulator > so that it presents the virtual CPU model directly. I don't know enough > about remote.c at this time to know what the problems are there, but I > suspect that this one will be the least of my worries when I want to start > adding support for the banked registers as well. However, if these > targets can't present the processor abstraction cleanly, then they are > technically broken ;-) The remote target is more than technically broken. GDB is a slave to the remote protocol. The remote protocol is what decides the layout of the raw register cache and that cache layout depends on what ever the remote target and GDB once, long ago, co-conspired. You can't touch the raw registers without breaking GDB's ability to debug a remote target. The MIPS, for instance, has more remote protocol formats than I've had hot dinners. Every different MIPS configuration has a different, hard wired, remote protocol register buffer. BTW, the reason I mention i387-tdep.c is that I think it is an example of where target side manipulation can go wrong. The i387-tdep code doesn't just massage values, it instead completly re-orders the register cache so that it contains the registers in i387 stack order. That, in turn, lead to all sorts of bugs when trying to save/restore the i387 registers. If this were re-implemented today, I think it the register buffer would be would left in i387 save order, instead using register_{read,write} (they were not available at the time). I think, under your model, this would be flaged as a no-no - there being no technical reason for laying the registers out in a way other than according to i387 save order. enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-11 14:52 ` Andrew Cagney @ 2002-05-12 7:20 ` Richard Earnshaw 2002-05-12 8:25 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-12 7:20 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > The remote target is more than technically broken. > I'm glad we agree on something then ;-) > GDB is a slave to the remote protocol. The remote protocol is what > decides the layout of the raw register cache and that cache layout > depends on what ever the remote target and GDB once, long ago, > co-conspired. You can't touch the raw registers without breaking GDB's > ability to debug a remote target. The MIPS, for instance, has more > remote protocol formats than I've had hot dinners. Every different MIPS > configuration has a different, hard wired, remote protocol register buffer. > > BTW, the reason I mention i387-tdep.c is that I think it is an example > of where target side manipulation can go wrong. The i387-tdep code > doesn't just massage values, it instead completly re-orders the register > cache so that it contains the registers in i387 stack order. That, in > turn, lead to all sorts of bugs when trying to save/restore the i387 > registers. If this were re-implemented today, I think it the register > buffer would be would left in i387 save order, instead using > register_{read,write} (they were not available at the time). Having either the debug-info register numbers or a single target impose an order on the regcache is broken. Consider the case where we have two target interfaces that need to mandate different orderings; clearly one of them must fail. Similarly, having the debug-info mandate an ordering is equally broken -- consider two ABIs which use different numbering in the debug info. Clearly, the only way to solve this is to have mapping layers, at least in concept, at each interface. Then the tdep code is free to select any ordering it likes in the cache; typically an ordering that will lead to greatest efficiency. A colleague of mine once commented: "There's very few software problems that can't be solved with an extra layer of indirection." This is clearly one that can... > I think, under your model, this would be flaged as a no-no - there being > no technical reason for laying the registers out in a way other than > according to i387 save order. See the WIP code I posted just now. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 7:20 ` Richard Earnshaw @ 2002-05-12 8:25 ` Andrew Cagney 2002-05-12 8:30 ` Richard Earnshaw 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 8:25 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > Having either the debug-info register numbers See my other reply. The debug-info registers do not impose order on the register cache. > or a single target impose an > order on the regcache is broken. And fixing remote.c is on the hit list (I should fix Daniel's bug) :-) It already has an internal table that does a mapping only it is 1:1. remote.c is complicated, however. The mapping will need to be defined at run (and not compile) time - this makes trying to perform transformations (and not simple mappings) on the way through more difficult. > Consider the case where we have two > target interfaces that need to mandate different orderings; clearly one of > them must fail. Similarly, having the debug-info mandate an ordering is > equally broken -- consider two ABIs which use different numbering in the > debug info. Clearly, the only way to solve this is to have mapping > layers, at least in concept, at each interface. Then the tdep code is > free to select any ordering it likes in the cache; typically an ordering > that will lead to greatest efficiency. Here, you're preaching to the converted :-) enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 8:25 ` Andrew Cagney @ 2002-05-12 8:30 ` Richard Earnshaw 2002-05-12 8:51 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-12 8:30 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb ac131313@cygnus.com said: > And fixing remote.c is on the hit list (I should fix Daniel's bug) :-) > It already has an internal table that does a mapping only it is 1:1. > remote.c is complicated, however. The mapping will need to be defined > at run (and not compile) time - this makes trying to perform > transformations (and not simple mappings) on the way through more > difficult. Surely it only has to select one of several pre-compiled mappings that is appropriate for the target processor configuration. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 8:30 ` Richard Earnshaw @ 2002-05-12 8:51 ` Andrew Cagney 0 siblings, 0 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 8:51 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > ac131313@cygnus.com said: > >> And fixing remote.c is on the hit list (I should fix Daniel's bug) :-) >> It already has an internal table that does a mapping only it is 1:1. >> remote.c is complicated, however. The mapping will need to be defined >> at run (and not compile) time - this makes trying to perform >> transformations (and not simple mappings) on the way through more >> difficult. > > > Surely it only has to select one of several pre-compiled mappings that is > appropriate for the target processor configuration. I wish! :-) I don't think anyone knows how many mappings there are. Every single mips target, for instance, likely has a different mapping. Instead of trying to second guess all of them, remote.c is being changed so that the user can specify them at runtime. That way, when (not if :-) the default mapping screws up, the user can fix it. enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 11:52 ` Andrew Cagney 2002-05-10 3:45 ` Richard Earnshaw @ 2002-05-10 9:29 ` Richard Earnshaw 2002-05-10 11:42 ` Andrew Cagney 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-10 9:29 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb If, as I understand your previous postings to imply, having pseudo registers stored in the cache is wrong, why does regcache_read() allow them? regcache_read (int rawnum, char *buf) { gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS)); R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 9:29 ` Richard Earnshaw @ 2002-05-10 11:42 ` Andrew Cagney 2002-05-11 6:16 ` Richard Earnshaw 2002-05-11 11:41 ` Richard Earnshaw 0 siblings, 2 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-10 11:42 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > If, as I understand your previous postings to imply, having pseudo > registers stored in the cache is wrong, why does regcache_read() allow > them? > > regcache_read (int rawnum, char *buf) > { > gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS)); Lets just pretend you didn't see that :-) Some existing mechanisms store pseudo-register values in the cache. In addition ``NUM_REGS'' is overloaded - it controls too many aspects of GDB - num regs in G packet, num regs to save across an inferior function call, ... Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 11:42 ` Andrew Cagney @ 2002-05-11 6:16 ` Richard Earnshaw 2002-05-11 11:41 ` Richard Earnshaw 1 sibling, 0 replies; 30+ messages in thread From: Richard Earnshaw @ 2002-05-11 6:16 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > > If, as I understand your previous postings to imply, having pseudo > > registers stored in the cache is wrong, why does regcache_read() allow > > them? > > > > regcache_read (int rawnum, char *buf) > > { > > gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS)); > > Lets just pretend you didn't see that :-) > Some existing mechanisms store pseudo-register values in the cache. In > addition ``NUM_REGS'' is overloaded - it controls too many aspects of > GDB - num regs in G packet, num regs to save across an inferior function > call, ... So how about a comment saying pseudo regs shouldn't be in the cache! R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-10 11:42 ` Andrew Cagney 2002-05-11 6:16 ` Richard Earnshaw @ 2002-05-11 11:41 ` Richard Earnshaw 2002-05-11 13:36 ` Andrew Cagney 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-11 11:41 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > > If, as I understand your previous postings to imply, having pseudo > > registers stored in the cache is wrong, why does regcache_read() allow > > them? > > > > regcache_read (int rawnum, char *buf) > > { > > gdb_assert (rawnum >= 0 && rawnum < (NUM_REGS + NUM_PSEUDO_REGS)); > > Lets just pretend you didn't see that :-) > Some existing mechanisms store pseudo-register values in the cache. In > addition ``NUM_REGS'' is overloaded - it controls too many aspects of > GDB - num regs in G packet, num regs to save across an inferior function > call, ... > > Andrew > > Argh! I've just come across another nasty gotcha in this code, if I try to make it so that the regcache does not hold any pseudos: There's an implicit assumption that all the physical registers will preceed the pseudo registers. This is a major problem when I want to implement the banked registers for the ARM, since then r8 through r14 (which must have regnums 8 through 14 for stabs debug info to work correctly), need to be pseudo registers (they must access the correct physical register for the current processor mode); which means they must appear in the middle of the register range. I can make my arm_register_read function correctly remap the register numbers, but then I run into the problem that REGISTER_RAW_SIZE is used both above and below the regcache. Would you be averse to me creating a gdbarch entry for REGISTER_REGCACHE_RAW_SIZE (which defaults to REGISTER_RAW_SIZE) and then using that when directly accessing the cache? R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-11 11:41 ` Richard Earnshaw @ 2002-05-11 13:36 ` Andrew Cagney 2002-05-12 7:11 ` Richard Earnshaw 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-11 13:36 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > > Argh! I've just come across another nasty gotcha in this code, if I try > to make it so that the regcache does not hold any pseudos: There's an > implicit assumption that all the physical registers will preceed the > pseudo registers. I should have warned you to not go looking under rocks :-( I think the real issue on this one is that the pseudo-registers and raw registers currently occupy the same register number space. If there was clear separation then it would be clear how many of these problems should be handled - you couldn't for instance try to put a pseudo in the middle of the raw part of the register buffer. I think it was mentioned, when adding register_{read,write} that this was likely to be sufficient rope to .... See also gdb/122. > This is a major problem when I want to implement the banked registers for > the ARM, since then r8 through r14 (which must have regnums 8 through 14 > for stabs debug info to work correctly), need to be pseudo registers (they > must access the correct physical register for the current processor mode); > which means they must appear in the middle of the register range. Make these pseudo registers (the corresponding real register_name() return ""), map stabs_regnum onto that and then (for all raw registers) use register register_{read,write} map onto the correct raw register. You'll also need to tweak saved_regs[] to set the pseudo and not the real register address. Even consider making everything a pseudo so that you know exactly what you have at any stage. > I can make my arm_register_read function correctly remap the register > numbers, but then I run into the problem that REGISTER_RAW_SIZE is used > both above and below the regcache. I don't understand why this is a problem. I think a register (pseudo or raw) should have only one size (c.f. my register_size() patch). Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-11 13:36 ` Andrew Cagney @ 2002-05-12 7:11 ` Richard Earnshaw 2002-05-12 7:40 ` Richard Earnshaw 2002-05-12 8:07 ` Andrew Cagney 0 siblings, 2 replies; 30+ messages in thread From: Richard Earnshaw @ 2002-05-12 7:11 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb [-- Attachment #1: Type: text/plain, Size: 783 bytes --] > Even consider making everything a pseudo so that you know exactly what > you have at any stage. > Hmm, I think this is effectively what I have. See the code below (which is very much a work-in-progress..., so don't even expect it to compile ;-) > > I can make my arm_register_read function correctly remap the register > > numbers, but then I run into the problem that REGISTER_RAW_SIZE is used > > both above and below the regcache. > > I don't understand why this is a problem. I think a register (pseudo or > raw) should have only one size (c.f. my register_size() patch). However, in this situation, pseudo_rengo("r0") != regcache_regno("r0"), yet we effectively have REGSITER_RAW_SIZE (pseudo_regno ("r0")) and REGISTER_RAW_SIZE (regcache_regno ("r0")) R. [-- Attachment #2: gdb-regcache.patch --] [-- Type: text/x-patch , Size: 26368 bytes --] Index: arm-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/arm-tdep.c,v retrieving revision 1.60 diff -p -r1.60 arm-tdep.c *** arm-tdep.c 9 May 2002 18:07:00 -0000 1.60 --- arm-tdep.c 12 May 2002 14:08:37 -0000 *************** static const char * const arm_abi_names[ *** 113,133 **** /* Number of different reg name sets (options). */ static int num_flavor_options; ! /* We have more registers than the disassembler as gdb can print the value ! of special registers as well. ! The general register names are overwritten by whatever is being used by ! the disassembler at the moment. We also adjust the case of cpsr and fps. */ ! ! /* Initial value: Register names used in ARM's ISA documentation. */ ! static char * arm_register_name_strings[] = ! {"r0", "r1", "r2", "r3", /* 0 1 2 3 */ ! "r4", "r5", "r6", "r7", /* 4 5 6 7 */ ! "r8", "r9", "r10", "r11", /* 8 9 10 11 */ ! "r12", "sp", "lr", "pc", /* 12 13 14 15 */ ! "f0", "f1", "f2", "f3", /* 16 17 18 19 */ ! "f4", "f5", "f6", "f7", /* 20 21 22 23 */ ! "fps", "cpsr" }; /* 24 25 */ ! static char **arm_register_names = arm_register_name_strings; /* Valid register name flavors. */ static const char **valid_flavors; --- 113,275 ---- /* Number of different reg name sets (options). */ static int num_flavor_options; ! /* We have more registers than the disassembler as gdb can print the ! value of special registers as well. It can also display the ! contents of banked registers if these are available from the ! inferior. ! ! Depending on the architecture, ARM processors have up to 31 integer ! registers, but these are banked so that only 16 are visible at any ! one time. The layout of the table is complicated by the fact that ! the ordering must match that used by the compiler to generate ! stabs/dwarf entries, so we put the banked registers first, even ! though we implement some of them as pseudos (mapping onto the ! correct bank entry for the current mode). A debug record entry may ! contain: ! ! 0-15 for the integer registers r0-r15, ! 16-23 for the FPA registers f0-f7, ! 32-63 for the VFP registers s0-s31. ! ! Which leaves a gap of 8 registers in the numbering space: we put ! the cpsr, spsr (x5), fpsr and fpcr registers in this space, though ! not all of these will always be available. None of these registers ! will have debug table entries. [XXX-rwe 20020511 At least, I don't ! think so]. ! ! The general register names are overwritten by whatever is being ! used by the disassembler at the moment. We also adjust the case of ! cpsr and fps. ! ! Note, the ordering of registers in the regcache is entirely ! different, since we don't want the pseudo registers in that. The ! mapping tables follow. */ ! ! ! struct register_info ! { ! const char *name, ! enum arm_phys_reg regcache, ! enum arm_reg_class regclass ! }; ! ! static struct register_info arm_register_info[] = ! { ! { "r0", ARM_PHYS_R0, ARM_REGCLASS_INT }, ! { "r1", ARM_PHYS_R1, ARM_REGCLASS_INT }, ! { "r2", ARM_PHYS_R2, ARM_REGCLASS_INT }, ! { "r3", ARM_PHYS_R3, ARM_REGCLASS_INT }, ! { "r4", ARM_PHYS_R4, ARM_REGCLASS_INT }, ! { "r5", ARM_PHYS_R5, ARM_REGCLASS_INT }, ! { "r6", ARM_PHYS_R6, ARM_REGCLASS_INT }, ! { "r7", ARM_PHYS_R7, ARM_REGCLASS_INT }, ! /* Pseudos mapping to banked registers. */ ! { "r8", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "r9", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "r10", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "r11", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "r12", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "sp", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "lr", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! { "pc", ARM_PHYS_NONE, ARM_REGCLASS_INT }, ! /* FPA registers. */ ! { "f0", ARM_PHYS_F0, ARM_REGCLASS_FPA }, ! { "f1", ARM_PHYS_F1, ARM_REGCLASS_FPA }, ! { "f2", ARM_PHYS_F2, ARM_REGCLASS_FPA }, ! { "f3", ARM_PHYS_F3, ARM_REGCLASS_FPA }, ! { "f4", ARM_PHYS_F4, ARM_REGCLASS_FPA }, ! { "f5", ARM_PHYS_F5, ARM_REGCLASS_FPA }, ! { "f6", ARM_PHYS_F6, ARM_REGCLASS_FPA }, ! { "f7", ARM_PHYS_F7, ARM_REGCLASS_FPA }, ! /* PSR type registers (in unused space). */ ! { "cpsr", ARM_PHYS_NONE, ARM_REGCLASS_PSR }, ! { "spsr_svc", ARM_PHYS_SPSR_SVC, ARM_REGCLASS_PSR }, ! { "spsr_abt", ARM_PHYS_SPSR_ABT, ARM_REGCLASS_PSR }, ! { "spsr_und", ARM_PHYS_SPSR_UND, ARM_REGCLASS_PSR }, ! { "spsr_irq", ARM_PHYS_SPSR_IRQ, ARM_REGCLASS_PSR }, ! { "spsr_fiq", ARM_PHYS_SPSR_FIQ, ARM_REGCLASS_PSR }, ! { "fpsr", ARM_PHYS_FPSR, ARM_REGCLASS_FPA_FPSR }, ! { "fpcr", ARM_PHYS_FPCR, ARM_REGCLASS_FPA_FPCR }, ! /* Single precision VFP registers. */ ! { "s0", ARM_PHYS_S0, ARM_REGCLASS_VFP_SP }, ! { "s1", ARM_PHYS_S1, ARM_REGCLASS_VFP_SP }, ! { "s2", ARM_PHYS_S2, ARM_REGCLASS_VFP_SP }, ! { "s3", ARM_PHYS_S3, ARM_REGCLASS_VFP_SP }, ! { "s4", ARM_PHYS_S4, ARM_REGCLASS_VFP_SP }, ! { "s5", ARM_PHYS_S5, ARM_REGCLASS_VFP_SP }, ! { "s6", ARM_PHYS_S6, ARM_REGCLASS_VFP_SP }, ! { "s7", ARM_PHYS_S7, ARM_REGCLASS_VFP_SP }, ! { "s8", ARM_PHYS_S8, ARM_REGCLASS_VFP_SP }, ! { "s9", ARM_PHYS_S9, ARM_REGCLASS_VFP_SP }, ! { "s10", ARM_PHYS_S10, ARM_REGCLASS_VFP_SP }, ! { "s11", ARM_PHYS_S11, ARM_REGCLASS_VFP_SP }, ! { "s12", ARM_PHYS_S12, ARM_REGCLASS_VFP_SP }, ! { "s13", ARM_PHYS_S13, ARM_REGCLASS_VFP_SP }, ! { "s14", ARM_PHYS_S14, ARM_REGCLASS_VFP_SP }, ! { "s15", ARM_PHYS_S15, ARM_REGCLASS_VFP_SP }, ! { "s16", ARM_PHYS_S16, ARM_REGCLASS_VFP_SP }, ! { "s17", ARM_PHYS_S17, ARM_REGCLASS_VFP_SP }, ! { "s18", ARM_PHYS_S18, ARM_REGCLASS_VFP_SP }, ! { "s19", ARM_PHYS_S19, ARM_REGCLASS_VFP_SP }, ! { "s20", ARM_PHYS_S20, ARM_REGCLASS_VFP_SP }, ! { "s21", ARM_PHYS_S21, ARM_REGCLASS_VFP_SP }, ! { "s22", ARM_PHYS_S22, ARM_REGCLASS_VFP_SP }, ! { "s23", ARM_PHYS_S23, ARM_REGCLASS_VFP_SP }, ! { "s24", ARM_PHYS_S24, ARM_REGCLASS_VFP_SP }, ! { "s25", ARM_PHYS_S25, ARM_REGCLASS_VFP_SP }, ! { "s26", ARM_PHYS_S26, ARM_REGCLASS_VFP_SP }, ! { "s27", ARM_PHYS_S27, ARM_REGCLASS_VFP_SP }, ! { "s28", ARM_PHYS_S28, ARM_REGCLASS_VFP_SP }, ! { "s29", ARM_PHYS_S29, ARM_REGCLASS_VFP_SP }, ! { "s30", ARM_PHYS_S30, ARM_REGCLASS_VFP_SP }, ! { "s31", ARM_PHYS_S31, ARM_REGCLASS_VFP_SP }, ! /* Double precision pseudo views of the above. */ ! { "d0", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d1", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d2", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d3", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d4", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d5", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d6", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d7", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d8", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d9", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d10", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d11", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d12", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d13", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d14", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! { "d15", ARM_PHYS_NONE, ARM_REGCLASS_VFP_DP }, ! /* VFP status registers. */ ! { "fpsid" ARM_PHYS_FPSID, ARM_REGCLASS_VFP_FPSID }, ! { "fpscr", ARM_PHYS_FPSCR, ARM_REGCLASS_VFP_FPSCR }, ! { "fpexc", ARM_PHYS_FPEXC, ARM_REGCLASS_VFP_FPEXC }, ! /* Banked registers. */ ! { "r8_usr", ARM_PHYS_R8_USR, ARM_REGCLASS_INT }, ! { "r9_usr", ARM_PHYS_R9_USR, ARM_REGCLASS_INT }, ! { "r10_usr", ARM_PHYS_R10_USR, ARM_REGCLASS_INT }, ! { "r11_usr", ARM_PHYS_R11_USR, ARM_REGCLASS_INT }, ! { "r12_usr", ARM_PHYS_R12_USR, ARM_REGCLASS_INT }, ! { "r13_usr", ARM_PHYS_R13_USR, ARM_REGCLASS_INT }, ! { "r14_usr", ARM_PHYS_R14_USR, ARM_REGCLASS_INT }, ! { "r15_raw", ARM_PHYS_R15, ARM_REGCLASS_INT }, ! { "r13_svc", ARM_PHYS_R13_SVC, ARM_REGCLASS_INT }, ! { "r14_svc", ARM_PHYS_R14_SVC, ARM_REGCLASS_INT }, ! { "r13_abt", ARM_PHYS_R13_ABT, ARM_REGCLASS_INT }, ! { "r14_abt", ARM_PHYS_R14_ABT, ARM_REGCLASS_INT }, ! { "r13_und", ARM_PHYS_R13_UND, ARM_REGCLASS_INT }, ! { "r14_und", ARM_PHYS_R14_UND, ARM_REGCLASS_INT }, ! { "r13_irq", ARM_PHYS_R13_IRQ, ARM_REGCLASS_INT }, ! { "r14_irq", ARM_PHYS_R14_IRQ, ARM_REGCLASS_INT }, ! { "r8_fiq", ARM_PHYS_R8_FIQ, ARM_REGCLASS_INT }, ! { "r9_fiq", ARM_PHYS_R9_FIQ, ARM_REGCLASS_INT }, ! { "r10_fiq", ARM_PHYS_R10_FIQ, ARM_REGCLASS_INT }, ! { "r11_fiq", ARM_PHYS_R11_FIQ, ARM_REGCLASS_INT }, ! { "r12_fiq", ARM_PHYS_R12_FIQ, ARM_REGCLASS_INT }, ! { "r13_fiq", ARM_PHYS_R13_FIQ, ARM_REGCLASS_INT }, ! { "r14_fiq", ARM_PHYS_R14_FIQ, ARM_REGCLASS_INT }, ! { "spsr" ARM_PHYS_NONE, ARM_REGCLASS_PSR }, ! }; /* Valid register name flavors. */ static const char **valid_flavors; *************** arm_print_float_info (void) *** 1596,1627 **** static struct type * arm_register_type (int regnum) { ! if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS) { if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) return builtin_type_arm_ext_big; else return builtin_type_arm_ext_littlebyte_bigword; - } - else - return builtin_type_int32; - } ! /* Index within `registers' of the first byte of the space for ! register N. */ ! static int ! arm_register_byte (int regnum) ! { ! if (regnum < ARM_F0_REGNUM) ! return regnum * INT_REGISTER_RAW_SIZE; ! else if (regnum < ARM_PS_REGNUM) ! return (NUM_GREGS * INT_REGISTER_RAW_SIZE ! + (regnum - ARM_F0_REGNUM) * FP_REGISTER_RAW_SIZE); ! else ! return (NUM_GREGS * INT_REGISTER_RAW_SIZE ! + NUM_FREGS * FP_REGISTER_RAW_SIZE ! + (regnum - ARM_FPS_REGNUM) * STATUS_REGISTER_SIZE); } /* Number of bytes of storage in the actual machine representation for --- 1738,1766 ---- static struct type * arm_register_type (int regnum) { ! switch (arm_register_info[regnum].class) { + case ARM_REGCLASS_FPA: if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) return builtin_type_arm_ext_big; else return builtin_type_arm_ext_littlebyte_bigword; ! case ARM_REGCLASS_VFP_SP: ! if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ! return builtin_type_ieee_double_big; ! else ! return builtin_type_ieee_double_little; ! case ARM_REGCLASS_VFP_DP: ! if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ! return builtin_type_ieee_single_big; ! else ! return builtin_type_ieee_single_little; ! ! default: ! return builtin_type int32; ! } } /* Number of bytes of storage in the actual machine representation for *************** arm_register_byte (int regnum) *** 1629,1657 **** 12 bytes in length. */ static int ! arm_register_raw_size (int regnum) { ! if (regnum < ARM_F0_REGNUM) ! return INT_REGISTER_RAW_SIZE; ! else if (regnum < ARM_FPS_REGNUM) ! return FP_REGISTER_RAW_SIZE; ! else ! return STATUS_REGISTER_SIZE; } ! /* Number of bytes of storage in a program's representation ! for register N. */ static int ! arm_register_virtual_size (int regnum) { ! if (regnum < ARM_F0_REGNUM) ! return INT_REGISTER_VIRTUAL_SIZE; ! else if (regnum < ARM_FPS_REGNUM) ! return FP_REGISTER_VIRTUAL_SIZE; ! else ! return STATUS_REGISTER_SIZE; } /* NOTE: cagney/2001-08-20: Both convert_from_extended() and convert_to_extended() use floatformat_arm_ext_littlebyte_bigword. --- 1768,1949 ---- 12 bytes in length. */ static int ! arm_register_size (int regnum) { ! switch (arm_register_info[regnum].class) ! { ! case ARM_REGCLASS_INT: ! return INT_REGISTER_SIZE; ! case ARM_REGCLASS_FPA: ! return FPA_REGISTER_SIZE; ! case ARM_REGCLASS_VFP_SP: ! return VFP_SP_REGISTER_SIZE; ! case ARM_REGCLASS_VFP_DP: ! return VFP_DP_REGISTER_SIZE; ! default: ! return STATUS_REGISTER_SIZE; ! } } ! /* Index within the regcache of the first byte of the space for ! register N. ! NOTE: calling this with regnum == ARM_PHYS_NUM_REGS will give the ! size of the regcache. */ ! static int ! arm_register_byte (int regnum) { ! static int *reg_offsets = 0; ! ! if (reg_offsets == 0) ! { ! int i; ! int offset = 0; ! ! reg_offset = (int *) xmalloc ((1 + ARM_PHYS_NUM_REGS) * sizeof (int)); ! ! for (i = 0; i <= ARM_PHYS_NUM_REGS; i++) ! { ! reg_offset[i] = offset; ! offset += arm_register_size (i); ! } ! } ! ! return reg_offset[i]; ! } ! ! /* Construct a pseudo register. */ ! static void ! arm_pseudo_register_read (struct gdbarch *gdbarch, int regno, char *buffer) ! { ! switch (arm_register_info[regno].regclass) ! { ! case ARM_REGCLASS_INT: ! switch (read_register (ARM_PS_REGNUM) & PSR_MODE_MASK) ! { ! case MODE_FIQ32: ! case MODE_FIQ26: ! regcache_read (ARM_PHYS_R8_FIQ + (regno - ARM_R8_REGNUM), buffer); ! break; ! ! case MODE_IRQ32: ! case MODE_IRQ26: ! if (regno == ARM_SP_REGNUM || regno == ARM_LR_REGNUM) ! { ! regcache_read (ARM_PHYS_R13_IRQ + (regno - ARM_SP_REGNUM), ! buffer); ! break; ! } ! /* Fall through. */ ! ! case MODE_SVC32: ! case MODE_SVC26: ! if (regno == ARM_SP_REGNUM || regno == ARM_LR_REGNUM) ! { ! regcache_read (ARM_PHYS_R13_SVC + (regno - ARM_SP_REGNUM), ! buffer); ! break; ! } ! /* Fall through. */ ! ! case MODE_ABT: ! if (regno == ARM_SP_REGNUM || regno == ARM_LR_REGNUM) ! { ! regcache_read (ARM_PHYS_R13_ABT + (regno - ARM_SP_REGNUM), ! buffer); ! break; ! } ! /* Fall through. */ ! ! case MODE_UND: ! if (regno == ARM_SP_REGNUM || regno == ARM_LR_REGNUM) ! { ! regcache_read (ARM_PHYS_R13_UND + (regno - ARM_SP_REGNUM), ! buffer); ! break; ! } ! /* Fall through. */ ! ! default: /* Everything else reads from the user bank. ! regcache_read (ARM_PHYS_R8_USR + (regno - ARM_R8_REGNUM), buffer); ! break; ! ! } ! break; ! ! case ARM_REGCLASS_PSR: ! /* Two cases to handle here. The CPSR and the SPSR. ! The CPSR will either be in the physical register, or part of the ! PC. We look at the APCS mode to determine which. ! ! The SPSR may not exist if the current mode is not privilaged (or it ! is System mode). To determine that we need to look at the CPSR. */ ! if (regno == ARM_PS_REGNUM) /* CPSR. */ ! { ! if (arm_apcs_32) ! regcache_read (ARM_PHYS_CPSR, buffer); ! else ! { ! LONGEST cpsr_bits; ! ! regcache_read (ARM_PHYS_R15, buffer); ! cpsr_bits ! = (extract_unsigned_integer (buffer, STATUS_REGISTER_SIZE) ! & APCS_26_PS_MASK); ! ! store_signed_integer (buffer, STATUS_REGISTER_SIZE, cpsr_bits); ! } ! } ! else ! { ! gdb_assert (regnum == ARM_SPSR_REGNUM); ! ! switch (read_register (ARM_PS_REGNUM) & PSR_MODE_MASK) ! { ! case MODE_FIQ32: ! regcache_read (ARM_PHYS_SPSR_FIQ, buffer); ! break; ! case MODE_IRQ32: ! regcache_read (ARM_PHYS_SPSR_IRQ, buffer); ! break; ! case MODE_SVC32: ! regcache_read (ARM_PHYS_SPSR_SVC, buffer); ! break; ! case MODE_ABT: ! regcache_read (ARM_PHYS_SPSR_ABT, buffer); ! break; ! case MODE_UND: ! regcache_read (ARM_PHYS_SPSR_UND, buffer); ! break; ! default: ! store_signed_integer (buffer, STATUS_REGISTER_SIZE, (LONGEST) 0); ! break; ! } ! } ! break; ! ! case ARM_REGCLASS_VFP_DP: ! /* XXX Fixme: suppor these pseudos. */ ! break; ! ! default: ! internal_error ! (__FILE__, __LINE__, ! "arm_pseudo_register_read: Invalid class for pseudo register %s", ! REGISTER_NAME(regno)); ! } } + /* Read a register, either directly from the regcache, or by constructing + it from other registers. */ + static void + arm_register_read (struct gdbarch *gdbarch, int regno, char *buffer) + { + if (arm_register_info[regno].regcache != ARM_PHYS_NONE) + regcache_read (regno, buffer); + else + arm_pseudo_register_read (gdbarch, regno, buffer); + } /* NOTE: cagney/2001-08-20: Both convert_from_extended() and convert_to_extended() use floatformat_arm_ext_littlebyte_bigword. *************** set_disassembly_flavor_sfunc (char *args *** 2475,2481 **** static char * arm_register_name (int i) { ! return arm_register_names[i]; } static void --- 2767,2773 ---- static char * arm_register_name (int i) { ! return arm_register_info[i].name; } static void *************** arm_gdbarch_init (struct gdbarch_info in *** 3014,3028 **** set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM); set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM); set_gdbarch_register_byte (gdbarch, arm_register_byte); ! set_gdbarch_register_bytes (gdbarch, ! (NUM_GREGS * INT_REGISTER_RAW_SIZE ! + NUM_FREGS * FP_REGISTER_RAW_SIZE ! + NUM_SREGS * STATUS_REGISTER_SIZE)); ! set_gdbarch_num_regs (gdbarch, NUM_GREGS + NUM_FREGS + NUM_SREGS); ! set_gdbarch_register_raw_size (gdbarch, arm_register_raw_size); ! set_gdbarch_register_virtual_size (gdbarch, arm_register_virtual_size); ! set_gdbarch_max_register_raw_size (gdbarch, FP_REGISTER_RAW_SIZE); ! set_gdbarch_max_register_virtual_size (gdbarch, FP_REGISTER_VIRTUAL_SIZE); set_gdbarch_register_virtual_type (gdbarch, arm_register_type); /* Integer registers are 4 bytes. */ --- 3306,3317 ---- set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM); set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM); set_gdbarch_register_byte (gdbarch, arm_register_byte); ! set_gdbarch_register_bytes (gdbarch, arm_register_byte(ARM_PHYS_NUM_REGS)); ! set_gdbarch_num_regs (gdbarch, ARM_PHYS_NUM_REGS); ! set_gdbarch_register_raw_size (gdbarch, arm_register_size); ! set_gdbarch_register_virtual_size (gdbarch, arm_register_size); ! set_gdbarch_max_register_raw_size (gdbarch, ARM_MAX_REGISTER_SIZE); ! set_gdbarch_max_register_virtual_size (gdbarch, ARM_MAX_REGISTER_SIZE); set_gdbarch_register_virtual_type (gdbarch, arm_register_type); /* Integer registers are 4 bytes. */ Index: arm-tdep.h =================================================================== RCS file: /cvs/src/src/gdb/arm-tdep.h,v retrieving revision 1.8 diff -p -r1.8 arm-tdep.h *** arm-tdep.h 7 May 2002 12:58:51 -0000 1.8 --- arm-tdep.h 12 May 2002 14:08:37 -0000 *************** *** 28,33 **** --- 28,34 ---- enum gdb_regnum { ARM_A1_REGNUM = 0, /* first integer-like argument */ ARM_A4_REGNUM = 3, /* last integer-like argument */ + ARM_R8_REGNUM = 8, /* First banked register */ ARM_AP_REGNUM = 11, ARM_SP_REGNUM = 13, /* Contains address of top of stack */ ARM_LR_REGNUM = 14, /* address to return to from a function call */ *************** enum gdb_regnum { *** 35,42 **** ARM_F0_REGNUM = 16, /* first floating point register */ ARM_F3_REGNUM = 19, /* last floating point argument register */ ARM_F7_REGNUM = 23, /* last floating point register */ ! ARM_FPS_REGNUM = 24, /* floating point status register */ ! ARM_PS_REGNUM = 25, /* Contains processor status */ ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */ THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */ ARM_NUM_ARG_REGS = 4, --- 36,43 ---- ARM_F0_REGNUM = 16, /* first floating point register */ ARM_F3_REGNUM = 19, /* last floating point argument register */ ARM_F7_REGNUM = 23, /* last floating point register */ ! ARM_PS_REGNUM = 24, /* Contains processor status */ ! ARM_FPS_REGNUM = 31, /* floating point status register */ ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */ THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */ ARM_NUM_ARG_REGS = 4, *************** enum gdb_regnum { *** 45,86 **** ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM }; /* Used in target-specific code when we need to know the size of the largest type of register we need to handle. */ ! #define ARM_MAX_REGISTER_RAW_SIZE 12 ! #define ARM_MAX_REGISTER_VIRTUAL_SIZE 8 /* Size of integer registers. */ ! #define INT_REGISTER_RAW_SIZE 4 ! #define INT_REGISTER_VIRTUAL_SIZE 4 ! /* Say how long FP registers are. Used for documentation purposes and code readability in this header. IEEE extended doubles are 80 bits. DWORD aligned they use 96 bits. */ ! #define FP_REGISTER_RAW_SIZE 12 ! /* GCC doesn't support long doubles (extended IEEE values). The FP ! register virtual size is therefore 64 bits. Used for documentation ! purposes and code readability in this header. */ ! #define FP_REGISTER_VIRTUAL_SIZE 8 /* Status registers are the same size as general purpose registers. Used for documentation purposes and code readability in this header. */ #define STATUS_REGISTER_SIZE 4 - /* Number of machine registers. The only define actually required - is NUM_REGS. The other definitions are used for documentation - purposes and code readability. */ - /* For 26 bit ARM code, a fake copy of the PC is placed in register 25 (PS) - (and called PS for processor status) so the status bits can be cleared - from the PC (register 15). For 32 bit ARM code, a copy of CPSR is placed - in PS. */ - #define NUM_FREGS 8 /* Number of floating point registers. */ - #define NUM_SREGS 2 /* Number of status registers. */ - #define NUM_GREGS 16 /* Number of general purpose registers. */ - - /* Instruction condition field values. */ #define INST_EQ 0x0 #define INST_NE 0x1 --- 46,125 ---- ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM }; + /* Indecees of the registers in the regcache. Note that this effectively + determines the order of these registers in the cache. arm_regcache_read + will perform a mapping between these and the virtual index so that debug + formats like stabs will see the registers in the right place. */ + enum arm_phys_reg { + ARM_PHYS_NONE= -1, + + ARM_PHYS_R0 = 0, ARM_PHYS_R1, ARM_PHYS_R2, ARM_PHYS_R3, + ARM_PHYS_R4, ARM_PHYS_R5, ARM_PHYS_R6, ARM_PHYS_R7, + + ARM_PHYS_R8_USR, ARM_PHYS_R9_USR, ARM_PHYS_R10_USR, ARM_PHYS_R11_USR, + ARM_PHYS_R12_USR, ARM_PHYS_R13_USR, ARM_PHYS_R14_USR, ARM_PHYS_R15, + + ARM_PHYS_R13_SVC, ARM_PHYS_R14_SVC, ARM_PHYS_SPSR_SVC, + ARM_PHYS_R13_ABT, ARM_PHYS_R14_ABT, ARM_PHYS_SPSR_ABT, + ARM_PHYS_R13_UND, ARM_PHYS_R14_UND, ARM_PHYS_SPSR_UND, + ARM_PHYS_R13_IRQ, ARM_PHYS_R14_IRQ, ARM_PHYS_SPSR_IRQ, + + ARM_PHYS_R8_FIQ, ARM_PHYS_R9_FIQ, ARM_PHYS_R10_FIQ, ARM_PHYS_R11_FIQ, + ARM_PHYS_R12_FIQ, ARM_PHYS_R13_FIQ, ARM_PHYS_R14_FIQ, ARM_PHYS_SPSR_FIQ, + + ARM_PHYS_CPSR, + + ARM_PHYS_F0, ARM_PHYS_F1, ARM_PHYS_F2, ARM_PHYS_F3, + ARM_PHYS_F4, ARM_PHYS_F5, ARM_PHYS_F6, ARM_PHYS_F7, + + ARM_PHYS_FPSR, ARM_PHYS_FPCR, + + ARM_PHYS_S0, ARM_PHYS_S1, ARM_PHYS_S2, ARM_PHYS_S3, + ARM_PHYS_S4, ARM_PHYS_S5, ARM_PHYS_S6, ARM_PHYS_S7, + ARM_PHYS_S8, ARM_PHYS_S9, ARM_PHYS_S10, ARM_PHYS_S11, + ARM_PHYS_S12, ARM_PHYS_S13, ARM_PHYS_S14, ARM_PHYS_S15, + ARM_PHYS_S16, ARM_PHYS_S17, ARM_PHYS_S18, ARM_PHYS_S19, + ARM_PHYS_S20, ARM_PHYS_S21, ARM_PHYS_S22, ARM_PHYS_S23, + ARM_PHYS_S24, ARM_PHYS_S25, ARM_PHYS_S26, ARM_PHYS_S27, + ARM_PHYS_S28, ARM_PHYS_S29, ARM_PHYS_S30, ARM_PHYS_S31, + + ARM_PHYS_FPSID, ARM_PHYS_FPSCR, ARM_PHYS_FPEXC, + + /* Keep last. */ + ARM_PHYS_NUM_REGS + }; + + enum arm_reg_class + { + ARM_REGCLASS_INT, ARM_REGCLASS_PSR, + + ARM_REGCLASS_FPA, ARM_REGCLASS_FPA_FPSR, ARM_REGCLASS_FPA_FPCR, + + ARM_REGCLASS_VFP_SP, ARM_REGCLASS_VFP_DP, ARM_REGCLASS_VFP_FPSID, + ARM_REGCLASS_VFP_FPSCR, ARM_REGCLASS_VFP_FPEXC + }; + /* Used in target-specific code when we need to know the size of the largest type of register we need to handle. */ ! #define ARM_MAX_REGISTER_SIZE FPA_REGISTER_SIZE /* Size of integer registers. */ ! #define INT_REGISTER_SIZE 4 ! /* Say how long FPA registers are. Used for documentation purposes and code readability in this header. IEEE extended doubles are 80 bits. DWORD aligned they use 96 bits. */ ! #define FPA_REGISTER_SIZE 12 ! /* Size of VFP SP and DP registers. */ ! #define VFP_SP_REGISTER_SIZE 4 ! #define VFP_DP_REGISTER_SIZE 8 /* Status registers are the same size as general purpose registers. Used for documentation purposes and code readability in this header. */ #define STATUS_REGISTER_SIZE 4 /* Instruction condition field values. */ #define INST_EQ 0x0 #define INST_NE 0x1 *************** enum gdb_regnum { *** 103,108 **** --- 142,165 ---- #define FLAG_Z 0x40000000 #define FLAG_C 0x20000000 #define FLAG_V 0x10000000 + + #define PSR_MODE_MASK 0x00000011 + + #define MODE_USR32 0x00000010 + #define MODE_FIQ32 0x00000011 + #define MODE_IRQ32 0x00000012 + #define MODE_SVC32 0x00000013 + #define MODE_ABT 0x00000017 + #define MODE_UND 0x0000001b + #define MODE_SYS 0x0000001f + #define MODE_USR26 0x00000000 + #define MODE_FIQ26 0x00000001 + #define MODE_IRQ26 0x00000002 + #define MODE_SVC26 0x00000003 + + #define APCS_26_PC_MASK 0x03fffffc + #define APCS_26_PS_MASK (~APCS_26_PC_MASK) + /* ABI variants that we know about. If you add to this enum, please update the table of names in tm-arm.c. */ ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 7:11 ` Richard Earnshaw @ 2002-05-12 7:40 ` Richard Earnshaw 2002-05-12 9:03 ` Andrew Cagney 2002-05-12 8:07 ` Andrew Cagney 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-12 7:40 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb rearnsha@arm.com said: > See the code below (which is very much a work-in-progress..., so > don't even expect it to compile ;-) Of course, there was a major flaw in the WIP code I just posted, that confuses what I was talking about in a significant way. The code for arm_register_read, should be: static void arm_register_read (struct gdbarch *gdbarch, int regno, char *buffer) { if (arm_register_info[regno].regcache != ARM_PHYS_NONE) /* Recover the register directly from the cache. */ regcache_read (arm_register_info[regno].regcache, buffer); else arm_pseudo_register_read (gdbarch, regno, buffer); } R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 7:40 ` Richard Earnshaw @ 2002-05-12 9:03 ` Andrew Cagney 2002-05-12 11:31 ` Andrew Cagney 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 9:03 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > rearnsha@arm.com said: > >> See the code below (which is very much a work-in-progress..., so >> don't even expect it to compile ;-) > > > Of course, there was a major flaw in the WIP code I just posted, that > confuses what I was talking about in a significant way. The code for > arm_register_read, should be: (I guessed this :-) > static void > arm_register_read (struct gdbarch *gdbarch, int regno, char *buffer) > { > if (arm_register_info[regno].regcache != ARM_PHYS_NONE) > /* Recover the register directly from the cache. */ > regcache_read (arm_register_info[regno].regcache, buffer); > else > arm_pseudo_register_read (gdbarch, regno, buffer); > } If I had my way, it would read: > static void > arm_register_read (struct gdbarch *gdbarch, struct pseudoreg *pseudo, char *buffer) > { > arm_pseudo_register_read (gdbarch, pseudo, buffer); > } however, that is a long way off (and, to be honest, I suspect the amount of effort required would not give a reasonable return). In the mean time, I recommend: > static void > arm_register_read (struct gdbarch *gdbarch, int regno, char *buffer) > { > gdb_assert (regno >= NUM_REGS && regno < NUM_REGS+NUM_PSEUDO_REGS); > arm_pseudo_register_read (gdbarch, regno, buffer); > } Per, the other e-mail. Keeping the separation is very important. The next person to work on the code won't know if they are looking at a pseudo or raw register. Having debugged code that used this approach, this this is very important. enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 9:03 ` Andrew Cagney @ 2002-05-12 11:31 ` Andrew Cagney 0 siblings, 0 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 11:31 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > If I had my way, it would read: > > static void > arm_register_read (struct gdbarch *gdbarch, struct pseudoreg *pseudo, char *buffer) > { > arm_pseudo_register_read (gdbarch, pseudo, buffer); > } PS: Checking my notes, I've previously used the term ``cooked'' to avoid confusion with the existing ``pseudo-reg'' framework. So the above would map a ``struct cookedreg'' onto one or more ``struct rawreg'' vis: > static void > arm_register_read (struct gdbarch *gdbarch, struct cookedreg *cooked, char *buffer) > { > arm_pseudo_register_read (gdbarch, cooked, buffer); > } The thought of having something like: struct cookedreg; int cookedreg2i (struct cookedreg *r) { return r - (struct cookedreg *)someaddress; }; et.al. To get strongly typed integers in C has also crossed my mind. Outch! :-) enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 7:11 ` Richard Earnshaw 2002-05-12 7:40 ` Richard Earnshaw @ 2002-05-12 8:07 ` Andrew Cagney 2002-05-12 8:25 ` Richard Earnshaw 2002-05-13 5:35 ` Richard Earnshaw 1 sibling, 2 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 8:07 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > Even consider making everything a pseudo so that you know exactly what >> you have at any stage. >> > > > Hmm, I think this is effectively what I have. See the code below (which is > very much a work-in-progress..., so don't even expect it to compile ;-) Even more ruthless. Try a register layout of: -- raw normal r0..r15 raw someothers raw floats raw bank r0..r15 raw still more -- pseudo r0..r15 mapped onto either normal or banked pseudo floats mapped onto floats and so on, for instance, explict register names to identify normal and banked r0. -- which completly separates the raw and pseudo registers. The function register_name() becomes: if regnum < NUM_REGS return ""; else return yourtable[regnum - NUM_REGS]; In an ideal world, I'd be changing register_{read,write} to take a ``struct pseudoreg *'' and regcache_{read,write} to take a ``struct rawreg *''. That way it would be clear what is going on. I can but dream! I'm still trying to bury registers[] -) >> > I can make my arm_register_read function correctly remap the register >> > numbers, but then I run into the problem that REGISTER_RAW_SIZE is used >> > both above and below the regcache. > >> >> I don't understand why this is a problem. I think a register (pseudo or >> raw) should have only one size (c.f. my register_size() patch). > > > However, in this situation, > pseudo_rengo("r0") != regcache_regno("r0"), yet we effectively have > > REGSITER_RAW_SIZE (pseudo_regno ("r0")) > and > REGISTER_RAW_SIZE (regcache_regno ("r0")) Sorry, I still don't understand. Given pseudo-registers, the name of the function ``register_raw_size'' is definitly overloaded. However, per the patch very recently committed, the norm should now be: register_raw_size() == register_virtual_size() == TYPE_LENGTH (register_virtual_type()) (which makes them all badly named :-) > ! /* We have more registers than the disassembler as gdb can print the > ! value of special registers as well. It can also display the > ! contents of banked registers if these are available from the > ! inferior. > ! > ! Depending on the architecture, ARM processors have up to 31 integer > ! registers, but these are banked so that only 16 are visible at any > ! one time. The layout of the table is complicated by the fact that > ! the ordering must match that used by the compiler to generate > ! stabs/dwarf entries, so we put the banked registers first, even > ! though we implement some of them as pseudos (mapping onto the > ! correct bank entry for the current mode). A debug record entry may > ! contain: > ! > ! 0-15 for the integer registers r0-r15, > ! 16-23 for the FPA registers f0-f7, > ! 32-63 for the VFP registers s0-s31. This restriction doesn't exist. Your architecture has complete control over how debug register numbers are represented internally. For instance, STABS_REG_TO_REGNUM() can be used to completly map the above numbers onto pseudo-registers. Again, in an ideal world, I'd try to change these functions to return a ``struct pseudoreg *''. That would make it clear which side of the fence they sit on :-) > ! Which leaves a gap of 8 registers in the numbering space: we put > ! the cpsr, spsr (x5), fpsr and fpcr registers in this space, though > ! not all of these will always be available. None of these registers > ! will have debug table entries. [XXX-rwe 20020511 At least, I don't > ! think so]. > ! > ! The general register names are overwritten by whatever is being > ! used by the disassembler at the moment. We also adjust the case of > ! cpsr and fps. > ! > ! Note, the ordering of registers in the regcache is entirely > ! different, since we don't want the pseudo registers in that. The > ! mapping tables follow. */ (I think I remember what you wanted me to document ....) enjoy, Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 8:07 ` Andrew Cagney @ 2002-05-12 8:25 ` Richard Earnshaw 2002-05-12 8:41 ` Andrew Cagney 2002-05-13 5:35 ` Richard Earnshaw 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-12 8:25 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > > However, in this situation, > > pseudo_rengo("r0") != regcache_regno("r0"), yet we effectively have > > > > REGSITER_RAW_SIZE (pseudo_regno ("r0")) > > and > > REGISTER_RAW_SIZE (regcache_regno ("r0")) > > Sorry, I still don't understand. In my view of things, the domain of the result returned by pseudo_regno() is 0..Num_pseudos, and the domain of regcache_regno() is 0..NUM_REGS But we have cases where the two functions return a different number for the same register; more precisely, we might encounter the situation where pseudo_regno ("int_reg0") == regcache_regno ("float_reg5") and clearly in this case one of these will give the wrong answer if used to call REGISTER_RAW_SIZE(). > Sorry, I still don't understand. Given pseudo-registers, the name of > the function ``register_raw_size'' is definitly overloaded. However, > per the patch very recently committed, the norm should now be: > register_raw_size() == register_virtual_size() == TYPE_LENGTH > (register_virtual_type()) (which makes them all badly named :-) This has nothing to do with the raw and virtual sizes being different, or the raw and virtual types being different. > Even more ruthless. Try a register layout of: > -- > raw normal r0..r15 > raw someothers > raw floats > raw bank r0..r15 > raw still more > -- > pseudo r0..r15 > mapped onto either normal or banked > pseudo floats > mapped onto floats > and so on, for instance, explict register names to identify normal and > banked r0. > -- > which completly separates the raw and pseudo registers. The function > register_name() becomes: > > if regnum < NUM_REGO > return ""; > else > return yourtable[regnum - NUM_REGS]; Hmm, not quite, I'm trying to bury the regcache even deeper than that... It simply does not exist to most of core-gdb, except by calling through arm_register_read(), which is the only function that knows how to map a regno onto its regcache entry. R. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 8:25 ` Richard Earnshaw @ 2002-05-12 8:41 ` Andrew Cagney 0 siblings, 0 replies; 30+ messages in thread From: Andrew Cagney @ 2002-05-12 8:41 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > However, in this situation, >> > pseudo_rengo("r0") != regcache_regno("r0"), yet we effectively have >> > >> > REGSITER_RAW_SIZE (pseudo_regno ("r0")) >> > and >> > REGISTER_RAW_SIZE (regcache_regno ("r0")) > >> >> Sorry, I still don't understand. > > > In my view of things, the domain of the result returned by pseudo_regno() > is > 0..Num_pseudos, Pseudo-registers occupy the space: [NUM_REGS .. NUM_REGS+NUM_PSEUDO_REGS) there isn't an overlap. As I said, I'd like to have strongly typed ``struct pseudoreg *'' and ``struct rawreg *''. In the mean time, this numeric separation is the onlything we have. > and the domain of regcache_regno() is > > 0..NUM_REGS > > But we have cases where the two functions return a different number for > the same register; more precisely, we might encounter the situation where > > pseudo_regno ("int_reg0") == regcache_regno ("float_reg5") That isn't correct. Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-12 8:07 ` Andrew Cagney 2002-05-12 8:25 ` Richard Earnshaw @ 2002-05-13 5:35 ` Richard Earnshaw 2002-05-13 6:13 ` Andrew Cagney 1 sibling, 1 reply; 30+ messages in thread From: Richard Earnshaw @ 2002-05-13 5:35 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > Even more ruthless. Try a register layout of: > > -- > raw normal r0..r15 > raw someothers > raw floats > raw bank r0..r15 > raw still more > -- > pseudo r0..r15 > mapped onto either normal or banked > pseudo floats > mapped onto floats > and so on, for instance, explict register names to identify normal and > banked r0. > -- > > which completly separates the raw and pseudo registers. The function > register_name() becomes: > > if regnum < NUM_REGS > return ""; > else > return yourtable[regnum - NUM_REGS]; OK, I'm trying this general approach. One major failure, unfortunately. The remote-sim code has: else if (REGISTER_NAME (regno) != NULL && *REGISTER_NAME (regno) != '\0') { char buf[MAX_REGISTER_RAW_SIZE]; int nr_bytes; if (REGISTER_SIM_REGNO (regno) >= 0) nr_bytes = sim_fetch_register (gdbsim_desc, REGISTER_SIM_REGNO (regno), buf, REGISTER_RAW_SIZE (regno)); ... supply_register (regno, buf); Which is precisely the opposite of what I want: sim_fetch_register needs to fetch the raw (uncooked) registers, which is precisely the set that don't have names :-( REGISTER_SIM_REGNO doesn't help, because we never get to the code for the registers I need. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-13 5:35 ` Richard Earnshaw @ 2002-05-13 6:13 ` Andrew Cagney 2002-05-13 6:18 ` Richard Earnshaw 0 siblings, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-13 6:13 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > > OK, I'm trying this general approach. One major failure, unfortunately. > > The remote-sim code has: > > else if (REGISTER_NAME (regno) != NULL > && *REGISTER_NAME (regno) != '\0') > { > char buf[MAX_REGISTER_RAW_SIZE]; > int nr_bytes; > if (REGISTER_SIM_REGNO (regno) >= 0) > nr_bytes = sim_fetch_register (gdbsim_desc, > REGISTER_SIM_REGNO (regno), > buf, REGISTER_RAW_SIZE (regno)); > ... > supply_register (regno, buf); > > Which is precisely the opposite of what I want: sim_fetch_register needs > to fetch the raw (uncooked) registers, which is precisely the set that > don't have names :-( > > REGISTER_SIM_REGNO doesn't help, because we never get to the code for the > registers I need. Want it fixed? Next to no targets define the macro so changing the the behavour - make REGISTER_SIM_REGNO totally responsible for the decision is straight forward. (In fact, why didn't I do this before). Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-13 6:13 ` Andrew Cagney @ 2002-05-13 6:18 ` Richard Earnshaw 0 siblings, 0 replies; 30+ messages in thread From: Richard Earnshaw @ 2002-05-13 6:18 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > > > > OK, I'm trying this general approach. One major failure, unfortunately. > > > > The remote-sim code has: > > > > else if (REGISTER_NAME (regno) != NULL > > && *REGISTER_NAME (regno) != '\0') > > { > > char buf[MAX_REGISTER_RAW_SIZE]; > > int nr_bytes; > > if (REGISTER_SIM_REGNO (regno) >= 0) > > nr_bytes = sim_fetch_register (gdbsim_desc, > > REGISTER_SIM_REGNO (regno), > > buf, REGISTER_RAW_SIZE (regno)); > > ... > > supply_register (regno, buf); > > > > Which is precisely the opposite of what I want: sim_fetch_register needs > > to fetch the raw (uncooked) registers, which is precisely the set that > > don't have names :-( > > > > REGISTER_SIM_REGNO doesn't help, because we never get to the code for the > > registers I need. > > Want it fixed? Next to no targets define the macro so changing the the > behavour - make REGISTER_SIM_REGNO totally responsible for the decision > is straight forward. > > (In fact, why didn't I do this before). Yeah! that would be great. R. ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 7:31 ARM and virtual/raw registers Richard Earnshaw 2002-05-09 9:45 ` Andrew Cagney @ 2002-05-09 10:08 ` Andrew Cagney 2002-05-09 10:36 ` Richard Earnshaw 1 sibling, 1 reply; 30+ messages in thread From: Andrew Cagney @ 2002-05-09 10:08 UTC (permalink / raw) To: Richard.Earnshaw; +Cc: gdb > Ok, so it's clear that the current ARM code for handling virtual and raw > registers is wrong... > > So the question is, what does it need to be? > > The answer is that I'm not quite sure, since there are a number of factors > involved here. > > 1) FPA registers are multi-precision -- that is, they are modal, holding > information about the type of result in the register at any particular > time. The extra information is used to enable correct support of type > conversions with signalling NaNs. [And I thought MIPS was bad :-)] So an FP register could contain a single, double, ... and each would be represented differently - single, for instance, would not be stored as a rounded double? I think the Alpha does this for int values - it has some really strange to/from register/int code. If this is the only problem, then the new REGISTER_TO_VALUE et.al. methods should address the problem. Those methods, do, however, assume that the format of a register spilt into memory is identical to the layout of the h/w register supplied by the OS / H/W / ... Hmm, ... > 2) The format of that information can depend on the hardware present, or, > if absent, on the emulator being used (different emulators handle this in > different ways). > 3) Some of the emulators use three words to hold the raw information, some > use four. RDP returns uses four words. > > 4) When a floating point value is stored in memory the format of that > memory may depend on the instruction used to store it. For example, the > sfmfd instruction used in a prologue sequence will store three words (as > would stfe), but there may be information in the unused bits that > indicates the type of the value in the register. The format of this > memory may, or may not, be the same as the three-word register information > mentioned in 3) above. So the way the ARM spills its FP registers into memory may not necessarily match the equivalent h/w register? Does the ARM always spill these registers in the same way (at least for a given ISA/ABI combination?) - if GDB is fetching a saved register from the stack, it knows what the format is. > 5) All of the above is poorly documented ;-( > > 6) Selecting the correct conversion routine may involve some inspired > guess-work :-) Andrew ^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: ARM and virtual/raw registers 2002-05-09 10:08 ` Andrew Cagney @ 2002-05-09 10:36 ` Richard Earnshaw 0 siblings, 0 replies; 30+ messages in thread From: Richard Earnshaw @ 2002-05-09 10:36 UTC (permalink / raw) To: Andrew Cagney; +Cc: Richard.Earnshaw, gdb > [And I thought MIPS was bad :-)] Welcome to the real world where hardware designers get in the way, and then software developers add extra things to save some time too... > > So an FP register could contain a single, double, ... and each would be > represented differently - single, for instance, would not be stored as a > rounded double? Well, either representation might be used, and I think there exist cases where both occur. For example, a SP value just loaded from memory might be left in SP format, with a tag indicating this, or it might be held in extended precision. The only time it gets really nasty is when it comes to signalling NaNs. IEEE requires an exception if a type conversion is performed on them (but not if the value is just copied/stored/sign-flipped), so the register must hold some meta-data on the value indicating the type held, so that we can fault if required. The reason for the SFM/LFM instructions is so that a subroutine can stack such values across subroutine calls without causing exceptions to occur. > If this is the only problem, then the new REGISTER_TO_VALUE et.al. > methods should address the problem. Partly, but it puts the conversion in the Arch space, but conversion is really dependent on the Target vector, not the ABI (or not just the ABI). > Those methods, do, however, assume that the format of a register spilt > into memory is identical to the layout of the h/w register supplied by > the OS / H/W / ... Hmm, ... We might be able to achieve this, with some magic, but the format in memory isn't guaranteed to be the same for all targets. That makes use of that format undesirable: I'd much prefer to be able to use a format that was common to all ARM targets and then have both registers and memory normalized to the internal format during back-trace analysis. > > 4) When a floating point value is stored in memory the format of that > > memory may depend on the instruction used to store it. For example, the > > sfmfd instruction used in a prologue sequence will store three words (as > > would stfe), but there may be information in the unused bits that > > indicates the type of the value in the register. The format of this > > memory may, or may not, be the same as the three-word register information > > mentioned in 3) above. > > So the way the ARM spills its FP registers into memory may not > necessarily match the equivalent h/w register? Correct, the documentation for the SFM instruction says that the format is internal to the CPU, and that the only way to recover the value is to use LFM to load it back again ;-) Of course, that's no good with a debugger, particularly a cross debugger. I don't think there is a problem with getting some documentation releases on the format that the FPA hardware uses, but I suspect that this won't necessarily match the behaviour of, say, the emulator used on ARM/Linux, since that was written without access to the details of the way the FPA does it. > > Does the ARM always spill these registers in the same way (at least for > a given ISA/ABI combination?) - if GDB is fetching a saved register from > the stack, it knows what the format is. Well, it should, but there's no absolute guarantee. In practice, some code may use SFM (storing in internal format), and other code might use STFE (store in extended format) and expect the Hardware/emulator to ignore faults when converting to/from extended precision. Although code using these methods *shouldn't* be intermixed, there's certainly no reason why multiple applications running on the same platform shouldn't use either one. I shan't bother you yet with details about how the VFP co-processor works ;-) R. ^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2002-05-13 13:18 UTC | newest] Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-05-09 7:31 ARM and virtual/raw registers Richard Earnshaw 2002-05-09 9:45 ` Andrew Cagney 2002-05-09 10:01 ` Richard Earnshaw 2002-05-09 11:52 ` Andrew Cagney 2002-05-10 3:45 ` Richard Earnshaw 2002-05-10 7:48 ` Andrew Cagney 2002-05-10 12:07 ` Andrew Cagney 2002-05-11 7:05 ` Richard Earnshaw 2002-05-11 14:52 ` Andrew Cagney 2002-05-12 7:20 ` Richard Earnshaw 2002-05-12 8:25 ` Andrew Cagney 2002-05-12 8:30 ` Richard Earnshaw 2002-05-12 8:51 ` Andrew Cagney 2002-05-10 9:29 ` Richard Earnshaw 2002-05-10 11:42 ` Andrew Cagney 2002-05-11 6:16 ` Richard Earnshaw 2002-05-11 11:41 ` Richard Earnshaw 2002-05-11 13:36 ` Andrew Cagney 2002-05-12 7:11 ` Richard Earnshaw 2002-05-12 7:40 ` Richard Earnshaw 2002-05-12 9:03 ` Andrew Cagney 2002-05-12 11:31 ` Andrew Cagney 2002-05-12 8:07 ` Andrew Cagney 2002-05-12 8:25 ` Richard Earnshaw 2002-05-12 8:41 ` Andrew Cagney 2002-05-13 5:35 ` Richard Earnshaw 2002-05-13 6:13 ` Andrew Cagney 2002-05-13 6:18 ` Richard Earnshaw 2002-05-09 10:08 ` Andrew Cagney 2002-05-09 10:36 ` Richard Earnshaw
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox