Without something like java.lang.Reflection, being able to serialize everything and anything is a pipe dream. There are three groupings of objects available in salesforce.com: things you can serialize, things you can't serialize but have a "legal" representation of how you could interpret them with your own code, and things you can't serialize and contain only data that would be useless outside the current context.
The first category are the normal things you'd expect: lists, maps, and objects (classes) that don't contain a forbidden item, and basic primitives. The second category contains some obvious and some not-so-obvious entries: Messaging.Email, Enum, JSONParser, and so on. The final category are things like System.SavePoint, which obviously has no meaning outside of the current execution context.
For the first category, just use JSON.serialize, and for the second category, choose only the types you really care about, and make some sort of lengthy if-else block somewhere, and ignore everything else, and for the last category, ignore them completely. Something like this:
try {
System.debug(JSON.serialize(<target>);
catch(Exception e) {
if(<target> instanceof Enum) {
System.debug(<target>.name());
} else if(<target> instanceof Exception) {
System.debug(<target>.getMessage());
} // etc...
}