Thursday May 18, 2006

My last day at Sun

Today is my last day at Sun. After 7 years of learning, coding, making friends and having fun, I've finally decided to move on to a new job. I don't know what will happen to this blog, so I've created a new one at Hopefully, this posting will be alive long enough for people to know what happened...

Thursday Sep 22, 2005

Have you ever seen US-IV+ ? (Picture)

Sun just announced new UltraSPARC-IV+ chip based systems, and this is how the new chip looks like:

Thursday Jun 09, 2005

Ever heard of sound ISOLATING earphones ?

For last few weeks since I got my iPod Shuffle, I've been using this earphone to listen to my collection of music while in the office. There's a reason why it's called sound isolating - I don't hear almost any sound when I'm plugged.

I don't hear my phone ringing unless I turn the ring volume all the way up. I don't hear my roommate talking on the phone (he doesn't exactly whisper when he's on the phone). I don't hear someone asking me for lunch. I don't hear my manager opening my room door (I sit facing away from the door), walking across my back and sitting down on my side. I have no idea he's there until he taps me on the shoulder. Ooops.

This earphone works...and works too well to use it in the office. So I ended up switching back to less satisfying earbuds bundled with iPod. If you're working in noisy environment (maybe in some cubicle full of noisy coworkers or rack full of servers), sound isolating earphones might be a great help. Of course, it reproduces music \*much\* better than others.

PS. I'd love to get this one if I have some spare cash to burn. Although mine sounds much better than most other earbuds, I know it still lacks precise high to mid-high frequency response (I'm not much of a bass person and the bass of E2c is enough for me). And like most other earphones, the sound field feels "closed". Maybe I should get one of these.

Friday Jun 03, 2005

How Apple can move to Intel

CNet reported that Apple is going to switch to Intel for its CPU supplier. Some people thinks that this means Intel will produce PowerPC compatible processor, but I strongly doubt it. Some other people thinks that this would involve mostly emulation of PowerPC on x86. However, I have slightly different take on this - I think Apple is going to use FAT binary to smooth the transition.

NeXTSTEP used to support FAT binary for four architectures - Motorola 68k, Intel x86, HP PA and Sun SPARC (NIHS). And it worked pretty well. Gcc compiler for NeXTSTEP had an option to produce objects for all four targets at the same time, and linker and runtime loader all supported this very well. A single executable file can contain object codes for four different architectures, and many applications were distributed for all four (NIHS), or at least for 68k and x86 (NI).

Assuming Apple didn't remove FAT support in MacOS X, it would be fairly easy for Apple to provide developers ways to create executables for both targets (a simple recompilation for both target would work for most applications, just like moving applications from Solaris SPARC to Solaris x86) and the ISVs can distribute one software package that supports both platforms.

Of course, Apple may still need to provide a PowerPC emulation for x86. But that shouldn't be too difficult either, since underlying OS and APIs remain the same. But emulation doesn't address the actual transition of ISV code itself, and it alone doesn't really ease the transition for ISVs like FAT binary does. So all in all, I bet Apple will revive FAT binary in OS X. Maybe it's time for Sun to push SPARC support in OS X...after all, Niagara and ROCK will be quite attractive as a CPU for Xserve :)

Monday Sep 27, 2004

My another $.01 on Eric and Greg's debate.

From Greg's another reply :
    I really need to write a article/essay about why Linux does
    not have driver api stability. I touched on it in my
    previous post, but in reading your response, and the
    responses by others, you all seem to miss the main points.
    It's not that we don't know how to create a binary api with
    padding structures out, and offering up new functions, it's
    the fact that because we have the source to all of our
    drivers, we do not have to.
So now he changed his mind and admits that it's possible to have a driver api stability (see my previous blog entry). Fine. At least this time it looks a bit more reasonable on the face.

Let me counter this argument by quoting one open source driver developer. Following is from a posting on comp.unix.solaris by Joerg Schilling (In case you don't know, he's the author of libscg, the SCSI generic driver which is used by many cd recording software).
From: (Joerg Schilling) Newsgroups:
comp.unix.solaris Subject: Re: Anyone else seeing this management
trend favoring Linux?

