SmbiosItem.cpp

Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  * vim:expandtab:autoindent:tabstop=4:shiftwidth=4:filetype=c:cindent:textwidth=0:
00003  *
00004  * Copyright (C) 2005 Dell Inc.
00005  *  by Michael Brown <Michael_E_Brown@dell.com>
00006  * Licensed under the Open Software License version 2.1
00007  *
00008  * Alternatively, you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published
00010  * by the Free Software Foundation; either version 2 of the License,
00011  * or (at your option) any later version.
00012 
00013  * This program is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  */
00018 
00019 // compat header should always be first header if including system headers
00020 #define LIBSMBIOS_SOURCE
00021 #include "smbios/compat.h"
00022 
00023 #include <iomanip>
00024 
00025 #include "SmbiosImpl.h"
00026 // message.h should be included last.
00027 #include "smbios/message.h"
00028 
00029 using namespace smbiosLowlevel;
00030 using namespace std;
00031 
00032 #define NOT_IMPLEMENTED { throw NotImplementedImpl(); }
00033 
00034 namespace smbios
00035 {
00036     ISmbiosItem::~ISmbiosItem()
00037     {}
00038 
00039     ISmbiosItem::ISmbiosItem()
00040     {}
00041 
00042     //
00043     // COPY CONSTRUCTOR
00044     //
00045     SmbiosItem::SmbiosItem (const SmbiosItem & source)
00046             : ISmbiosItem(), header (source.header), header_size(source.header_size)
00047     {
00048         // only one allocation here. If it fails, there is
00049         // nothing to rollback, so we are exception safe.
00050         // if we add another allocation, we need to restructure this.
00051         u8 *newSmbiosItem = new u8[ header_size ];
00052         memcpy (newSmbiosItem, source.header, header_size);
00053         header = reinterpret_cast<const smbios_structure_header *>(newSmbiosItem);
00054     }
00055 
00056     //
00057     // REGULAR CONSTRUCTOR
00058     //
00059     SmbiosItem::SmbiosItem (const smbios_structure_header *init_header)
00060             : ISmbiosItem(), header(init_header), header_size(0)
00061     {
00062         // we need to copy all of our data out of the SmbiosTable
00063         // so that we have our own copy. This effectively lets
00064         // smbiosItem have a separate lifetime from it's containing
00065         // table.
00066         //
00067         // we do all of the stuff below, up to the "new", to figure
00068         // out the size of the item.
00069 
00070         // hop over to the next struct using smbios parsing rules
00071         // see smbiostable code for more details
00072         const u8 *nextStruct = reinterpret_cast<const u8 *>(header)  + header->length ;
00073 
00074         // skip over the strings in the string table. It ends with a double null
00075         while (*nextStruct || nextStruct[1])
00076             nextStruct++;
00077 
00078         // skip over the actual double null
00079         nextStruct += 2;
00080 
00081         // now we are at the next struct, we know the size
00082         // of the struct we are supposed to be pointing at.
00083         header_size = nextStruct - reinterpret_cast<const u8 *>(header);
00084 
00085         // only one allocation here. If it fails, there is
00086         // nothing to rollback, so we are safe.
00087         // if we add another allocation, we need to restructure this.
00088         u8 *newSmbiosItem = new u8[header_size];
00089         memcpy (newSmbiosItem, header, header_size);
00090         header = reinterpret_cast<const smbios_structure_header *>(newSmbiosItem);
00091     }
00092 
00093     SmbiosItem::~SmbiosItem ()
00094     {
00095         // its ugly because microsoft vc++ 6 sucks so much.
00096         delete [] const_cast<u8 *>(reinterpret_cast<const u8 *>(header));
00097         header = 0;
00098     }
00099 
00100     // gcc workaround. overprotective git. #!#$J@*(&$%
00101     // This is only used to format informational output stuff.
00102     // it loses precision, so don't do it except for display
00103     static u32 force_u64_to_u32(u64 orig)
00104     {
00105         // only gives correct results for little endian (I think)
00106         // but shouldn't matter, as it is for information purposes only.
00107         u32 *temp32 = reinterpret_cast<u32 *>(&orig);
00108         return *temp32;
00109     }
00110 
00111     // Lifetime of returned char* is the same as the SmbiosItem
00112     // FIXME: This function needs to make sure it doesn't run past the end of the table for
00113     // malformed strings.
00114     //
00115     // Invariant: will always return a valid const char * or throw an exception
00116     const char *SmbiosItem::getStringByStringNumber (u8 which) const
00117     {
00118         const char *string_pointer = reinterpret_cast<const char *>(header);
00119 
00120         //  either user is an idiot and should go read the spec,
00121         //  _or_ there is a '\0' in the table, indicating
00122         //  the string does not exist. :-(
00123         //  In either case, we throw an exception.
00124         if (!which)     //strings are numbered beginning with 1
00125         {
00126             throw StringUnavailableImpl(_("String does not exist."));
00127         }
00128 
00129         // don't deref header if it isn't valid
00130         // the world is not right if this happens.
00131         if (!header)
00132         {
00133             InternalErrorImpl internalError;
00134             internalError.setMessageString(_("Not a valid header. header is zero."));
00135             throw internalError;
00136         }
00137 
00138         // start out at the end of the header. This is where
00139         // the first string starts
00140         string_pointer += header->length;
00141 
00142         for (; which > 1; which--)
00143         {
00144             string_pointer += strlen (string_pointer);
00145             string_pointer++;  // skip past '\0'
00146 
00147             // check that we don't overflow this item
00148             //  additionally, split test into temp vars outside if() to work
00149             //  around astyle formatting bug where it will break code.
00150             const u8 *cur_loc = reinterpret_cast<const u8 *>(string_pointer);
00151             const u8 *base_loc =  reinterpret_cast<const u8 *>(header);
00152             if( cur_loc >= base_loc + header_size)
00153             {
00154                 ParseExceptionImpl parseException;
00155                 parseException.setMessageString(_("Overflow while getting byte data at location: cur_loc >= base_loc + header_size\n cur_loc : %(cur_loc)i\n base_loc : %(base_loc)i\n header_size : %(header_size)i "));
00156                 parseException.setParameter("cur_loc",    force_u64_to_u32(reinterpret_cast<u64>(cur_loc)));
00157                 parseException.setParameter("base_loc",   force_u64_to_u32(reinterpret_cast<u64>(base_loc)));
00158                 parseException.setParameter("header_size",static_cast<u32>(header_size));
00159                 throw parseException;
00160             }
00161 
00162             // if it is still '\0', that means we are
00163             // at the end of this item and should stop.
00164             // user gave us a bad index
00165             if( ! *string_pointer )
00166             {
00167                 throw StringUnavailableImpl(_("The string does not exist. Bad index caused this error"));
00168             }
00169         }
00170 
00171         return string_pointer;
00172     }
00173 
00174     const char *SmbiosItem::getString(unsigned int header_offset) const
00175     {
00176         DataOutOfBoundsImpl dataOutOfBounds;
00177         // apply quick sanity check.
00178         if( header_offset >= getLength() )
00179         {
00180             dataOutOfBounds.setMessageString(_("Attempt to access string outside the length of header. offset : %(header_offset)i, header_length : %(header_length)i"));
00181             dataOutOfBounds.setParameter("header_offset",static_cast<int>(header_offset));
00182             dataOutOfBounds.setParameter("header_length",static_cast<int>(getLength()));
00183             throw dataOutOfBounds;
00184         }
00185 
00186         // Another world-gone-mad check
00187         if (!header)
00188         {
00189             InternalErrorImpl().setMessageString(_("Not a valid header. header is zero."));
00190             throw InternalErrorImpl();
00191         }
00192 
00193         return getStringByStringNumber ( (reinterpret_cast<const u8 *>(header))[header_offset]);
00194     }
00195 
00196     std::auto_ptr<const ISmbiosItem> SmbiosItem::clone() const
00197     {
00198         return auto_ptr<const ISmbiosItem>(new SmbiosItem (*this));
00199     }
00200 
00201     std::auto_ptr<ISmbiosItem> SmbiosItem::clone()
00202     {
00203         return auto_ptr<ISmbiosItem>(new SmbiosItem (*this));
00204     }
00205 
00206     u8 SmbiosItem::getType () const
00207     {
00208         return header->type;
00209     }
00210 
00211     u8 SmbiosItem::getLength () const
00212     {
00213         return header->length;
00214     }
00215 
00216     u16 SmbiosItem::getHandle () const
00217     {
00218         return header->handle;
00219     }
00220 
00221     // We do not implement the string passing interfaces
00222     // because we have no way of converting from string to int.
00223     u8          SmbiosItem::getU8 ( const std::string ) const   NOT_IMPLEMENTED;
00224     u16         SmbiosItem::getU16( const std::string ) const   NOT_IMPLEMENTED;
00225     u32         SmbiosItem::getU32( const std::string ) const   NOT_IMPLEMENTED;
00226     u64         SmbiosItem::getU64( const std::string ) const   NOT_IMPLEMENTED;
00227     const char *SmbiosItem::getString(const std::string ) const NOT_IMPLEMENTED;
00228     u32         SmbiosItem::getBitfield( const std::string, const std::string ) const   NOT_IMPLEMENTED;
00229 
00230     void checkItemBounds( size_t total_size, size_t length, size_t offset, size_t size)
00231     {
00232         DataOutOfBoundsImpl dataOutOfBounds;
00233         dataOutOfBounds.setParameter("offset",static_cast<int>(offset));
00234         dataOutOfBounds.setParameter("header_length",static_cast<int>(total_size));
00235 
00236         // tricky.  Need all three tests here in this order to avoid security hole
00237         if( offset > length )
00238         {
00239             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00240             throw dataOutOfBounds;
00241         }
00242 
00243         if( offset + size < offset )
00244         {
00245             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00246             throw dataOutOfBounds;
00247         }
00248 
00249         if( offset + size > length )
00250         {
00251             dataOutOfBounds.setMessageString(_("Attempt to access data outside the length of header. offset : %(offset)i, header_length : %(header_length)i"));
00252             throw dataOutOfBounds;
00253         }
00254 
00255         if( offset >= total_size ) // world gone mad check.
00256             // data is inside what the header says is
00257             // the length, but outside the range of the
00258             // buffer we are using to hold the header.
00259             // Impossible?
00260         {
00261             dataOutOfBounds.setMessageString(_("Attempt to access data outside header buffer. Impossible situation! offset : %(offset)i, header_length : %(header_length)i"));
00262             throw dataOutOfBounds;
00263         }
00264 
00265     }
00266 
00267     void getData(const ISmbiosItem &item, u8 *data, unsigned int offset, unsigned int size)
00268     {
00269         for (unsigned int i=0; i< size; i++)
00270         {
00271             data[i] = item.getU8(offset +i);
00272         }
00273     }
00274 
00275     u8 SmbiosItem::getU8 ( unsigned int offset ) const
00276     {
00277         checkItemBounds( header_size, header->length, offset, 1U );
00278         u8 byte1 = static_cast<u8>(reinterpret_cast<const u8 *>(header)[ offset + 0 ]);
00279         return byte1;
00280     }
00281 
00282     u16 SmbiosItem::getU16 ( unsigned int offset ) const
00283     {
00284         u16 retval = 0;
00285         checkItemBounds(header_size, header->length, offset, sizeof(retval));
00286         getData(*this, reinterpret_cast<u8 *>(&retval), offset, sizeof(retval));
00287         return retval;
00288     }
00289 
00290 
00291     u32 SmbiosItem::getU32 ( unsigned int offset ) const
00292     {
00293         u32 retval = 0;
00294         checkItemBounds(header_size, header->length, offset, sizeof(retval));
00295         getData(*this, reinterpret_cast<u8 *>(&retval), offset, sizeof(retval));
00296         return retval;
00297     }
00298 
00299     u64 SmbiosItem::getU64 ( unsigned int offset ) const
00300     {
00301         u64 retval = 0;
00302         checkItemBounds(header_size, header->length, offset, sizeof(retval));
00303         getData(*this, reinterpret_cast<u8 *>(&retval), offset, sizeof(retval));
00304         return retval;
00305     }
00306 
00307     void checkBitfieldBounds( unsigned int bound, unsigned int lsb, unsigned int msb, DataOutOfBoundsImpl &doob )
00308     {
00309         if(lsb > bound || msb > bound)
00310         {
00311             doob.setMessageString(_("The total length of bit field is out of bounds. The largest accessible bit is %(bound)i. lsb: %(lsb)i , msb: %(msb)i"));
00312             doob.setParameter( "bound", bound );
00313             throw doob;
00314         }
00315     }
00316 
00317     // Hope this is right too! ;-)
00318     u32 SmbiosItem::getBitfield ( unsigned int offset, unsigned int fieldLen, unsigned int lsb, unsigned int msb ) const
00319     {
00320         u64 bitfield = 0;
00321         DataOutOfBoundsImpl dataOutOfBounds;
00322         // reduce code duplication by setting these up now
00323         dataOutOfBounds.setParameter("lsb",lsb);
00324         dataOutOfBounds.setParameter("msb",msb);
00325         dataOutOfBounds.setParameter("offset",static_cast<int>(offset));
00326         dataOutOfBounds.setParameter("header_length",static_cast<int>(header->length));
00327 
00328         checkItemBounds( header_size, header->length, offset, fieldLen );
00329 
00330         //If msb is less/equal to lsb, they are only requesting a single bit
00331         if(msb <= lsb)
00332         {
00333             msb=lsb;
00334         }
00335 
00336         //Determine how many bits they want and make the mask
00337         u64 bitlen = (msb-lsb) + 1;
00338         u64 mask = 0;
00339         for(u64 i=0;i<bitlen;i++)
00340         {
00341             mask = (mask << 1);
00342             mask |= 1;
00343         }
00344 
00345         switch(fieldLen)
00346         {
00347         case FIELD_LEN_BYTE:
00348             checkBitfieldBounds( 7, lsb, msb, dataOutOfBounds);
00349             bitfield = getU8(offset);
00350             break;
00351         case FIELD_LEN_WORD:
00352             checkBitfieldBounds( 15, lsb, msb, dataOutOfBounds);
00353             bitfield = getU16(offset);
00354             break;
00355         case FIELD_LEN_DWORD:
00356             checkBitfieldBounds( 31, lsb, msb, dataOutOfBounds);
00357             bitfield = getU32(offset);
00358             break;
00359         case FIELD_LEN_QWORD:
00360             checkBitfieldBounds( 63, lsb, msb, dataOutOfBounds);
00361             bitfield = getU64(offset);
00362             break;
00363         default:
00364             dataOutOfBounds.setMessageString(_("Unsupported field length"));
00365             throw dataOutOfBounds;
00366         }
00367 
00368         return static_cast<u32>((bitfield >> lsb) & mask);
00369     }
00370 
00371     const u8 *SmbiosItem::getBufferCopy(size_t &size) const
00372     {
00373         size = header_size;
00374 
00375         const u8 *newBuffer = new u8[ size ];
00376         memcpy (const_cast<u8 *>(newBuffer), header, size);
00377         return newBuffer;
00378     }
00379 
00380     const size_t SmbiosItem::getBufferSize() const
00381     {
00382         return header_size;
00383     }
00384 
00385     void SmbiosItem::fixup( const SmbiosWorkaroundTable *workaround ) const
00386     {
00387         u8 *buffer = const_cast<u8 *>(reinterpret_cast<const u8 *>(header));
00388         workaround->fixupItem( this, buffer, header_size );
00389     }
00390 
00391     ostream & operator << (ostream & cout, const ISmbiosItem & item)
00392     {
00393         return item.streamify (cout);
00394     }
00395 
00396     ostream & SmbiosItem::streamify (ostream & cout) const
00397     {
00398         if (header == 0)  // violates class invariant, should never happen
00399             cout << "operator << on an uninitialized SmbiosItem!";
00400         else
00401         {
00402             std::ios::fmtflags old_opts = cout.flags ();
00403             cout << "Handle 0x" << hex << setfill ('0') <<
00404             setw (4) << getHandle () << endl;
00405             cout << "\tDMI type 0x" << static_cast<int>(getType()) << dec <<
00406             ", " << static_cast<int>(getLength()) << " bytes." <<
00407             endl;
00408             cout.flags (old_opts);
00409         }
00410         return cout;
00411     }
00412 }

Generated on Tue Jul 11 20:46:46 2006 for SMBIOS Library by  doxygen 1.4.7