Login
Username:

Password:

Remember me



Lost Password?

Register now!

Sections

Who's Online
49 user(s) are online (45 user(s) are browsing Forums)

Members: 0
Guests: 49

more...

Support us!

Headlines

Forum Index


Board index » All Posts




Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Quote:

Typically, your current approach -- doing as little as possible in the patch, and postponing the formatting and output to Snork itself -- is the recommended way to handle such things. But I wonder if in this case your original approach -- doing everything, including the DebugPrintF(), in the patch -- isn't a better idea.


I switched to IPC only because I started losing strings (some had garbage when they shouldn't). Maybe it was a side effect of a bug or something else, but once I began copying strings and tags in the patch and sending them via messages, the bug disappeared. But of course, this means I now have more code to handle, like first copying, then parsing, and overall it’s starting to be a bit too much, but still probably safer...

Quote:

One drawback to the current approach is that logging the function call is asynchronous to the function call itself- by the time Snork gets the message and outputs the log, the call has already occurred. So if the call crashes due to a bad argument, the crash occurs before the call can be logged (and if the crash takes down the system, the log will never be written).

A bigger problem comes up when you start logging exec.library calls. I presume you allocate memory in the patch to hold all the copies of arguments, and memory allocation can break a Forbid() that might be in effect when Exec is called. It looks like that can be prevented by using the AVT_Wait, FALSE tag with AllocVecTags().


Yes, for copying strings and tags, I use AllocVecTags, and currently my GenericPatch function and SendIPCMessage function look like this:

Patching function:

void GenericPatch(struct Interface *Selfint watchIndexuint32 args[MAX_PARAMS]) {
    if (
watchIndex || watchIndex >= watchCount || !watches[watchIndex].origFunc || 
        !
watches[watchIndex].iface || Self != watches[watchIndex].iface) {
        
IExec->DebugPrintF("Invalid watchIndex or interface mismatch: watchIndex=%d\n"watchIndex);
        return;
    }
    
    
struct Watch *watch = &watches[watchIndex];

    
// Prepare parameter types for IPC message
    
char paramTypes[MAX_PARAMS] = {0};
    for (
int i 0watch->paramCount && MAX_PARAMSi++) {
        
paramTypes[i] = watch->params[i].type;
    }

    
// Handle process filter and task info
    
if (showProcessName || showTaskInfo) {
        
char taskName[256];
        
struct Process *proc = (struct Process *)IExec->FindTask(NULL);
        
Get_Name(taskNamesizeof(taskName), proc);
        if (!
showProcessName || strcmp(taskNameshowProcessName) == 0)
            
SendIPCMessage(watchIndexargswatch->libNamewatch->funcNameparamTypes
                           
showTaskInfo taskName NULLshowTaskInfo ? (uint32)proc 0);
    } else {
        
SendIPCMessage(watchIndexargswatch->libNamewatch->funcNameparamTypesNULL0);
    }


    
// Call the original function with the appropriate number of parameters        
    
typedef void (*FuncPtr)(struct Interface *, ...);
    
FuncPtr origFunc = (FuncPtr)watch->origFunc;
    switch (
watch->paramCount) {
        case 
0origFunc(Self); break;
        case 
1origFunc(Selfargs[0]); break;
        case 
2origFunc(Selfargs[0], args[1]); break;
        case 
3origFunc(Selfargs[0], args[1], args[2]); break;
        case 
4origFunc(Selfargs[0], args[1], args[2], args[3]); break;
        case 
5origFunc(Selfargs[0], args[1], args[2], args[3], args[4]); break;
        case 
6origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5]); break;
        case 
7origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
        case 
8origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
        case 
9origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
        case 
10origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
        case 
11origFunc(Selfargs[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); break;
        default:
            
IExec->DebugPrintF("Debug: Unsupported parameter count %ld\n"watch->paramCount);
            break;
    }
}



SendIPCMessage():