There are other reasons why Linux & Linux are wrong:

Linux folks likes to force me to use /dev/hdc in order to send SCSI
commands to the first CD-ROM.

Well inside cdrecord all SCSI commands are routed though the highly
portable libscg (which started in August 1986 so it is 6 years older
than Linux but it is still binary compatible to the August 1986
version if you use SunOS on a 68020).

Libscg offers services that are just above the SCSI transport level
in the OS while /dev/hdc is a device node of a block device. Why
should I be forced to use a interface that is far too high in
layering and thus uses inapropriate names at /dev/\* when Linux
already has a SCSI generic driver system that offers services at the
right layering level and allows (in contrary to /dev/hdc) to map
/dev/sg\* entries to SCSI bus,target,lun?

The reason is that the linux kernel is completely non-orthogonal and
offers many superfluous services. It is possible to send SCSI
commands to ATAPI drives by using /dev/sg\* fd's but with /dev/sg\* and
ATAPI there is no DMA if the transfer length is not a multiple of

---> Linux has no DMA abstraction layer as Solaris. If it had, then
everything would work the same. But the useless /dev/hd\* SCSI
transport for ATAPI which has been introduced by Linus Torvalds only
in order to annouy users of CD/DVD writer did not have correct DMA in
the beginning too. Later after I made a bug report, the bug in
/dev/hd\* has been fixed but as a fact of pure evilness, the _same_
bug has not been removed from the /dev/sg\* interface.

>Then it struck me that the Linux disk driving naming convention (i.e.
>hda, hdb, hdc, etc.) offers a clue on why Solaris had no problem with
>three controllers and why Linux choked. With 3 SCSI controllers, you
>could put a whole scheissload of disks on the system, but how in the
>heck are you going to label them with the /dev/hdx convention? This is
>especially true if the 3 SCSI strings are only partly filled initially
>and more disks are added later on.

This problem has tradition on Linux and is _very_ probable with the /dev/sg\*
(Generic SCSI transport) interface. Many people had external CD writers that
have been switched off some time. If you boot with the CD drive switched off,
the /dev/sg\* interface that yesterday has been pointing to the CD writer now
may become the second HDD.....

Let me give a final and frustrated comclusion:

