Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
[c] 32-bit cast works, 16 bit doesn't.
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Portage & Programming
View previous topic :: View next topic  
Author Message
poly_poly-man
Advocate
Advocate


Joined: 06 Dec 2006
Posts: 2477
Location: RIT, NY, US

PostPosted: Thu Aug 05, 2010 2:07 pm    Post subject: [c] 32-bit cast works, 16 bit doesn't. Reply with quote

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
View user's profile Send private message
Hu
Moderator
Moderator


Joined: 06 Mar 2007
Posts: 21621

PostPosted: Fri Aug 06, 2010 2:43 am    Post subject: Reply with quote

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
View user's profile Send private message
Akkara
Bodhisattva
Bodhisattva


Joined: 28 Mar 2006
Posts: 6702
Location: &akkara

PostPosted: Fri Aug 06, 2010 3:48 am    Post subject: Reply with quote

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
View user's profile Send private message
xibo
Apprentice
Apprentice


Joined: 21 Aug 2007
Posts: 152
Location: moving between kubuntu and ubuntu kde edition

PostPosted: Fri Aug 06, 2010 10:06 am    Post subject: Reply with quote

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
View user's profile Send private message
username234
Guru
Guru


Joined: 09 May 2007
Posts: 332

PostPosted: Fri Aug 06, 2010 10:38 am    Post subject: Reply with quote

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
View user's profile Send private message
poly_poly-man
Advocate
Advocate


Joined: 06 Dec 2006
Posts: 2477
Location: RIT, NY, US

PostPosted: Fri Aug 06, 2010 3:11 pm    Post subject: Reply with quote

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
View user's profile Send private message
poly_poly-man
Advocate
Advocate


Joined: 06 Dec 2006
Posts: 2477
Location: RIT, NY, US

PostPosted: Thu Aug 12, 2010 4:04 pm    Post subject: Reply with quote

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
View user's profile Send private message
Akkara
Bodhisattva
Bodhisattva


Joined: 28 Mar 2006
Posts: 6702
Location: &akkara

PostPosted: Thu Aug 12, 2010 11:24 pm    Post subject: Reply with quote

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
View user's profile Send private message
poly_poly-man
Advocate
Advocate


Joined: 06 Dec 2006
Posts: 2477
Location: RIT, NY, US

PostPosted: Fri Aug 13, 2010 3:55 am    Post subject: Reply with quote

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
View user's profile Send private message
poly_poly-man
Advocate
Advocate


Joined: 06 Dec 2006
Posts: 2477
Location: RIT, NY, US

PostPosted: Fri Aug 13, 2010 5:29 pm    Post subject: Reply with quote

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
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Portage & Programming All times are GMT
Page 1 of 1

 
Jump to:  
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