void SendIPCMessage(int watchIndexuint32 args[MAX_PARAMS], const char *libName, const char *funcName, const char paramTypes[MAX_PARAMS], const char *taskNameuint32 taskAddr) {
    if (!
ipcPort) {
        
IExec->DebugPrintF("IPC port not initialized!\n");
        return;
    }
    
struct IPCMessage *ipcMsg IExec->AllocVecTags(sizeof(struct IPCMessage), 
                                                    
AVT_TypeMEMF_PRIVATE
                                                    
AVT_ClearWithValue0
                                                    
TAG_END);
    if (!
ipcMsg) {
        
IExec->DebugPrintF("Failed to allocate IPC message!\n");
        return;
    }

    
ipcMsg->watchIndex watchIndex;
    
IExec->CopyMem(argsipcMsg->argssizeof(ipcMsg->args));
    
IUtility->Strlcpy(ipcMsg->libNamelibNamesizeof(ipcMsg->libName));
    
IUtility->Strlcpy(ipcMsg->funcNamefuncNamesizeof(ipcMsg->funcName));
    
IExec->CopyMem(paramTypesipcMsg->paramTypesMAX_PARAMS);

    
// Set task name and address only if taskName is provided
    
if (taskName) {
        
IUtility->Strlcpy(ipcMsg->taskNametaskNamesizeof(ipcMsg->taskName));
        
ipcMsg->taskAddr taskAddr;
    } else {
        
ipcMsg->taskName[0] = '\0'// Set to empty string (equivalent to NULL)
        
ipcMsg->taskAddr 0;
    }

    
// Copy string parameters
    
ipcMsg->stringParamCount 0;
    for (
int i 0MAX_PARAMS && paramTypes[i] && ipcMsg->stringParamCount MAX_STRING_PARAMSi++) {
        if (
paramTypes[i] == 's') {
            const 
char *str = (const char *)args[i];
            if (
str) {
                
IUtility->Strlcpy(ipcMsg->stringParams[ipcMsg->stringParamCount], strMAX_STRING_LENGTH);
                
ipcMsg->args[i] = (uint32)ipcMsg->stringParams[ipcMsg->stringParamCount];
                
ipcMsg->stringParamCount++;
            }
        }
    }

    
// Copy tag lists
    
ipcMsg->tagItemCount 0;
    
ipcMsg->tagStringParamCount 0;
    for (
int i 0MAX_PARAMS && paramTypes[i]; i++) {
        if (
paramTypes[i] == 't') {
            
struct TagItem *tags = (struct TagItem *)args[i];
            if (
tags) {
                
int tagCount 0;
                
int moreCount 0;
                while (
tags[tagCount].ti_Tag != TAG_END && tags[tagCount].ti_Tag != TAG_DONE && 
                       
tagCount MAX_TAG_ITEMS && ipcMsg->tagItemCount MAX_TAG_ITEMS && 
                       
moreCount 10) {
                    if (
tags[tagCount].ti_Tag == TAG_IGNORE) {
                        
tagCount++;
                        continue;
                    }
                    if (
tags[tagCount].ti_Tag == TAG_MORE) {
                        if (
tags[tagCount].ti_Data && moreCount 10) {
                            
tags = (struct TagItem *)tags[tagCount].ti_Data;
                            
tagCount 0;
                            
moreCount++;
                            continue;
                        }
                        break;
                    }
                    if (
tags[tagCount].ti_Tag == TAG_SKIP) {
                        
uint32 skipCount tags[tagCount].ti_Data;
                        
tagCount += skipCount 1;
                        if (
tagCount >= MAX_TAG_ITEMS) break;
                        continue;
                    }
                    
// Check if the tag is a string type
                    
const struct TagInfo *info findTagInfoForTag(tags[tagCount].ti_TaglibName);
                    if (
info && info->Type == 's' && tags[tagCount].ti_Data && 
                        
ipcMsg->tagStringParamCount MAX_TAG_STRING_PARAMS) {
                        
// Copy string to tagStringParams
                        
IUtility->Strlcpy(ipcMsg->tagStringParams[ipcMsg->tagStringParamCount], 
                                          (const 
char *)tags[tagCount].ti_DataMAX_STRING_LENGTH);
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag tags[tagCount].ti_Tag;
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Data = (uint32)ipcMsg->tagStringParams[ipcMsg->tagStringParamCount];
                        
ipcMsg->tagStringParamCount++;
                    } else {
                        
// Copy tag as-is
                        
ipcMsg->tagItems[ipcMsg->tagItemCount] = tags[tagCount];
                    }
                    
ipcMsg->tagItemCount++;
                    
tagCount++;
                    if (
ipcMsg->tagItemCount >= MAX_TAG_ITEMS) break;
                }
                if (
ipcMsg->tagItemCount 0) {
                    if (
ipcMsg->tagItemCount MAX_TAG_ITEMS) {
                        
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag TAG_END;
                        
ipcMsg->tagItemCount++;
                    }
                    
ipcMsg->args[i] = (uint32)ipcMsg->tagItems;
                }
            }
        }
    }

    
ipcMsg->msg.mn_Node.ln_Type NT_MESSAGE;
    
ipcMsg->msg.mn_Length sizeof(struct IPCMessage);
    
ipcMsg->msg.mn_ReplyPort NULL;

    
IExec->PutMsg(ipcPort, (struct Message *)ipcMsg);
}