From various mail exchanged I had with many "prominent" Linux kernel people
(including Linus Torvalds and Alan Cox) it seems that the main reason why
Linux constantly breaks interfaces is not because the Linux kernel folks
are trying to do the best without a compromise but rather because they
did not yet understand what an interface is :-(

-- (home) Jörg Schilling D-13353 Berlin                (uni)  If you don't have iso-8859-1     (work) chars I am J"org Schilling
Enough said.

It's not a simple matter of binary interface. It's a matter of "stable" interface and proper abstraction layer. That doesn't change regardless of the availability of the driver source code.

Friday Sep 24, 2004

Solaris vs Linux debate between Eric Schrock and Greg K-H

Wow. There's an interesting debate going on between our Eric Schrock and Greg K-H on different philosophies of Solaris and Linux.

Eric Schrock's first post:

And Greg K-H's rebuttal:

Then Eric's rebuttal of the rebuttal:

Eric's last post is very good, so I don't have much to add except for one thing. From Greg's rebuttal:
 Here's why the Linux kernel does not have binary driver
 compatibility, and why it never will:

    \* compiler versions and kernel options. If you
    select something as simple as CONFIG_SMP, that means that core
    kernel structures will be different sizes, and locks will either
    be enabled, or compiled away into nothing. So, if you wanted to
    ship a binary driver, you would have to build your driver for
    that option enabled, and disabled. Now combine that with the
    zillion different kernel options that are around that change the
    way structures are sized and built, and you have a huge number of
    binary drivers that you need to ship. Combine that with the
    different versions of gcc which align things differently (and
    turn on some kernel options themselves, based on different
    features available in the compiler) and there's no way you can
    successfully ship a binary kernel driver that will work for all
    users. It's just an impossible dream of people who do not
    understand the technology.
There you have it. A binary driver compatibility is "an impossible dream of people who do not understand the technology". Yikes. So all those commercial unix vendors (or even Microsoft) who provide the binary compatible driver are idiots who do not understand the technology.
Also, as a compiler writer, it's mystifying, to say the least, that he blames compiler versions for structure size or alignment changes. If you have a proper application binary interface which defines the structure layout, no matter what compiler you use, they won't change. If they do, then the compiler has just broken the ABI. If I didn't know better, I would have thought gcc doesn't even provide a proper and stable ABI that it adheres to - it does. So don't blame it on gcc - linux's binary driver (non-)compatiblity issue has nothing to do with gcc.

Monday Sep 13, 2004

Dbx tip of the day - tracing malloc/free or new/delete

On comp.unix.solaris, someone asked: 
   I want to set a breakpoint such that it will stop when some
   specific heap address, say, 0x12345678, is allocated or freed. Is there
   any way to do this?
After I replied an answer, someone else asked me how to do similar for new/delete in C++. It isn't too difficult to do, but it involves optimized code (malloc and free in libc are optimized), so it may not be obvious to someone who's not familiar with SPARC assembly or calling convention.

Enough intro. Here's my answers:

One possible solution is to set the breakpoint
at just before returning from malloc, and right after free is called.

Following is an example:

$ cat t.c

int main(void) {
    void \* p = malloc(100);

    printf("%x\\n", p);

    return 0;
$ cc -g t.c
$ dbx ./a.out
Reading a.out
(dbx 1) stop in main
(2) stop in main
(dbx 2) run
Running: a.out
(process id 14122)
stopped in main at line 5 in file "t.c"
    5       void \* p = malloc(100);
(dbx 3) dis malloc
0x7fac1cb8: malloc       :      save     %sp, -96, %sp
0x7fac1cbc: malloc+0x0004:      call     malloc+0xc     ! 0x7fac1cc4
0x7fac1cc0: malloc+0x0008:      sethi    %hi(0x7a000), %o1
0x7fac1cc4: malloc+0x000c:      inc      844, %o1
0x7fac1cc8: malloc+0x0010:      add      %o1, %o7, %o3
0x7fac1ccc: malloc+0x0014:      ld       [%o3 + 3788], %l0
0x7fac1cd0: malloc+0x0018:      call     _PROCEDURE_LINKAGE_TABLE_+0x3c
0x7fac1cd4: malloc+0x001c:      mov      %l0, %o0
0x7fac1cd8: malloc+0x0020:      call     _malloc_unlocked       ! 0x7fac1cf4
0x7fac1cdc: malloc+0x0024:      mov      %i0, %o0
(dbx 4) dis
0x7fac1ce0: malloc+0x0028:      mov      %o0, %i0
0x7fac1ce4: malloc+0x002c:      call     _PROCEDURE_LINKAGE_TABLE_+0x48
0x7fac1ce8: malloc+0x0030:      mov      %l0, %o0
0x7fac1cec: malloc+0x0034:      ret
0x7fac1cf0: malloc+0x0038:      restore
0x7fac1cf4: _malloc_unlocked       :    save     %sp, -96, %sp
0x7fac1cf8: _malloc_unlocked+0x0004:    sethi    %hi(0xffffdc00), %o0
0x7fac1cfc: _malloc_unlocked+0x0008:    call     _malloc_unlocked+0x10
0x7fac1d00: _malloc_unlocked+0x000c:    sethi    %hi(0x7a000), %o1
0x7fac1d04: _malloc_unlocked+0x0010:    inc      999, %o0
(dbx 5) stopi at 0x7fac1cec -if $i0 == 0x20e38
(3) stopi at &malloc+0x34 -if $i0 == 0x20e38
(dbx 6) stop in free -if $o0 == 0x20e38
dbx: warning: 'free' has no debugger info -- will trigger on first instruction
(4) stop in free -if $o0 == 0x20e38
(dbx 7) cont
stopped in malloc at 0x7fac1cec
0x7fac1cec: malloc+0x0034:      ret
(dbx 8) up
Current function is main
    5       void \* p = malloc(100);
(dbx 9) cont
stopped in free at 0x7fac2b4c
0x7fac2b4c: free       :        save     %sp, -96, %sp
Current function is main
    9       free(p);
(dbx 10) cont

execution completed, exit code is 0
(dbx 11)

The first stopi point is at the "ret" instruction of malloc,
and stops only when $i0 (the return value, %i0 in disassembly)
is the value you want (in this case, 0x20e38).
The second stop point is at the first instruction of free (stop in free)
and only if $o0 (the first parameter) is the value you want.
(dbx 8) promt caught malloc() from returning 0x20e38,
and (dbx 10) caught free() being passed 0x20e38.

Depending on what you want to do, apptrace might be useful also.
with the same a.out:

$ apptrace ./a.out
apptrace: unexpected version: 3
a.out    -> = 0x7fbaeaa8) = 0x0
a.out    -> = 0x10c98) = 0x0
a.out    -> = 0x64) = 0x20e38
a.out    ->
format = 0x10cb0, ...) = 6
a.out    -> = 0x20e38)
a.out    -> = 0)

