View previous topic :: View next topic |
Author |
Message |
poly_poly-man Advocate
Joined: 06 Dec 2006 Posts: 2477 Location: RIT, NY, US
|
Posted: Thu Aug 05, 2010 2:07 pm Post subject: [c] 32-bit cast works, 16 bit doesn't. |
|
|
In /usr/src/linux/fs/jffs2/scan.c, I'm hitting a very strange issue on this one particular hardware (wrt54g, seems to affect certain router models in the brcm47xx family - mipsel arch).
Code: | node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs]; |
That line is the culprit... and, to be complete: Code: | typedef struct {
__u32 v32;
} __attribute__((packed)) jint32_t;
typedef struct {
__u32 m;
} __attribute__((packed)) jmode_t;
typedef struct {
__u16 v16;
} __attribute__((packed)) jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
}
|
so, with the code as-is, totlen and hdr_crc get pulled correctly, but magic and nodetype do not. Example: if the first 32 bits from that offset are 0x20031985 (really 0x85, 0x19, 0x03, 0x20 because of le), it should be 0x1985 and 0x2003 respectively, but instead, it's 0x8585 and 0xffff...
Simply casting to a 16-bit pointer type, a la *(uint16_t *)&node[0], also shows the issue (same with talking about buf directly instead of node)... and casting to 32-bit then talking about & 0xffff does the same, because it's casting to 16-bits there too...
The weirdest part is that this problem hasn't caused noticable issues anywhere else yet - everything else works as expected... so even a simple workaround for this would be nice (I'd hate to try to think where the problem is hidden, but I'll explore that too)... any comments? _________________ iVBORw0KGgoAAAANSUhEUgAAA
avatar: new version of logo - see topic 838248. Potentially still a WiP. |
|
Back to top |
|
|
Hu Moderator
Joined: 06 Mar 2007 Posts: 21621
|
Posted: Fri Aug 06, 2010 2:43 am Post subject: |
|
|
What version of gcc are you using? Newer versions of gcc have gotten progressively more strict about type punning. You can usually get the compiler to do the right thing if you replace the type punned pointer with a union of the original type and the punned type. |
|
Back to top |
|
|
Akkara Bodhisattva
Joined: 28 Mar 2006 Posts: 6702 Location: &akkara
|
Posted: Fri Aug 06, 2010 3:48 am Post subject: |
|
|
What happens when you cast to char and printf %02X the first 4 bytes there?
Did you try different levels of optimization? Sometimes -O2 and -Os can be buggy, particularly with non-X86 architectures.
Also, did you try compiling that file using -O -S and seeing if the assembly output has any obvious errors? (Maybe try to make a small stand-alone program that exhibits this problem). |
|
Back to top |
|
|
xibo Apprentice
Joined: 21 Aug 2007 Posts: 152 Location: moving between kubuntu and ubuntu kde edition
|
Posted: Fri Aug 06, 2010 10:06 am Post subject: |
|
|
Code: |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include <assert.h>
typedef struct
{
__u32 v32;
} __attribute__((packed)) jint32_t;
typedef struct
{
__u32 m;
} __attribute__((packed)) jmode_t;
typedef struct
{
__u16 v16;
} __attribute__((packed)) jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
};
void *dump( __u16 const magic, __u16 const nodetype, __u32 const totlen, __u32 const hdr_crc )
{
struct jffs2_unknown_node instance = { {magic}, {nodetype}, {totlen}, {hdr_crc} };
size_t const length = sizeof(struct jffs2_unknown_node);
void *dump = malloc(length);
return memcpy( dump, &instance, length );
}
void print_struct_mem( struct jffs2_unknown_node const* ptr )
{
size_t i=0;
size_t const e = sizeof( struct jffs2_unknown_node );
char const *c = (char const *)ptr;
for( ; i!=e; ++i )
printf( "%02hhx ", c[i] );
printf( "\n" );
}
void print_struct_val( struct jffs2_unknown_node const* ptr )
{
printf( "magic=0x%04hx, nodetype=0x%04hx, nodetype=0x%08x, hdr_crc=0x%08x\n", ptr->magic.v16, ptr->nodetype.v16, ptr->totlen.v32, ptr->hdr_crc.v32 );
}
int main()
{
char *chunk1 = (char *)dump( 0x2003, 0x1985, 0x11223344, 0xffeeddcc );
char *chunk2 = (char *)dump( 0x2003, 0x1985, 0x11223344, 0xffeeddcc );
assert(chunk1 && chunk2);
struct jffs2_unknown_node *ptr1 = (struct jffs2_unknown_node *)chunk1;
struct jffs2_unknown_node *ptr2 = (struct jffs2_unknown_node *)chunk2;
ptr2->magic.v16 = htons( ptr2->magic.v16 );
ptr2->nodetype.v16 = htons( ptr2->nodetype.v16 );
ptr2->totlen.v32 = htonl( ptr2->totlen.v32 );
ptr2->hdr_crc.v32 = htonl( ptr2->hdr_crc.v32 );
print_struct_mem( ptr1 );
print_struct_mem( ptr2 );
print_struct_val( ptr1 );
print_struct_val( ptr2 );
free( ptr1 );
free( ptr2 );
return EXIT_SUCCESS;
}
|
Code: |
alonso@ip012 ~ $ cc test.c -O0 && ./a.out
03 20 85 19 44 33 22 11 cc dd ee ff
20 03 19 85 11 22 33 44 ff ee dd cc
magic=0x2003, nodetype=0x1985, nodetype=0x11223344, hdr_crc=0xffeeddcc
magic=0x0320, nodetype=0x8519, nodetype=0x44332211, hdr_crc=0xccddeeff
alonso@ip012 ~ $ cc test.c -O1 && ./a.out
03 20 85 19 44 33 22 11 cc dd ee ff
20 03 19 85 11 22 33 44 ff ee dd cc
magic=0x2003, nodetype=0x1985, nodetype=0x11223344, hdr_crc=0xffeeddcc
magic=0x0320, nodetype=0x8519, nodetype=0x44332211, hdr_crc=0xccddeeff
alonso@ip012 ~ $ cc test.c -O2 && ./a.out
03 20 85 19 44 33 22 11 cc dd ee ff
20 03 19 85 11 22 33 44 ff ee dd cc
magic=0x2003, nodetype=0x1985, nodetype=0x11223344, hdr_crc=0xffeeddcc
magic=0x0320, nodetype=0x8519, nodetype=0x44332211, hdr_crc=0xccddeeff
alonso@ip012 ~ $ cc test.c -O3 && ./a.out
03 20 85 19 44 33 22 11 cc dd ee ff
20 03 19 85 11 22 33 44 ff ee dd cc
magic=0x2003, nodetype=0x1985, nodetype=0x11223344, hdr_crc=0xffeeddcc
magic=0x0320, nodetype=0x8519, nodetype=0x44332211, hdr_crc=0xccddeeff
alonso@ip012 ~ $ cc test.c -Os && ./a.out
03 20 85 19 44 33 22 11 cc dd ee ff
20 03 19 85 11 22 33 44 ff ee dd cc
magic=0x2003, nodetype=0x1985, nodetype=0x11223344, hdr_crc=0xffeeddcc
magic=0x0320, nodetype=0x8519, nodetype=0x44332211, hdr_crc=0xccddeeff
|
gcc-4.5.1-vanilla, x86-64 here.
Are the 16 bit members initialized propperly ? ie. struct jffs2_unknown_node k = { {0x2003}, {0x1995}, ... } instead of k={ 0x2003, 0x1985, ... } |
|
Back to top |
|
|
username234 Guru
Joined: 09 May 2007 Posts: 332
|
Posted: Fri Aug 06, 2010 10:38 am Post subject: |
|
|
you say that "0x20031985" is an example and from the looks of it it's an arbitrary one. If it is, could you give an actual example? In this particular case, the value is very important when debugging. For example, had the value 0xffff8585 not ended with a '1', I would guess you're reading out a memory address instead of its contents. _________________ Creating usernames when you're
in a creative slump is a bad idea
because if you are when you do
then you end up with uninspiring
alphanumeric cocktails like the
one directly above. |
|
Back to top |
|
|
poly_poly-man Advocate
Joined: 06 Dec 2006 Posts: 2477 Location: RIT, NY, US
|
Posted: Fri Aug 06, 2010 3:11 pm Post subject: |
|
|
well, I can't test until next wednesday.. away on vacation.
This code has been working on many archs for a while. It seems to only not work on certain wrt54g's... especially version 1.1. I can't reproduce the problem in userspace, and I haven't tried other spots in kernel.
I have not tried reading as chars, but as 32 bit works as I said.
The first 32 bits of most erase blocks is indeed 85, 19, 03, 20 (in hex) - they all start with 0x1985 at least.
This code loops a couple of times, upping the offset by 4 at each potential erase block ( in case it shifted in memory)... every time through it gets double of the first byte for the magic (first 16 bits), and ffff for the nodetype...
well, thanks for the ideas, and I'll be happy to try them out when I getback. _________________ iVBORw0KGgoAAAANSUhEUgAAA
avatar: new version of logo - see topic 838248. Potentially still a WiP. |
|
Back to top |
|
|
poly_poly-man Advocate
Joined: 06 Dec 2006 Posts: 2477 Location: RIT, NY, US
|
Posted: Thu Aug 12, 2010 4:04 pm Post subject: |
|
|
so, the issue seems to be one with reading 16-bits at a time from the flash... buf points to the flash rom apparently, and that's where the main issue lies.
However instead of fixing it in flash (which a number of people are indeed working on), I thought I'd look further into just a workaround...
Code: | magnod = *(uint32_t *)&buf[ofs-buf_ofs];
node->magic.v16 = (uint16_t)(magnod & 0xffff);
node->nodetype.v16 = (uint16_t)((magnod & 0xffff0000)>>16); | where magnod is a uint32_t... nodetype gets set correctly, but magic is getting odd, seemingly unrelated values...
This printing code: Code: | printk(KERN_WARNING "JFFS2 node header: %04x, %04x, %08x, %08x\n", node->magic.v16, node->nodetype.v16, node->totlen.v32, node->hdr_crc.v32);
printk(KERN_WARNING "JFFS2 node: %08x\n", *(uint32_t *)node);
printk(KERN_WARNING "This isn't funny. %04x should equal %08x... are they?\n", node->magic.v16, magnod); |
reveals (and this is just a few entries):
Code: | This isn't funny. b0b0 should equal 20031985... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00150000: 0xb0b0 instead
JFFS2 node header: 0c0c, 00b0, e41eb0b1, ffffffff
JFFS2 node: 0000000c
This isn't funny. 0c0c should equal 00b000b0... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00150004: 0x0c0c instead
JFFS2 node header: b1b1, e41e, ffffffff, ffffffff
JFFS2 node: e41eb0b1
This isn't funny. b1b1 should equal e41eb0b1... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00150008: 0xb1b1 instead
JFFS2 node header: ffff, ffff, ffffffff, ffffffff
JFFS2 node: ffffffff
This isn't funny. ffff should equal ffffffff... are they?
JFFS2 node header: b0b0, 2003, 00b000b0, 00b000b0
JFFS2 node: 00b000b0
This isn't funny. b0b0 should equal 20031985... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00160000: 0xb0b0 instead
JFFS2 node header: 0c0c, 00b0, e41eb0b1, ffffffff
JFFS2 node: 0000000c
This isn't funny. 0c0c should equal 00b000b0... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00160004: 0x0c0c instead
JFFS2 node header: b1b1, e41e, ffffffff, ffffffff
JFFS2 node: e41eb0b1
This isn't funny. b1b1 should equal e41eb0b1... are they?
jffs2_scan_eraseblock(): Magic bitmask 0x1985 not found at 0x00160008: 0xb1b1 instead
JFFS2 node header: ffff, ffff, ffffffff, ffffffff
JFFS2 node: ffffffff
This isn't funny. ffff should equal ffffffff... are they? | The scan_eraseblock() message is from somewhere else in the function - pretty clear what it does.
Any ideas on this while I further investigate the situation with the flash? _________________ iVBORw0KGgoAAAANSUhEUgAAA
avatar: new version of logo - see topic 838248. Potentially still a WiP. |
|
Back to top |
|
|
Akkara Bodhisattva
Joined: 28 Mar 2006 Posts: 6702 Location: &akkara
|
Posted: Thu Aug 12, 2010 11:24 pm Post subject: |
|
|
Print them out reading byte by byte. That often works, even with broken devices. If that works, you can use code like the following to assemble your int16's: Code: | unsigned char const *bytep = ...your...address;
int x;
x = bytep[1] << 8;
x <<= 8;
x |= bytep[0]; |
if you want to read a signed value, replace the bytep[1] with ((signed char const *)bytep)[1]. If you're reading big-endian short ints, switch the '1' and the '0' index around.
Another issue that sometimes crops up on broken devices, is the 1st read works, but a 2nd one issued "too soon" after the 1st fails. And you can end up with a situation where the code seems to work when you've got printfs in it, but breaks when you remove them. |
|
Back to top |
|
|
poly_poly-man Advocate
Joined: 06 Dec 2006 Posts: 2477 Location: RIT, NY, US
|
Posted: Fri Aug 13, 2010 3:55 am Post subject: |
|
|
Akkara wrote: | Print them out reading byte by byte. That often works, even with broken devices. If that works, you can use code like the following to assemble your int16's: Code: | unsigned char const *bytep = ...your...address;
int x;
x = bytep[1] << 8;
x <<= 8;
x |= bytep[0]; |
if you want to read a signed value, replace the bytep[1] with ((signed char const *)bytep)[1]. If you're reading big-endian short ints, switch the '1' and the '0' index around.
Another issue that sometimes crops up on broken devices, is the 1st read works, but a 2nd one issued "too soon" after the 1st fails. And you can end up with a situation where the code seems to work when you've got printfs in it, but breaks when you remove them. | I tried reading by byte, it seems to have the same issue as with 16-bit reads - doubled first byte, etc. I will try throwing some delay in between to see if that helps. _________________ iVBORw0KGgoAAAANSUhEUgAAA
avatar: new version of logo - see topic 838248. Potentially still a WiP. |
|
Back to top |
|
|
poly_poly-man Advocate
Joined: 06 Dec 2006 Posts: 2477 Location: RIT, NY, US
|
Posted: Fri Aug 13, 2010 5:29 pm Post subject: |
|
|
Akkara wrote: | Code: | unsigned char const *bytep = ...your...address;
int x;
x = bytep[1] << 8;
x <<= 8;
x |= bytep[0]; |
| I assume you meant to only << 8 once? doesn't work - reads 8585. _________________ iVBORw0KGgoAAAANSUhEUgAAA
avatar: new version of logo - see topic 838248. Potentially still a WiP. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|