And then, after I copy it all, I have to reparse and print it, so it's like double the work...

But for now I'm facing another problem: 64-bit arguments for some dos.library functions. The issue is:

Currently, all my patching code, wrappers for functions, etc., are using uint32/int32. That's everywhere, and all arguments are treated like this too (bytes, words, etc., are treated as longs, so int32, no problems there; strings and pointers fit into int32 as well). But then, dos.library has six functions that allow some arguments to be int64:


watch=dos,ChangeFilePosition,file=%lp,position=%ld,offset=%ld                                                  // file (BPTR), position (int64), offset (int32)
watch=dos,ChangeFileSize,fh=%lp,pos=%ld,mode=%ld                                                               // fh (BPTR), pos (int64), mode (int32)
watch=dos,DoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld                           // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,PRIVATEDoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld                    // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,LockRecord,fh=%lp,offset=%ld,length=%ld,mode=%ld,timeout=%ld                                         // fh (BPTR), offset (int64), length (int64), mode (uint32), timeout (uint32)
watch=dos,UnLockRecord,fh=%lp,offset=%ld,length=%ld                                                            // fh (BPTR), offset (int64), length (int64)


Now, if I patch those functions with my generic patch, which expects all arguments to be int32, I'll just get bugs because an int64 takes up two int32 slots, causing memory shifts, crashes, and other issues. I see that I need to handle int64 as two int32s in all cases, but that means changing GenericPatch, SendIPCMessage, and the logger to always skip two int32s when encountering an int64, and it’s starting to feel like a mess.

If I change everything in the code (wrappers, GenericPatch, etc.) to use int64, I’ll run into problems with int32 arguments for the same reasons.

So, for now, I’m thinking about how to solve this one...

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Just popping in
Just popping in


@kas1e

Quote:
The question i had now , is it correct way of doing things. I mean, for speed and for being correct at all.

I've been thinking about this, and since no one else has jumped in, here are my thoughts.

Typically, your current approach -- doing as little as possible in the patch, and postponing the formatting and output to Snork itself -- is the recommended way to handle such things. But I wonder if in this case your original approach -- doing everything, including the DebugPrintF(), in the patch -- isn't a better idea.

One drawback to the current approach is that logging the function call is asynchronous to the function call itself- by the time Snork gets the message and outputs the log, the call has already occurred. So if the call crashes due to a bad argument, the crash occurs before the call can be logged (and if the crash takes down the system, the log will never be written).

A bigger problem comes up when you start logging exec.library calls. I presume you allocate memory in the patch to hold all the copies of arguments, and memory allocation can break a Forbid() that might be in effect when Exec is called. It looks like that can be prevented by using the AVT_Wait, FALSE tag with AllocVecTags().

An even bigger problem is that some exec.library calls may be made from interrupts, and memory allocation can't be done from within an interrupt. (I'd guess that TypeOfMem() isn't safe to use from an interrupt, either.)

Calling DebugPrintF() from within the patch eliminates both of those problems, while also making the logging synchronous to the function calls. And there's no need to copy anything except strings (where you're also filtering out unprintable characters), and those could be buffered on the stack (though you're using the caller's stack, so you have to be careful how much you use).