And of course, Dtrace in Solaris 10 can do what apptrace can do (and more).

Another useful tool is dbx's rtc checking (if that's what you're trying to do).
Just do:

(dbx 1) check -access

And it will do bunch of different runtime error checkings for memory allocation.
Type "help check" on dbx command line to see more detail.

> Can I do similar things to new and delete?

New and delete calls malloc and free.
So you'll see some additional calls on top of malloc and free
but it's basically the same:

$ cat t.c
int main(void) {
    int \* p = new int;
    \*p = 10;
    delete p;
    return 0;
$ CC -g t.c
$ dbx ./a.out
Reading a.out
(dbx 1) si main
(2) stop in main
(dbx 2) r
Running: a.out
(process id 16911)
stopped in main at line 2 in file "t.c"
    2       int \* p = new int;
(dbx 3) si malloc
dbx: warning: 'malloc' has no debugger info -- will trigger on first instruction
(3) stop in malloc
(dbx 4) c
stopped in malloc at 0x7f8c1cb8
0x7f8c1cb8: malloc       :      save     %sp, -96, %sp
Current function is main
    2       int \* p = new int;
(dbx 5) where
  [1] malloc(0x4, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7f8c1cb8
  [2] operator new(0x4, 0x7f93c008, 0x13988, 0xb00, 0x7f9eae3c, 0x4), at 0x7f9d74d8
=>[3] main(), line 2 in "t.c"
(dbx 6) si free
More than one identifier 'free'.
Select one of the following:
 0) Cancel
 1) ``free
 2) ``#__1cDstdIvalarray4Cl_Efree6M_v_      [non -g, demangles to:
 3) ``#__1cDstdIvalarray4Ci_Efree6M_v_      [non -g, demangles to:
 4) ``#__1cDstdIvalarray4CL_Efree6M_v_      [non -g, demangles to:
 std::valarray::free()] 5)
 ``#__1cDstdIvalarray4CI_Efree6M_v_      [non -g, demangles to:
 a) All
> 1
dbx: warning: 'free' has no debugger info -- will trigger on first instruction
(4) stop in free
(dbx 8) cont
stopped in free at 0x7f8c2b4c
0x7f8c2b4c: free       :        save     %sp, -96, %sp
Current function is main
    4       delete p;