As far as I'm aware, there's no public information on the internal workings of DebugPrintF(). But given its intended purpose, I'd speculate that it depends as little as possible on the rest of the system (and presumably is okay to use from within an interrupt), and likely writes directly to the serial port (in SERIAL mode) with no buffering, and so doesn't return until the entire string has been sent.

If this is in fact the case it will be slow (especially when logging a tag list), as it takes 87 us for every character written at 115.2 kbps (it should be much faster if writing to the debug buffer or if using Sashimi). But the advantages of doing it this way may outweigh the reduced speed.

Go to top


Re: X5000 maybe dying :(
Just popping in
Just popping in


@daveyw

Okay, it's winter where you are, but here in Switzerland, we're baked!

He might have caught a cold

My fan is a Gelid Silent 6.

Go to top


Re: X5000 maybe dying :(
Just popping in
Just popping in


@daveyw

Thermal paste dries over years. I would clean old away ant put new good quality thermal paste there.

Peg2 1GHz G4, 1Gb mem, Radeon 9250
Go to top


Re: X5000 maybe dying :(
Not too shy to talk
Not too shy to talk


@skynet

5020. I've had it since 2017.

I live in the Southern Hemisphere, its winter right now, although my office is reasonably pleasant temperature, but certainly nowhere near 31! Probably not quite 20.

Yeah, 76 does sound high. Maybe because of your high room temperature? Do you know which fan you have? I have the Gelid Silence that most of the X5000s from Amigakit shipped with.

Go to top


Re: X5000 maybe dying :(
Just popping in
Just popping in


Hi daveyw,

Which model do you have, 5020 or 5040?

I've had a 5040 for a year now.

Out of curiosity and in relation to your problem, I checked my processor temperature and it's at 76 degrees Celsius.

I still find it high for my CPU.

I don't really have any idea why your problem is happening; maybe it's due to the heat?

I currently have 31 degrees in my office with a small fan and all the windows open, but no air.

I hope it's nothing serious.

Go to top


Re: DumbPad v03
Just can't stay away
Just can't stay away


@Maijestro

ok. that's another thing. D&D on AmiDock works if program has ReadArgs() IIRC it's working on.

Go to top


X5000 maybe dying :(
Not too shy to talk
Not too shy to talk


I was work on a project on Friday, not run anything too demanding, when suddenly I noticed a CPU temperature alert. CPU was running 98 degrees!

I powered off and let it cool for a while, then unplugged everything and powered it up lying on its side with the case open to check the CPU fan. It seemed fine.

Plugged everything back in and switched on again. Uboot came up, but OS wouldn't boot. The splash screen sloooowly faded up and then froze.

Left it to cool even longer, then tried again. This time it booted, although again there was the very slow fade up on the splash screen. CPU temperature slowly rose to 58 degrees. I did a backup and powered off.

According to the CPU temp docky, CPU fan speed is 30%. Is there any way to increase this?

Go to top


Re: DumbPad v03
Just can't stay away
Just can't stay away


@kas1e

Quote:
kas1e wrote:@Maijestro
D&D were added in v0.2, check release notes :)
And yeah, i working on, just not ready for next beta


Sorry, I expressed myself incorrectly, I meant Drag&Drop via AmiDock which does not yet work with the latest version 0.3.

MacStudio ARM M1 Max Qemu//Pegasos2 AmigaOs4.1 FE / AmigaOne x5000/40 AmigaOs4.1 FE
Go to top


Re: DumbPad v03
Home away from home
Home away from home


@Maijestro
D&D were added in v0.2, check release notes :)
And yeah, i working on, just not ready for next beta

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: DumbPad v03
Just can't stay away
Just can't stay away


@Maijestro

you can try yourself on the beta/demo:
https://kas1e.mikendezign.com/aos4/dumbpad/v03/dumbpad_v03.lha

Go to top


Re: DumbPad v03
Just can't stay away
Just can't stay away


@kas1e

I'm not sure if I may have missed it, but did you already have drag and drop support added to DumpPad?

Hopefully you will continue to work on this great editor.

MacStudio ARM M1 Max Qemu//Pegasos2 AmigaOs4.1 FE / AmigaOne x5000/40 AmigaOs4.1 FE
Go to top


Re: Introducing the Rear Window blog
Site Builder
Site Builder


@trixie
I enjoyed reading your article. And I agree with the majority of what you wrote and the way of thinking.

But, this is the best approach for developers and people who want to dive deeper in the OS. For plain users, and we have observed that happening, the whole situation seems frustrating and they leave the community. There is a need to keep a healthy and productive environment for people to feel that things are moving forward. I just hope that the number of people who would care about the survival and expandability of the platform will increase every year.

Follow me on
Ko-fi, Twitter, YouTube, Twitch
Go to top


Re: Introducing the Rear Window blog
Home away from home
Home away from home


@trixie
Quote:

Now on the Rear Window blog, my personal manifesto for the summer. Enjoy reading!


That's how I think for years, keeping me away from being disappointed by anything. We use what we already have, and if there are updates - cool, if not, I know what I do and with what. Waiting for anything from leaders or hoping for any promises is the way to the trap. Let them do what they think and can do, but it shouldn't reflect on you in any case.

Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Bootarguments for Qemu AmigaOne install on Mac M1
Just can't stay away
Just can't stay away


@johnfante

yep, there still some issues, 'cos server(s) where updated.
Hope they will fixed ASAP.

Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@joerg
Quote:

to add support for international chars, for example the default ISO 8859-15 ones.
Unprintable control chars on AmigaOS, in any supported 8 bit charset, are only 0-31 and 127-159.


Good catch , thanks !

Btw, what is the best way to follow if we need to parse data in a patch ? At fist, i just doing simple parsing inside of the patch, and then print it before calling original function. Then after , i add some simple IPC via PutMsg() (from patch) /GetMsg() (in main).

At first i tried to simple send what i have to the main, but find out that strings and other data simple died offten (because patch is done, memory changes, but i tried to handle it in the main which is point on whatever else). Because of that i had to copy in the patch before putmsg whole set : libname, functionname, doing findtaks(null), copy strings and tags, and then send this instead. For copy i use IExec->CopyMem/IUtility->Strlcpy (that for libname, funcname and strings), and for tags i simple do simple loop copy.

The question i had now , is it correct way of doing things. I mean, for speed and for being correct at all. As i doing dynamic copy for each patching function, i do not need locks and mutexes, but not sure shouldn't i somehow protect it or not ?


Edited by kas1e on 2025/6/27 19:58:44
Join us to improve dopus5!
AmigaOS4 on youtube
Go to top


Re: Bootarguments for Qemu AmigaOne install on Mac M1
Just popping in
Just popping in


@jabirulo

Thank you! That is the version I am running.

Think this is some kind of server error.

Go to top


Re: Bootarguments for Qemu AmigaOne install on Mac M1
Just can't stay away
Just can't stay away


@johnfante

there is an update AmiUpdate v2.56:
http://www.codebench.co.uk/amiupdate_ ... /index.php?page=downloads

Think it fixes the amissl v5 issue.

Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@msteed
Quote:
Of course, if the string pointer is invalid the function you're calling will probably cause a DSI itself as soon as you call it. Still, there's some value to Snork not causing the DSI, even if there's going to be one an instant later anyway.
Some functions may work with invalid string pointers, depending on other arguments the string pointer may not be used at all by the function itself and if it isn't accessed there wont be a DSI.
But Snork would cause a DSI trying to print it.

Go to top


Re: Snork: New Tracing Tool for AmigaOS 4
Home away from home
Home away from home


@kas1e
Quote:
strncpy(output"NULL"output_size 1);
output[output_size 1] = '\0';
= strlcpy(output, "NULL", output_size);

strncpy() and strncat() should be replaced by strlcpy() and strlcat().

Quote:
} else if (input[i] >= 32 && input[i] <= 126) {
            
output[j++] = input[i];
Replace by
} else if ((input[i] >= 32 && input[i] <= 126) || (input[i] >= 160)) {
to add support for international chars, for example the default ISO 8859-15 ones.
Unprintable control chars on AmigaOS, in any supported 8 bit charset, are only 0-31 and 127-159.

Go to top



TopTop
« 1 (2) 3 4 5 ... 7446 »




Powered by XOOPS 2.0 © 2001-2024 The XOOPS Project