(dbx 9) where
  [1] free(0x28620, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7f8c2b4c
  [2] operator delete(0x28620, 0x7f93c008, 0x13988, 0xb00, 0x7f9eae3c, 0x4), at
=>[3] main(), line 4 in "t.c"
(dbx 10)

Or an alternative is to set a breakint
at constructor/destructor that you want to track:

(dbx) stop in YourClass::YourClass -if this == ...pointer value...
(dbx) stop in YourClass::~YourClass

$ cat t.c
class myclass {
   myclass(void) { printf("I'm here.\\n"); };
   ~myclass(void) { printf("I'm gone.\\n"); };
int main(void) {
   myclass \*p = new myclass();

   delete p;
   return 0;
$ CC -g t.c
$ dbx ./a.out
Reading a.out
(dbx 1) si myclass::myclass
(2) stop in myclass::myclass()
(dbx 2) si myclass::~myclass
(3) stop in myclass::~myclass()
(dbx 3) r
Running: a.out
(process id 16929)
stopped in myclass::myclass at line 4 in file "t.c"
    4      myclass(void) { printf("I'm here.\\n"); };
(dbx 4) w
=>[1] myclass::myclass(this = 0x28838), line 4 in "t.c"
  [2] main(), line 8 in "t.c"
(dbx 5) c
I'm here.
stopped in myclass::~myclass at line 5 in file "t.c"
    5      ~myclass(void) { printf("I'm gone.\\n"); };
(dbx 6) w
=>[1] myclass::~myclass(this = 0x28838), line 5 in "t.c"
  [2] main(), line 10 in "t.c"
(dbx 7) stop in myclass::myclass -if this == 0x28838
(4) stop in myclass::myclass() -if this == 0x28838
(dbx 8) stop in myclass::~myclass -if this == 0x28838
(5) stop in myclass::~myclass() -if this == 0x28838
(dbx 9) status
 (2) stop in myclass::myclass()
\*(3) stop in myclass::~myclass()
 (4) stop in myclass::myclass() -if this == 0x28838
 (5) stop in myclass::~myclass() -if this == 0x28838
(dbx 10) handler -disable 2 3
(dbx 11) run
Running: a.out
(process id 16930)
stopped in myclass::myclass at line 4 in file "t.c"
    4      myclass(void) { printf("I'm here.\\n"); };
(dbx 12) where
=>[1] myclass::myclass(this = 0x28838), line 4 in "t.c"
  [2] main(), line 8 in "t.c"
(dbx 13) c
I'm here.
stopped in myclass::~myclass at line 5 in file "t.c"
    5      ~myclass(void) { printf("I'm gone.\\n"); };
(dbx 14) where
=>[1] myclass::~myclass(this = 0x28838), line 5 in "t.c"
  [2] main(), line 10 in "t.c"
(dbx 15)


Looks like I learn new things whenever I blog something - our dbx guy told me about this dbx feature "stop returns" which effectively sets a breakpoint at all places that call the function (in reality, it will wait till the function is called and set a breapoint at the return address).

Anyway, if you use "stop returns" then $o0 will have the return address of malloc since the brekapoint will be at the call site, whereas in the above example, I set the breapoint at the return instruction so the return value is in $i0.

Wednesday Sep 08, 2004

SunRay and voting machine.

I carpool with my coworker, and having two software geeks in a car for 30 minutes often lead to interesting discussions. This morning's topic was Diebold and voting machine (if "Diebold" and "voting" don't ring any bell, check 
this or  this out).

Anyway, we were talking mostly about how we can design a voting system that will be safe, secure and fail-proof. And my coworker suggested using a SunRay based system, but he wasn't sure installing a sunray server in every voting station is a very good idea. I told him about our wonderful SunRay over WAN, and it was clear to both of us that SunRay over WAN would be a perfect platform for voting (that is, if SunRay supports a touch screen).

The benefits are countless. It's secure, rugged, reliable and cost effective. Setting up a voting station will be very easy and will not require any skilled technician - just connect power cables and network ports. Moreover, the SunRay itself can be reused for its original purpose after the voting - a good cost saving. The total vote count would be instant - heck, a real-time vote count would be possible (although it would be debatable whether to allow it or not). Power failure in the voting station won't affect the voting data - although it could prevent people from voting in that particular voting station. Security won't be a concern - since the sunray server doesn't need to talk to anyone but SunRays, and the data will be kept in the server. WanRay uses VPN to secure the connection, and I believe SunRay has its own encryption again over VPN, so it's quite secure.

With various security and management features in Solaris 10, I can easily imagine using thousands of SunRays and a couple of SunRay servers as a secure and cost effective voting system - after all, our Trusted Solaris and SunRay are used for highly sensitive and secure environment, so why not use the same technology for voting ?

Thursday Aug 12, 2004

Talk about backward compatibility...

On the newsgroup comp.unix.solaris, I've encountered the following posting:

>MANY applications from the SunOS 4.x days will still work,
>without recompilation, on Solaris 10.

WordPerfect 5.1 for SunOS worked on my SunBlade 150 with Solaris 9. 
Took a while to eat all those floppies though.
...and here SunOS refers to SunOS 4.x (since Solaris 2 is SunOS 5.x + etc).

When I sit down and thought about this, it wasn't too surprising but it still was amazing that our Solaris folks can keep the backward compatibility for over 10 year and across the major OS version upgrade - after all, 4.x to 5.x jump was a really big change.

BTW, if you're not familiar with SunOS 4.x, you may want to check this link for which SunOS version was when and which SunOS is which Solaris, etc.

Kudos to our Solaris folks !

Friday Jul 30, 2004

Debugging your shared library with LD_PRELOAD

This morning, I've replied to one posting  on comp.unix.solaris about dbx and LD_PRELOAD (google groups doesn't seem to have my replies yet).
It reminded me of my experience with dbx and LD_PRELOAD 
which I'd like to share.

I needed to debug and test my shared library. LD_PRELOAD seemed to be the easiest way to do so (if you don't know what LD_PRELOAD is, you may want to take a look at manpage or the wonderful Linker and Libraries Guide).

Without much thinking, I did the following:
$ library...
$ dbx program...
And I immediately got the linker error: ....: fatal: ... wrong ELF class: ELFCLASS32
Dang. The real dbx is 64bit on SPARC but my library is 32bit. Obviously a 32bit library and a 64bit executable don't mix together very well.

So I tried the following:
$ dbx program...
(dbx) library...
(dbx) export LD_PRELOAD
(dbx) run
and it worked fine, or so it seemed. Dbx loads all libraries that the executable depends on in advance (if you have used dbx, you'll remember seeing those "Reading" lines when dbx reads your program). But LD_PRELOAD'ed library is loaded when the program is executed, not in advance. That means dbx loaded both the original shared library and my shared library in LD_PRELOAD.

This didn't affect the execution of my program, but it affected which symbol dbx sees. Since both original and my own shared libraries are loaded, whenever I wanted to inspect a symbol in the library, dbx saw two different copies. Sometimes it asked me for which version to really use (like when setting breakpoints or calling functions), but sometimes it just used the original (like when printing global variables). This was confusing, and so I cried help to the dbx guy and he taught me the following solution:
(dbx) loadobject -list
(dbx) loadobject -unload ...the original library...
which unloaded the unnecessary original library and the problem was solved.

Well, technically the above was the ideal way. But I'm lazy and didn't want to do "loadobject" thing everytime I start my dbx. And so I ended up doing the following:
$ library... dbx
which is sort of a work-around. This wouldn't have worked if my library were 64bit and interfered with dbx in some ways. I guess this is one of those cases where you prefer a little work around than a proper solution.

Tuesday Jul 27, 2004

Hidden benefits of the register window...

When SPARC ISA was first designed, the register window feature made sense given the first implementation characteristics such as unified cache and relatively shallow call depth. But as John Mashey pointed out in his posting here, it doesn't look like such a great idea nowadays.

But there's some unexpected benefit of the register window that are not well known.

The register window makes the call stack trace explicit, straightfoward and transparent, thus makes it fairly simple to do a stack unwind and do some tricks in the exception handling code. This contrasts to some other architectures where it isn't very simple to do a stack unwind due to potentially missing frame pointer, or difficulty of recovering the callee save registers.

Another hidden benefit is the simpler register allocation in the compiler. The register window effectively leaves no caller save registers, thus the compiler has less things to worry about. Also there's less need for interprocedural register allocation or link time register allocation.

Because of the register window and non-executable stack, it is quite a bit more difficult to exploit the buffer overflow vulnerability on SPARC, although it doesn't make exploiting impossible.




« July 2016